Jump to content
Brian Scramlin

Two Little Frustrations with AJAX

Recommended Posts

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By fruid
      I'm using custom fields for images (as mentioned here: processwire.com/blog/posts/pw-3.0.142) for a specific images-field, the images of which need to have an HTML-caption. It works fine so far. Now I'm trying to import pages that use this field. I first exported some pages of that kind to see what the spreadsheet would look like. It seems to not separate the captions for each images but instead put all images in one cell and all captions in another.
      How could I go about importing these pages and assign the captions to the images accordingly?
    • By longtom
      I'm creating this site where a 'motherpage' renders all subpages.  I switched on frontend editing to make editing as easy as possible to end-users. 
      I'm stuck on adding images to the subpages.  The frontend editor suggests to add images to the motherpage (that has no images field on it, nor should it), so it asks for another page to add the images to/from. 
      Is there a way to make the frontend-editor context aware so that it looks for images in the correct subpage? 
      I already tried the 'type C' approach and added <edit field="body" page="id">, but that doesn't seem to do the trick. 
    • By Rossie
      Hi Everyone,
      I wish to display a gallery of images from multiple pages on the site.  These images have custom fields created through page reference called 'furniture_list_type'.  Each image now has a radio button which has been selected.
      In  the example code below all images appear from the "gallery20", however the selector  "gallery20.furniture_list_type=3390" does not have any effect.  "3390" is the id of the page reference "chair" selected through the page reference.  I wish only images selected as chair to show.
      Hope someone can help with this.
       
      Thanks,
       
      Calum
       
      $imagePages = $pages->find("template=makers-child, gallery20.furniture_list_type=3390") ;                     foreach($imagePages as $p) {     echo "<ul>";     foreach($p->gallery20 as $image) {         echo "<li><img src='{$image->url}'>{$image->furniture_list_type}</li>";     }     echo "</ul>";      }
    • By daniel_puehringer
      Hey,

      so we all know about SEO and the importance of performance. Basically we do it, because if no one finds the website we just built, it´s frustrating. We all try to write clean markup, css and js code and most might have a webpack/gulp/whatever pipeline to minimize css&js.
      But when thinking about it, optimizing your pipeline might save you a few (hundreds) of kb, compared to loading an image with 1 mb that´s literally nothing and frankly just ridiculous.

      Don´t get me wrong, frontend pipelines are great and should be used, but let´s shift your "I will optimize the shit out of that 3 css lines" focus to something different: try to serve images as fast as possible, this is where the performance boost really happens.

      I´m no pro on processwire so far, but I built a very easy to use picture element, which some of you could find interesting:

      1. the picture comes with 3 different sizes: one for mobile (keep in mind the double dpi, therefore width of 828px), one for tablet and one for desktop
      2. the picture generates a webp version and the original file extension as a fallback
      3. the filesize of each element is rendered within the "data" attribute
      4. lazy loading(sooo important!!!) is done via the native 'loading="lazy"' attribute.


      Please try it out and see the difference 🙂

      I posted this so others can easily optimize their images, but I would also like to hear your suggestions in making it better. Maybe you could decrease the rendering time or maybe you have some easy improvements.

      Please let me know.

      Greetings from Austria!


       
      <picture> <source data="<?php echo($oElement->repeater_image->width(828)->webp->filesize);?>" media="(max-width: 414px)" srcset="<?php echo($oElement->repeater_image->width(828)->webp->url) ?> 2x" type="image/webp"> <source data="<?php echo($oElement->repeater_image->width(828)->filesize) ?>" media="(max-width: 414px)" srcset="<?php echo($oElement->repeater_image->width(828)->url) ?> 2x" type="image/<?php echo($oElement->repeater_image->ext)?>"> <source data="<?php echo($oElement->repeater_image->width(767)->webp->filesize) ?>" media="(min-width: 415) and (max-width: 767px)" srcset="<?php echo($oElement->repeater_image->width(767)->webp->url) ?> 2x" type="image/webp"> <source data="<?php echo($oElement->repeater_image->width(767)->filesize) ?>" media="(min-width: 415) and (max-width: 767px)" srcset="<?php echo($oElement->repeater_image->width(767)->url) ?> 2x" type="image/<?php echo($oElement->repeater_image->ext)?>"> <source data="<?php echo($oElement->repeater_image->webp->filesize) ?>" media="(min-width: 768px)" srcset="<?php echo($oElement->repeater_image->webp->url) ?>" type="image/webp"> <source data="<?php echo($oElement->repeater_image->filesize) ?>" media="(min-width: 768px)" srcset="<?php echo($oElement->repeater_image->url) ?>" type="image/<?php echo($oElement->repeater_image->ext)?>"> <img data="<?php echo($oElement->repeater_image->filesize) ?>" class="img-fluid" loading="lazy" src="<?php echo($oElement->repeater_image->url) ?>" alt="<?php echo($oElement->repeater_image->description) ?>" type="image/<?php echo($oElement->repeater_image->ext)?>"> </picture>
    • By picarica
      Hello si have this gallery, pretty good website, but yesterday client uploaded over 3000 images oto the site, and it cannot handle filtering them out and showing them at the same time , i wanted some simple pagination maybe infinite scrool or onclikc load whatever, but i cannot seem to implement infinite ajax scrool and any other JS methods, nut sure why i still got stuck at the next method, like there is not next page.
      so i wanted to implement PW method of paginating i wanted to use MarkupPagerNav
      so far i have  this code for outputting images
      $pa = $pages->find("template=basic-page|art_gallery, images.tags!=''"); /* $pa = $pages->find("has_parent!=2,id!=2|7,status<".Page::statusTrash.",include=all"); */ echo "<div class='js-filter' id='gal' >"; /* row gtr-50 gtr-uniform */ $frame = $pages->get('/settings/')->watermark; foreach ($pa as $p) { foreach($p->images as $image) { if(!$image->hasTag("act")) { $options = array('quality' => 80, 'upscaling' => true, 'cropping' => 'north', 'sharpening'=>'medium'); $large = $image->size(1200, 0, $options); $wmImage = $large->pim2Load('wm1', ['quality'=>80, 'upscaling' => true, 'sharpening'=>'medium', 'defaultGamma'=>-1])->watermarkLogo($frame, $position='se',$padding=1.5)->pimSave(); /* zmazanie variacii, treba odpoznakovat ked sa menia nastavenie vyssie */ /* $image->pim2Load('wm1')->removePimVariations(); */ $thumb = $image->size(400, 300, $options); echo "<div class='$image->tags grid-item' style=''>"; echo "<span style='overflow:hidden;'class='image fit'>"; echo "<a class='hvr-reveal' href='$wmImage->url'>"; echo "<img uk-scrollspy='cls: uk-animation-fade; repeat: false' src='$thumb->url' alt='$image->tags'>"; echo "</a>"; echo "</span>"; echo "</div>"; } else { $options = array('quality' => 80, 'upscaling' => true, 'cropping' => 'north', 'sharpening'=>'medium'); $large = $image->size(1200, 0, $options); $wmImage = $large->pim2Load('wm2', ['quality'=>80, 'upscaling' => true, 'sharpening'=>'medium', 'defaultGamma'=>-1])->pixelate(25)->smooth(255)->watermarkLogo($frame, $position='se',$padding=1.5)->pimSave(); /* zmazanie variacii, treba odpoznakovat ked sa menia nastavenie vyssie */ /* $image->pim2Load('wm2')->removePimVariations(); */ $thumb = $image->size(400, 300, $options); echo "<div class='$image->tags blur grid-item' style=''>"; echo "<span style='overflow:hidden;'class='image fit'>"; echo "<a class='hvr-reveal' href='$wmImage->url'>"; echo "<img uk-scrollspy='cls: uk-animation-fade; repeat: false' src='$thumb->url' alt='$image->tags'><span>18+</span>"; /* <span>BY OPENING THIS IMAGE YOU CONSET THAT YOU'RE 18 YEARS OR OLDER</span> text copyraightova,y dat vedla obrazky potom */ echo "</a>"; echo "</span>"; echo "</div>"; } } }; to put it  simply, it first searches for sites, and then outputs all images from those sites, pretty simple, it also uses watermarking and uikit filtering
      i have filtering done like this
      $num = 1; echo "<ul class='uk-subnav uk-subnav-pill'>"; foreach(array_unique($alltags) as $key => $tag) { echo"<li uk-filter-control='filter: .$tag;group: $num' class='butt$num' uk-toggle='target: .butt$num ; animation: uk-animation-fade; queued: true'><a href='#'>$tag</a></li>"; echo"<li uk-filter-control='group: $num' class='butt$num active' aria-hidden='true' hidden='' uk-toggle='target: .butt$num; animation: uk-animation-fade'><a href='#'>remove - $tag</a></li>"; $num++; } echo "</ul>"; simple, but i have NO idea how to implement pagination, just because it seems to work that it like find all images, and stores with limit, and then just paginates them, but i cannot apply this method in my code.
      any idea how to make any JS inifite scroll work ? or just how to make this work ? with my setup, or with some modifications, it just have to work as is now
×
×
  • Create New...