Jump to content
ryan

How to work with AJAX driven content in ProcessWire

Recommended Posts

Turns out I was using a selector that didn't work... I basically used the same one I use for regular search. In the end my selector just needed to define the parent, that was all.

It all works nicely now. I've added a little LazyCron task too: I save the JSON in certain intervals to a (hidden) PW page/field, and only query this JSON data with JS. It really speeds things up. Otherwise (with browser cache cleared) I had to wait a few seconds till the suggestions were loaded.

Thanks again for your help, suggestions + patience @AndZyk

  • Like 5

Share this post


Link to post
Share on other sites

Glad to hear it works now.

1 hour ago, dragan said:

I've added a little LazyCron task too: I save the JSON in certain intervals to a (hidden) PW page/field, and only query this JSON data with JS. It really speeds things up. Otherwise (with browser cache cleared) I had to wait a few seconds till the suggestions were loaded.

If your site doesn't frequently change, there is an cache option available in the Typeahead plugin:

Quote

cache: false,           // Improved option, true OR 'localStorage' OR 'sessionStorage'

But use whatever works best for you. ;)

  • Like 3

Share this post


Link to post
Share on other sites
On 8/26/2017 at 1:45 AM, dragan said:

I've added a little LazyCron task too: I save the JSON in certain intervals to a (hidden) PW page/field, and only query this JSON data with JS. It really speeds things up. Otherwise (with browser cache cleared) I had to wait a few seconds till the suggestions were loaded.

@dragan - Can you elaborate more on how you did this?  I would like to implement something like this on my sites.

Share this post


Link to post
Share on other sites
3 hours ago, gmclelland said:

@dragan - Can you elaborate more on how you did this?  I would like to implement something like this on my sites.

