1

I have a page full of items that I filter by class names. This works great, however, after implementing lazy loading using ajax, I am having difficulty getting it to work well together.

I currently pull out the next page of items without applying the filter to the ajax call and then hide the items that don't match the selected filter. This means that you can select a filter, scroll to the end of the page and then get no new items showing. Or in some cases only one or two show before the lazy load is initiated again. This isnt a great user experience.

The alternative of selecting items from the ajax call with the filter seems difficult to manage. Like how do you keep track of what has already been pulled into the DOM and ensure there are no repeated items?

Can anyone help?

JQuery for filterng divs.

jQuery( function( $ ) {

    var $divs = $('.box');

    //filter multiple divs on select
    var $selects = $('.filter_dd').on('change', function() { 

    var css_list_array = [];
        $selects.each(function(index){

            if ($(this).has('option:selected')){

                if( $(this).val() !== '' ) { 
                    var css = '.' + $(this).val();
                    var found = $.inArray(css, css_list_array);
                    if(found < 0) {
                        //if not already in array - add it
                        css_list_array.push(css); 
                    } 
                } 
            }
        });
        var css_string = css_list_array.join(''); 
        console.log(css_string);
        var $el = $(css_string); //selected CSS names           
        console.log($divs); //divs not being selected as this is empty
        $divs.removeClass('is-animated').fadeOut().promise().done(function() 
        {
            if(css_string == null || css_string==''){
                $divs.addClass('is-animated').fadeIn();
            } else {
                $el.addClass('is-animated').fadeIn();
            }
        });         
    });     
});

Ajax code:

    jQuery(document).ready(function($) {
        $(window).scroll(function() {
            var that = $('#loadMore');
            var page = $('#loadMore').data('page');
            var css_select = $('#loadMore').data('css');
            var newPage = page + 1;
            var ajaxurl = $('#loadMore').data('url');
            var docViewTop = $(window).scrollTop();
            var docViewBottom = docViewTop + $(window).height();
            var elemTop = $('#loadMore').offset().top;
            var elemBottom = elemTop + $('#loadMore').height();  



        if( $('#no-more').length == 0) {
        //check if scrolled to 'load more' element
        if ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)) {
            if (typeof loading != 'undefined' && loading) return;
            loading = true; 
            $('#resource_spinner').show();

            $.ajax({
                url: ajaxurl,
                type: 'post',
                data: {
                    page: page,
                    action: 'resources_load_more'
                },
                error: function(response) {
                    console.log(response);
                },
                success: function(response) { 
                    if (response == 0) {
                        //check if any more post
                        if ($("#no-more").length == 0) {
                            $('#ajax-content').append('<div id="no-more" style="text-align:center;font-size:22px;font-weight:bold"><p>No more posts to load.</p></div>');
                        }
                        $('#loadMore').hide();
                        $('#resource_spinner').hide();
                    } else {
                        $('#loadMore').data('page', newPage);
                        $('#ajax-content').append(response);
                    }
                },
                complete: function(){
                    $('#resource_spinner').hide();
                    loading = false;    
                    $divs = $('#ajax-content').find(".box");

                    if(css_select){
                        console.log('ajax'+ css_select);
                        $divs.not(css_select).hide();  
                    }
                }
            });
          }
        }
    });
});
6
  • Did you getting any errors. Commented Apr 19, 2018 at 4:15
  • No errors. The code above works but its not the best way to do it. I am asking for an alternate way to get this working Commented Apr 19, 2018 at 19:57
  • Do you have a DB column using which you want to filter the data? @LeeTee Commented Apr 20, 2018 at 9:09
  • The filters are custom post type categories Commented Apr 20, 2018 at 10:11
  • could you manage adding a sample html or a fiddle/snippet to get a visual of what you are facing? Commented Apr 24, 2018 at 0:50

2 Answers 2

1

If you don't want to filter out in the ajax call and response (thing that i recommend), i would use lazy loading on img src (or other big size content) and get all posts from the ajax call. That done, you can hide items to filter out and force media content of the first "x" (let's say 12) posts to load. If posts are quite much you can also cosmetically use a page lazy loader for each "page" that will contain those already filtered out items (let's say 12) and force their media contents to load when page lazy loader is in view. [option 1]

Following your path, to give the most straight forward answer (that i don't recommend), i would set the post number for each page, then loop a function with the ajax call (incrementing page and adding html for each response) untill items that match the filters are enough to "complete" a page (post number is reached). That done, just show those already filtered items. [option 2]

Please let me know if you want a code example for option 1 or option 2.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your reply. I am struggling to understand what you mean therefore a code example would be great for both if possible.
If you create a fiddle with your code, i will be able to edit it in order to give you a real example of both options.
OK thanks so much for your help with this, its much appreciated. jsfiddle.net/y20fogdo Hope thats ok, let me know if you need anything else
I saw you fiddle but it is not working. Add some html and simulate the ajax call so that it looks like in your website (make it a working example)
@LeeTee Here are docs so you can simulate ajax requests, of course since the question is about frontend, you can simulate static ajax calls using the data attribute as per documentation: doc.jsfiddle.net/use/echo.html . Here is a jsfiddle ajax working example: jsfiddle.net/GRMule/WQXXT.
|
0

It would seem you have conflicting concerns. You are trying to have a shared filter state between client and server while also being able to subsequently use client-only filtering to different constraints.

I would choose one if possible. Solutions differ based on your most important constraint

Client-only filtering
If client-only filtering is most important, then it will be easiest to abandon lazy-loading.

Lazy loading
If lazy loading is most important, then you can replace the list every time filters are changed. As you scroll, you can call to the server with the filter, sort, and an offset (the number of records already shown). This allows you to query the data such that you can consistently fetch the next records relevant to the filter without duplication and also know when you are out of results.

Must have both
If you need both, then your solution will inherently be complex. This solution is probably only worth considering in connection-limited environments.

Your best bet is probably to have the same filter, sort, offset model, but you would then calculate offset from existing items in the page (by counting elements of a class). Your server-side query could either take all items until it has the n next of the filter, or just only add items the pertain to the filter.

In any case, you may not save much anyhow because every time you re-apply filters, you will need to check if you have enough items and make a server call if not.

You could also fully replace dom elements, but have partially local data queries using a framework like pouchDb. This would have simpler management and session persistence, though it would add an extra layer to your app.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.