Jump to content
Brian Scramlin

Two Little Frustrations with AJAX

Recommended Posts

Posted (edited)

I just wanted to share that I added an AJAX-powered gallery to an artist website that I developed and host: https://jackpinecreations.com/gallery/

3197az.gif.725dd8cdeb146d00f75b5533aac654f6.gif

There were two things that frustrated me about creating this. Perhaps you can show me a better way.

1. After creating my processing script, which I placed under /templates/scripts/get-items.php, I realized that I would get a 403, due to ProcessWire's routing and security. This forced me to have to create a template and page for this little script. This was frustrating simply because it seemed unnecessarily confusing. But worse, see #2.

2. I usually use config.php to prepend and append each of my templates with a head.inc and foot.inc, which keeps my templates easy to use and I don't have to go and use the GUI to do so on each template separately. However, since I realized I needed to create a new template and page so as to access it, whenever I sent POST params to it, I would get the header and footer along with it!!! I could find no workarounds and had to remove the pre/append calls in config.php and use the GUI on each template individually.  

Code Below if you're interested:

HTML and JavaScript (forgive my sad JavaScript skills, I know this can be tightened up)

<!-- Begin Grid -->
<div class="container mt-4">
  <div id="gallery" class="row">
    <?php foreach ($page->children("limit=9") as $child): ?>
      <div class="col-6 col-md-4 gallery-item">
        <a href="<?= $child->url ?>" title="View <?= $child->title ?>">
          <img class="gallery-item" src="<?= $child->item_featured_image->size(640, 640)->url ?>" alt="<?= $child->title ?> Image">
        </a>
      </div>
    <?php endforeach; ?>
  </div>
</div>
<!-- End Grid -->

<div class="center-block text-center">
  <button id="get-more-items" type="button" name="get-more-items" class="btn-vintage">Load More</button>
</div>

<script type="text/javascript">
  var buttonGetItems = document.getElementById("get-more-items");
  var indexStart = 0;

  buttonGetItems.addEventListener("click", function() {
    indexStart += 9;

    $.ajax({
      url: '<?= $pages->get(1186)->url ?>',
      type: "POST",
      dataType:'json', // add json datatype to get json
      data: ({page_id: <?= $page->id ?>, index_start: indexStart}),
      success: function(data){
        console.log(data);
        if (data[1]) {
          //for each element, append it.
          $.each(data, function(key, value) {
            $("#gallery").append(value);
          });
        } else {
          $("#get-more-items").after('<p class="center-block text-center">There are no more items to load.</p>');
          $("#get-more-items").remove();
        }
      }
    });
  });

</script>

Processing Script

<?php

$items_array = [];
$i = 0;

foreach ($pages->get($input->post->page_id)->children->slice($input->post->index_start, 9) as $child) {
  $i++;
  $items_array[$i] =
    "<div class='col-6 col-md-4 gallery-item'>
      <a href='$child->url' title='View $child->title'>
        <img src='{$child->item_featured_image->size(640,640)->url}' alt='$child->title Image'>
      </a>
    </div>";
}

echo json_encode($items_array);

I love ProcessWire for hundreds of reasons, but I've been using AJAX more and more, and I'm not liking having to create templates to access scripts. 

Any advice?

Edited by Brian Scramlin
added GIF so people don't have to go to link if they don't want to.

Share this post


Link to post
Share on other sites
11 minutes ago, Brian Scramlin said:

Any advice?

1. If you put your PHP file in the site root it won't be affected by the htaccess restrictions. You could also put it any other place besides those places with restricted access.

2. See the "Files" tab in the template settings: "Disable automatic prepend of file..." / "Disable automatic append of file..."

  • Like 4

Share this post


Link to post
Share on other sites
2 minutes ago, Brian Scramlin said:

1. Would the file be overwritten when upgrading PW? 

Not so long as you keep it outside of the /wire/ folder.

Share this post


Link to post
Share on other sites

