Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

A R
A R
12,834 Points

Event handler firing too many times

I'm trying to get the modals to pop up for the related cards, but each time all the event handlers are firing so the last person is the one that shows up on the page. I'm not sure the route to get only the currently clicked one to show up. I've player around a bit and done some research, but no luck, so I figured I'd reach out.

//Variables and No-Script-Warning Cardd
const $gallery = $("#gallery");
const $cardNoJs = $('#card-no-js');
const usersAPI = 'https://randomuser.me/api/?results=12';
$cardNoJs.hide();

//function to iterate through array and create cards. 
function createUserCards(data){
    $.each(data, function(index, item){
        appendCard(index, item);
    })
}

//function to generate html and append cards to the gallery DIV
function appendCard(index, item){
     $gallery.append(`<div class="card">\
    <div class="card-img-container">\
    <img class="card-img" src="${item.picture.large}" alt="profile picture">\
    </div>\
    <div class="card-info-container">\
        <h3 id="name" class="card-name cap">${item.name.first} ${item.name.last}</h3>\
        <p class="card-text">${item.email}</p>\
        <p class="card-text cap">${item.location.city}</p>\
    </div>\
</div>`)
$('.card').on('click', $('.card'), function(e){
    console.log($(this));
    createModal(item)
    });
};

function createModal(item){
   $modal = $('body').append(`<div class="modal-container">
    <div class="modal">
        <button type="button" id="modal-close-btn" class="modal-close-btn"><strong>X</strong></button>
        <div class="modal-info-container">
            <img class="modal-img" src="${item.picture.large}" alt="profile picture">
            <h3 id="name" class="modal-name cap">${item.name.first} ${item.name.last}</h3>
            <p class="modal-text">${item.email}</p>
            <p class="modal-text cap">${item.location.city}</p>
            <hr>
            <p class="modal-text">${item.phone}</p>
            <p class="modal-text">${item.location.street.number} ${item.location.street.name} ${item.location.city} ${item.location.state} ${item.location.postcode}</p>
            <p class="modal-text">Age: ${item.dob.age}</p>
        </div>
    </div>

    // IMPORTANT: Below is only for exceeds tasks 
    <div class="modal-btn-container">
        <button type="button" id="modal-prev" class="modal-prev btn">Prev</button>
        <button type="button" id="modal-next" class="modal-next btn">Next</button>
    </div>
</div>`
)
$('#modal-close-button').on('click', function(event){
    console.log('clicked');
    $target = event.target
    $target.hide();
    });
};

//event handler for modal window popups

//AJAX request as outlined in the Random User API. getJSON could also work here
$.ajax({
    url: 'https://randomuser.me/api/?results=12',
    dataType: 'json',
    success: function(data) {
      createUserCards(data.results);
    }
  });

3 Answers

Torben Korb
seal-mask
PLUS
.a{fill-rule:evenodd;}techdegree seal-36
Torben Korb
Front End Web Development Techdegree Graduate 91,394 Points

Hi A R,

first of all compliments to your well readable code. It's clear and concise what your functions do. Even you could remove the comments because the code speaks for itself, which is always the best documentation. Really like it.

Your problem arises by attaching the event handler to any card in the document with the CSS class .card. It's attached for all cards once in any iteration and multiplies the handlers up.

You could solve it by: instead of selecting from the DOM to add a handler, you can save the created code in a variable before appending. Then attach the event handler to this variable and finally append to the gallery.

Like this:

function appendCard(index, item) {
    const $el = $(`<div class="card">\
            <div class="card-img-container">\
            <img class="card-img" src="${item.picture.large}" alt="profile picture">\
            </div>\
            <div class="card-info-container">\
                <h3 id="name" class="card-name cap">${item.name.first} ${item.name.last}</h3>\
                <p class="card-text">${item.email}</p>\
                <p class="card-text cap">${item.location.city}</p>\
            </div>\
        </div>`);
    $el.on('click', function (e) {
        createModal(item);
    });
    $gallery.append($el);
}

Hope this helps you. Happy Coding!

A R
A R
12,834 Points

I guess I have one more question, because I had tried something similar. I'm not sure where to add it in the code/how to link where I add it in the code to the data from the API request...

A R
A R
12,834 Points

Thanks for the suggestion and the positive feedback! I'll give your suggestion a try.

Torben Korb
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Torben Korb
Front End Web Development Techdegree Graduate 91,394 Points

I updated my answer above. The only change has to happen inside the appendCard function. By creating the item first and attaching the event handler only to the element itself the code works as intended.

A R
A R
12,834 Points

Ah, perfect! That's a great, simple solution. Thanks so much for your help.