Search code examples
jqueryajaxeachslidetoggletoggleclass

Trouble with toggleClass() for dynamically generated elements from Ajax .each()


On a successful .ajax() call, I'm creating a set of div's with forecasted weather data. I want to only show the div with class="forecast-list" initially, and listen for the user's click on the element to show the additional data from the <div class="box hide">

JS to to create DIVs:

 //HTML to append to document
                var html =
                    '<div class="forecast-list"><ul class="list">' +
                    '<li class="item" id="day">' + forecastDay + '</li>' +
                    '<li class="item"><canvas class="' + forecastIcon + '" width="40" height="40"></canvas></li>' +
                    '<li class="item forecastTemp" id="max">' + forecastMax + '</li>' +
                    '<li class="item forecastTemp" id="min">' + forecastMin + '</li>' +
                    '<li class="item"><span class="btn">+</span></li>' +
                    '</ul></div>' +

                    //The following div is hidden when the DOM loads
                    '<div class="box hide"><ul>' +
                    '<li>SUNRISE: ' + sunriseTime + '</li>' +
                    '<li>SUNSET: ' + sunsetTime + '</li>' +
                    '<div class="box-second-line">' +
                    '<li>LOW: ' + forecastMin + ' @' + minTempTime + '</li>' +
                    '<li>HIGH: ' + forecastMax + ' @' + maxTempTime + '</li>' +
                    '</ul></div></div><br><br>';

                //Append HTML to document
                $('.forecast').append(html);

I've hidden the second div when the DOM loads and have my click handler set as...

//Click event to unhide hidden forecast data
            $(document).on('click', '.forecast-list', function () {
                $(this).next($('.box')).toggleClass('hide', false);  
            });

On click, the hidden div shows, but on second click nothing happens. The effect I'm looking for is that when you click on a certain day's forecast, the data for that day with expand down into it's own div. If there is another div open with the extra information from another day, that div should close, so that only one div with class="box" is showing at a time.

I initially tried using slideToggle() in place of toggleClass()but just ended up with the hidden div expanding and contracting four times and then staying 'shut', I assume that's due to the effect being inside the .each() loop.

All this code lives inside an .each() loop in my Ajax function for success.

A link to my code pen


Solution

  • So what's happening is that you're adding a click handler to the document targeting the .forcast-list n times (n = number of times the $.each loops). So when you click on .forcast-list it runs the toggle n times. In this case 8 times.

    There's 2 ways to fix this:

    1. Simply move the click handler outside the $.each loop.

    Modified code pen

    1. Modify your click handler inside the $.each to attach to .forcast-list directly

      $('.forcast-list').on('click', function() {...});