If I understand the needs correctly, I think this is a perfect use case for WtireCache (https://processwire.com/blog/posts/processwire-core-updates-2.5.28/#wirecache-upgrades). I use this to store the results of a complex set of selector queries that serve JSON to an AngularJS app.

  • Like 1

Share this post


Link to post
Share on other sites

@gmclelland Basically, what I did is installing this module: https://processwire.com/api/modules/lazy-cron/

Then I added this one line at the very bottom of my "search-input" template (the only place I need to ever access that index JSON):

wire()->addHook('LazyCron::everyHour', null, 'cronAutocompleteJSONCache');

In file _cron.php, that I

include_once("./_cron.php");

in my search-input template, I have this:

<?php namespace ProcessWire;

function cronAutocompleteJSONCache(HookEvent $e) {

    $selector = "parent=1041, has_parent!=2";
    $matches = wire('pages')->find($selector);

    foreach ($matches as $match) {
        $result = array(
            "title" => htmlspecialchars_decode($match->title),
            "year" => $match->year,
            "project_desc_short" => htmlspecialchars_decode($match->project_desc_short)
        );
        $results[] = $result;
    }

    $cacheHolderPage = wire('pages')->get(10029);
    $cacheHolderPage->setOutputFormatting(false);
    $cacheHolderPage->autocomplete_json = json_encode($results);
    $cacheHolderPage->last_update = date('d.m.Y h:i:s');
    $cacheHolderPage->save();

}

Of course, I could have also saved the JSON on the file-system, and check the timestamp, and decide on every request if the static JSON is older or newer than the PW-content, and load/generate one or the other, but for my needs, this seemed like the easiest and most straightforward solution.

 

PS

the field last_update I have only added for myself to see if it really works. I made it a "read-only" field in the settings. (not editable)

  • Like 1

Share this post


Link to post
Share on other sites

Hi all,

slightly different issue here - I'm working with a search form (multiple fields, also arrays) to filter the list of items showed in the same page. I've implemented ajax for filtering items as-you-type or as-you-select-options, which is working just fine.

The only problem is the pagination: while ajax pulls items correctly within the selected container, the pagination keeps all pages as no filter form were submitted. In fact, pagination and everything else works perfectly if the form is submitted, but by getting items via ajax without "click form submit" the pagination keeps all items regardless the applied filter . here's selected code part:

$("#formNews").on('change', function ajaxWorks(event){
    var form = $(this);
    $.ajax({
        type: form.attr('method'),
        url: form.attr('action'),
        data: $('#formNews').serialize(),
        success: function(data) {
            var data = $(data).find('#mediaGrid').html();
            data = '<div id="mediaGrid" class="content-current" uk-grid>' + data + '</div>'; // div container
            // remove old content
            $('#mediaGrid.content-current').remove();
            // scroll to the top of the page
            $('html, body').animate({ scrollTop: 0 }, 'slow');
            // append new content to the page
            $('#colMedia').append(data);
        }
    });
    event.preventDefault();
});

The div container contains also the pagination function, so once ajax successes, it pulls both items and the pagination into the div container.

Am I forced to submit the form even though I am using ajax? thanks!

EDIT: The pagination for the ajax pulled items is ok, and it works if I click on the second/next page (without form submission). Since I am using IAS Infinite Ajax Scroll, it seems that the problem is when IAS clicks on the next page ancor tag, as no URL is updated and therefore the pagination thing gets messed up..

Share this post


Link to post
Share on other sites

I'm not quite sure I understand... what is #colMedia?

Maybe use another variable name than data in your success function? i.e.

var d = $(data).find('#mediaGrid').html();

Do you add items with filtering, or remove? (remove would be the behavior that Lister Pro uses - i.e. show fewer items as you add more filter conditions)

Share this post


Link to post
Share on other sites
56 minutes ago, dragan said:

I'm not quite sure I understand... what is #colMedia?

#colMedia is the parent div of the #mediaGrid items container, I'm calling it to append the #mediaGrid div to the #colMedia div after ajax success.

I've found that probably is an IAS problem, and I'm testing some reinitialize options without success, like this

jQuery.ias().reinitialize();
//or
ias.destroy(); ias.bind();

 

Share this post


Link to post
Share on other sites

@AndZyk Hey this Autocomplete typeahead search is not working for me.  

$.typeahead is not a function this kind of error I am getting where's the problem? 

@AndZyk Hey this Autocomplete typeahead search is not working for me.  

$.typeahead is not a function this kind of error I am getting where's the problem? 

Share this post


Link to post
Share on other sites

Hi,

I'm trying the simple json return example, all I've done is change the url to the page I'm requesting:

<ul id='info'></ul>
<script type='text/javascript'>
    var url = '/wishlist/func_wishpage/'; // this is homepage, so replace '/' with page URL you want to load JSON from
    $(document).ready(function() {
        $.getJSON(url, function(data) {
            $.each(data, function(key, value) {
            $("#info").append("<li>" + key + ": " + value + "</li>");
        });
    });
});
</script>

The page I'm requesting, with just some dummy info:

<?php

if($config->ajax) {

// this is an ajax request, return basic page information in a JSON string
$json = array(
    'id' => 3333,
    'something' => "else",
    );
echo json_encode($json);
return;

}

It does not return any values, am I missing something?

 

Share this post


Link to post
Share on other sites

So this last topic just above me - where the person trying to use multiple dropdowns to send ajax filters to a page output container. I think this is what I am trying to figure out. I've got someone interested in moving from WordPress to Processwire but they really like the FacetWP plugin functionality and so I'm looking at techniques for replicating that process.

If you've never seen the plugin: https://facetwp.com/

It seems very similar to what Ryan uses in the bike tours website. I do believe there is some caching involved in terms of result set combinations? - I haven't looked deeply into the FacetWP code, but my impression is that it runs something like this:

  • Grab an initial catalog defined by a search selector(s) definition - this would be provided by the configuration - what pages to list in the results and then which page references fields to be able to filter on.
  • Grab distinct page reference fields and selected values for those - package them into initiall object to output
  • Push those template output items to a paginated search results template and a dynamically generated checkbox fieldset, or multiple selection box, etc navigation template.
  • Live on the client, when an option is selected, send the new selector modifications back to the original search results template - adding the option to the original property selector
  • At this point, there is an option branch that facet employs - you can either keep the full list of possible options and then grey out the options as unselectable where no valid combinations exist, or you can hide the options that are no longer valid - I don't believe there is any interaction between the typical wordpress search box and the facet filters - but I don't see why you couldn't have a selector title tie-in, for example - though precaching result combinations goes completely out the window there...
  • Inject the updated options selectors template and paginated results.

Does this sound about right? So I would want to call a navigation template/fieldset and the paginated result set/controls with ajax and then update both templates with ajax?

I don't really know how the facetWP plugin degrades without javascript - I think it may just show the full list of checkboxes as a control that uses a plain form destination with getstring parameters passed. I suppose it would just go back to the search page results template!

On the server side, could I just create a single search results output template that detect whether it should return a full page or just the page collection and pagination number depending on whether the request is ajax or not? I supposed I'd still need to have a separate filter generator template? Maybe it could all get loaded by the same search results/filter form template?

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.

×
×
  • Create New...