0

So I'm fairly novice with jquery and js, so I apologise if this is a stupid error but after researching I can't figure it out.

So I have a list of data loaded initially in a template, one part of which is a dropdown box that lets you filter the data. My issue is that the filtering only works once? As in, the .change function inside $(document).ready() only fires the once.

There are two ways to reload the data, either click the logo and reload it all, or use the search bar. Doing either of these at any time also means the .change function never fires again. Not until you refresh the page.

    var list_template, article_template, modal_template;
var current_article = list.heroes[0];


function showTemplate(template, data)
{
    var html = template(data);
    $("#content").html(html);
}

$(document).ready(function()
{
  var source = $("#list-template").html();
  list_template = Handlebars.compile(source);

  source = $("#article-template").html();
  article_template = Handlebars.compile(source);

    source = $("#modal-template").html();
    modal_template = Handlebars.compile(source);

  showTemplate(list_template,list);
    $(".articleButton").click(function()
    {
        var index = $(this).data("id");
        current_article = list.heroes[index];
        showTemplate(article_template,current_article);
        $('.poseThumb').click(displayModal);
    });

    $("#classFilter").change(function()
    {
        console.log("WOW!");
        var classToFilter = this.value;
        var filteredData =
        {
            heroes: list.heroes.filter(function(d)
            {
                if (d.heroClass.search(classToFilter) > -1)
                {
                    return true;
                }
                return false;
            })
        };
        console.log(filteredData);
        showTemplate(list_template,filteredData);
        $(".articleButton").click(function()
        {
            var index = $(this).data("id");
            current_article = filteredData.heroes[index];
            showTemplate(article_template,current_article);
            $('.poseThumb').click(displayModal);
        });
    });

    $("#searchbox").keypress(function (e)
    {
        if(e.which == 13)
            {
                var rawSearchText = $('#searchbox').val();
                var search_text = rawSearchText.toLowerCase();
                var filteredData =
                {
                    heroes: list.heroes.filter(function(d)
                    {
                        if (d.name.search(search_text) > -1)
                        {
                            return true;
                        }
                        return false;
                    })
                };
                console.log(filteredData);
                showTemplate(list_template,filteredData);
                $(".articleButton").click(function()
                {
                    var index = $(this).data("id");
                    current_article = filteredData.heroes[index];
                    showTemplate(article_template,current_article);
                    $('.poseThumb').click(displayModal);
                });
            }
    });

    $("#logo").click(function()
    {
            showTemplate(list_template,list);

            $(".articleButton").click(function()
            {
        var index = $(this).data("id");
                current_article = list.heroes[index];
                showTemplate(article_template,current_article);
                $('.poseThumb').click(displayModal);
            });
    });
    //$("#logo").click();
});

function displayModal(event)
{
        var imageNumber = $(this).data("id");
        console.log(imageNumber);
        var html    = modal_template(current_article.article[0].vicPose[imageNumber]);
        $('#modal-container').html(html);
        $("#imageModal").modal('show');
}

I should note two things: first, that the search bar works perfectly, and the anonymous function inside both of them is nearly identical, and like I said, the filtering works perfectly if you try it after the initial load. The second is that the same problem occurs replacing .change(anonymous function) with .on("change",anonymous function)

Any help or advice would be greatly appreciated. Thanks.

Polyrogue
  • 15
  • 1
  • 4
  • Post your HTML and CSS, or create a jsfiddle so we can take a look? – RSSM Jan 02 '17 at 15:48
  • Here's the HTML template in question. I can post all m CSS if needed but I don't see how it could be affected. http://pastebin.com/5zEqGTqz Thanks! – Polyrogue Jan 02 '17 at 16:04

2 Answers2

0

Try to use some reference like 'body' in the event listeners inside your DOM like:

  $('body').on('click','.articleButton', function() {
        //Do your stuff...
    })


    $('body').on('click','#classFilter', function() {
        //Do your stuff...  
    })


    $('body').on('keypress','#searchbox', function() {
       //Do your stuff...   
    })

    $('body').on('click','#logo', function() {
        //Do your stuff...  
    })

This will work that you can fire it more than once.

Fernando Torres
  • 460
  • 7
  • 24
  • 2
    should explain why, or point to a duplicate that has a detailed answer – charlietfl Jan 02 '17 at 16:26
  • 1
    I'm working on an answer that explains it as we speak ;-) – David Knipe Jan 02 '17 at 16:27
  • 1
    Thank you very much for the solution! Reading David's explanation currently. I've been racking my head over this all day. – Polyrogue Jan 02 '17 at 16:38
  • 1
    There's one more thing I should say. You're using `$('body')`. I seem to recall reading somewhere that it can affect performance if you have a lot of these things attached to an element near the root of the HTML tree. It's better to attach the handler as far from the root as possible, i.e. the innermost persistent element (by "persistent" I mean of course an element which isn't going to be removed). Don't know how much of an issue this is. – David Knipe Jan 03 '17 at 13:22
0

I agree with Fernando Urban's answer, but it doesn't actually explain what's going on.

You've created a handler attached to an HTML element (id="classFilter") which causes part of the HTML to be rewritten. I suspect that the handler overwrites the HTML which contains the element with the handler on it. So after this the user is clicking on a new HTML element, which looks like the old one but doesn't have a handler.

There are two ways round this. You could add code inside the handler which adds the handler to the new element which has just been created. In this case, that would mean making the handler a named function which refers to itself. Or (the easier way) you could do what Fernando did. If you do this, the event handler is attached to the body, but it only responds to clicks on the #classFilter element inside the body. In other words, when the user clicks anywhere on the body, jQuery checks whether the click happened on a body #classFilter element. This way, it doesn't matter whether the #classFilter existed when the handler was set. See "Direct and delegated events" in jQuery docs for .on method.

David Knipe
  • 3,417
  • 1
  • 19
  • 19
  • Ah, I see. Thank you very much for the detailed explanation! That makes complete sense. Thanks again. – Polyrogue Jan 02 '17 at 16:38
  • Ah, and there's so much of my code which I can optimise now that I know about this. Thanks again to the both of you! – Polyrogue Jan 02 '17 at 16:49
  • Great explanation! I can't did it so good than you. @Polyrogue please see this answer for understand my last answer. Greetings! – Fernando Torres Jan 02 '17 at 23:50