my preferred way is to make a generic 'service' template, and have a 'services' index page, under which you can add as many services/ajax endpoints as you want; then you just have the template include the correct service php file by matching the name; in any given service file, you can do a return $this->halt() or exit() to stop the appending; you can also just turn off prepend/append for that service template and you'd be all set...

1 hour ago, Brian Scramlin said:

I usually use config.php to prepend and append each of my templates with a head.inc and foot.inc,

that's risky and not so future proof; also on some templates it might prevent you from doing some processing before the head loads, for that template – maybe add a dns prefetch to the header, or a custom script or style for that template's pages. if you don't have a lot of templates, it is probably better to just include head and foot in each template file and skip the auto prepend/append.

The benefit of using pages for your endpoints is that you have full native access to the api, and no bootstrapping necessary..

 

  • Like 6

Share this post


Link to post
Share on other sites

Thank you, everyone! These are helpful strategies and I will integrate them into my work. What a great community. Regarding the auto-pre/appending, this is documented on the PW (https://processwire.com/docs/tutorials/how-to-structure-your-template-files/) as Direct Output with Automatic Inclusions, but I know Delayed Output and Markup Regions are probably preferred and I will work on switching to those strategies.

  • Like 2

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By PawelGIX
      Can I convert uploaded images to PNG, GIF, BMP -> JPEG?
      Is there any function in the API that I can change the file type?
    • By Robin S
      Repeater Images
      Adds options to modify Repeater fields to make them convenient for "page-per-image" usage. Using a page-per-image approach allows for additional fields to be associated with each image, to record things such as photographer, date, license, links, etc.
      When Repeater Images is enabled for a Repeater field the module changes the appearance of the Repeater inputfield to be similar (but not identical) to an Images field. The collapsed view shows a thumbnail for each Repeater item, and items can be expanded for field editing.
      Screencast

      Installation
      Install the Repeater Images module.
      Setup
      Create an image field to use in the Repeater field. Recommended settings for the image field are "Maximum files allowed" set to 1 and "Formatted value" set to "Single item (null if empty)". Create a Repeater field. Add the image field to the Repeater. If you want additional fields in the Repeater create and add these also. Repeater Images configuration
      Tick the "Activate Repeater Images for this Repeater field" checkbox. In the "Image field within Repeater" dropdown select the single image field. You must save the Repeater field settings to see any newly added Image fields in the dropdown. Adjust the image thumbnail height if you want (unlike the core Images field there is no slider to change thumbnail height within Page Edit). Note: the depth option for Repeater fields is not compatible with the Repeater Images module.
      Image uploads feature
      There is a checkbox to activate image uploads. This feature allows users to quickly and easily add images to the Repeater Images field by uploading them to an adjacent "upload" field.
      To use this feature you must add the image field selected in the Repeater Images config to the template of the page containing the Repeater Images field - immediately above or below the Repeater Images field would be a good position.
      It's recommended to set the label for this field in template context to "Upload images" or similar, and set the visibility of the field to "Closed" so that it takes up less room when it's not being used. Note that when you drag images to a closed Images field it will automatically open. You don't need to worry about the "Maximum files allowed" setting because the Repeater Images module overrides this for the upload field.
      New Repeater items will be created from the images uploaded to the upload field when the page is saved. The user can add descriptions and tags to the images while they are still in the upload field and these will be retained in the Repeater items. Images are automatically deleted from the upload field when the page is saved.
      Tips
      The "Use accordion mode?" option in the Repeater field settings is useful for keeping the inputfield compact, with only one image item open for editing at a time. The "Repeater item labels" setting determines what is shown in the thumbnail overlay on hover. Example for an image field named "image": {image.basename} ({image.width}x{image.height})  
      https://github.com/Toutouwai/RepeaterImages
      https://modules.processwire.com/modules/repeater-images/
    • By louisstephens
      I have been messing around with creating pages from ajax requests, and it has gone swimmingly thus far. However, I am really struggling with creating a page and saving an image via ajax. 
      The form:
      <form action="./" role="form" method="post" enctype="multipart/form-data"> <div> <input type="text" id="preview" name="preview" placeholder="Image Title"> </div> <div> <input type="file" id="preview-name" name="preview-name"> </div> <div> <select id="select-tags" name="select-tags"> <?php $tags = $pages->find("template=tag"); ?> <option value="">Select Your Tags</option> <?php foreach ($tags as $tag) : ?> <option value="<?= $tag->name; ?>"><?= $tag->name; ?></option> <?php endforeach; ?> </select> </div> <div> <button type="button" id="submit-preview" name="submit" class="">Upload Images</button> </div> </form>  
      The ajax in my home template:
      $('#submit-preview').click(function(e) { e.preventDefault(); title = $("#preview").val(); image = $("input[name=preview-name]"); console.log(title); console.log(image); data = { title: title, image: image //not sure if this is actually needed }; $.ajax({ type: 'POST', data: data, url: '/development/upload-preview/', success: function(data) { console.log("Woo"); }, error: function(xhr, ajaxOptions, thrownError) { alert(xhr.responseText); } }); }); And finally in my ajax template:
      $imagePath = $config->paths->assets . "files/pdfs/"; //was from an older iteration $title = $sanitizer->text($_POST['title']); $image = $sanitizer->text($_POST['image']); $p = new Page(); $p->template = "preview"; $p->parent = $pages->get("/previews/"); $p->name = $title; $p->title = $title; $p->save(); $p->setOutputFormatting(false); $u = new WireUpload('preview_image'); $u->setMaxFiles(1); $u->setOverwrite(false); $u->setDestinationPath($p->preview_image->path()); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png', 'pdf')); foreach($u->execute() as $filename) { $p->preview_image->add($filename); } $p->save(); I can complete the file upload but just using a simple post to the same page and it it works well, but I was really trying to work out the ajax on this so I could utilize some modals for success on creation (and to keep my templates a little cleaner). When I do run the code I have, a new/blank folder is created under assets, and a new page is created with the correct title entered. However, no image is being processed. I do get a 200 status in my console. I have searched google for help, but everything seems to be slightly off from my needs. If anyone could help point me in the right direction I would greatly appreciate it. 
    • By louisstephens
      So I am using ajax to upload an image, but I am getting the error "Method WireUpload:: save does not exist or is not callable". I am not quite sure how to go about fixing this (at the moment).
      elseif($config->ajax && $input->urlSegment1 == "upload-preview") { $u = $config->paths->assets . "files/pdfs/"; $title = $sanitizer->text($_POST['title']); $p = new Page(); $p->template = "preview"; $p->parent = $pages->get("/previews/"); $p->name = $title; $p->title = $title; $p->save(); $p->setOutputFormatting(false); $u = new WireUpload('preview_image'); $u->setMaxFiles(1); $u->setOverwrite(false); $u->setDestinationPath($p->preview_image->path()); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png', 'pdf')); foreach($u->execute() as $filename) { $p->preview_image->add($filename); } $u->save(); } I compared my code to something I did previously (though previously I just posted to the current template file, not through ajax) which works, but this doesnt seem to be working. I have the _init.php file prepending as well. Does anyone have any ideas of what might be happening?
    • By Kiwi Chris
      In the RTE, when inserting a link, there are several input fields that can be used to select a page, including a text input field that will auto-complete with pages on the site.
      When inserting an image, there is only an option to navigate the page tree. (equivalent to the second input option 'Select Page...' on the Insert Link screen from the RTE.
      When inserting an image from another page buried somewhere in the page tree, if you know the name of the page, it would often be quicker to use an auto-complete text field than 'Select Page...' option.
      It would be nice if the image insertion dialog offered the same functionality as the link insertion dialog so that when selecting a page it's possible to choose either to navigate the page tree, or have a text auto-complete field.
×
×
  • Create New...