-1

I have a block of code that reads json data, then constructs 50 divs with contest related information in it. I am working with Gleam.io so people can enter the contest. Each contest is it's own day and has a unique URL.

Currently I have it rendering all my boxes fine, putting in the correct data for each div. What I can't figure out for the life of me is when I click on a box, for it to find and pull the correct URL to put into the modal.

When I do it, the onclick will always just pull the last box's information and display that.

<script>
        // FETCHING DATA FROM JSON FILE
        $.getJSON("https://cdn.shopify.com/s/files/1/2660/5202/files/data.json?v=1624391152", 
            function (data) {
            var modal = '';
            var prizeState = '';
            var prizeURL = '';
            var card = '';
            // ITERATING THROUGH OBJECTS
            var cardwrapper = document.getElementById('cardWrapper');
            $.each(data, function (key, value) {
                var prize = '';
                var prizeState = value.prizeState;
                    prizeURL = value.entryForm;
                // DATA FROM JSON OBJECT
                var card = document.createElement('div');
                    card.setAttribute('data-modal', value.prizeDay);
                    card.classList.add('card');
                    prize += '<div class="entry-form" onclick="modalPop(' + value.entryForm + ')"><span class="entry-url">' + value.entryForm + '</span></div>' +
                        ' <div class=" ' + value.prizeState + '">' +
                        '<div class="prizeDay">Day ' + value.prizeDay + '</div>' +
                        /* '<div class="prizeDate"> ' + value.prizeDate + '</div>' + */
                        '<div class="prizePhoto"> <img src="' + value.prizePhoto + '" /></div>' +
                        '<div class="prizeTitle"> ' +  value.prizeTitle + '</div>' +
                        '<div class="prizeWinner">' + value.prizeWinner + ' ' + value.prizeCity + '</div>' +
                        '<span class="button btn btn-default prizeEnterButton">Enter Contest</span>'
                    prize += '</div>';
                    card.innerHTML = prize;
                    card.addEventListener('click', function(){
                        modalPop(prizeURL);
                        console.log(prizeURL, ' from onclick');
                    });
                    cardwrapper.appendChild(card);
                    console.log(prizeURL);
            });
        });         

    // Get the modal
    var modal = document.getElementById("myModal");

    // Get the button that opens the modal
    var btn = document.getElementById("myBtn");

    function modalPop(prizeURL) {
        console.log(prizeURL);
        var popupContent = '<h4>' + prizeURL + '</h4>' +
        '<span id="modalClose" class="close">&times;</span>' +
        '<span id="widget-code">' +
        '<iframe src="' + prizeURL + '" frameBorder="0" allowfullscreen></iframe>' +
        '</span>'
        $('#myModal #modalReplace').empty().html(popupContent);
        $('#myModal').fadeIn(200).addClass('modal-active');
    }

    // When the user clicks anywhere outside of the modal, close it
    window.onclick = function(event) {
        if (event.target == modal) {
            $('#myModal').fadeOut(200);
        }
    }
</script>
  • Assuming the AJAX works, please click [edit], then `[<>]` snippet editor and create a [mcve] with just the object and the relevant HTML and script – mplungjan Jun 29 '21 at 14:29
  • Also you have jQuery, why not use it? Lastly look at delegation – mplungjan Jun 29 '21 at 14:31
  • `prizeURL = value.entryForm;` is defined in the outer loop so will always be the last value. [last as in end, not last as in previous] You "redefine" `prizeState` so why not move *all* your variables to the inner most scope and use `let` instead of `var` - so they're scoped correctly. – freedomn-m Jun 29 '21 at 14:44

3 Answers3

0

The problem with modalPop(prizeURL) is that, when you click the card, this click function should trigger correctly, but it has no idea what prizeURL is. This variable is defined in the function (key, value) function, not in the onclick function. I guess it just logs undefined.

It's just a blind guess, but a neat trick could be to attach each prizeURL to each card, like this :

card.prizeURL = prizeURL;

card.addEventListener('click', function(){
     modalPop(this.prizeURL);
     console.log(this.prizeURL, ' from onclick');
});
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
0

Store the prizeURL as an attribute of the card

    ...
      prizeURL = value.entryForm;
      // DATA FROM JSON OBJECT
      var card = document.createElement('div');
      card.setAttribute('data-prizeurl', prizeURL);
      card.setAttribute('data-modal', value.prizeDay);
    ...

Move your click function out of the loop and delegate it

      $(document).on('click', '[data-modal]', function(){
          modalPop($(this).data('prizeurl'));
          console.log(prizeURL, ' from onclick');
      });

     // When the user clicks anywhere outside of the modal, close it
     window.onclick = function(event) {
       if (event.target == modal) {
        $('#myModal').fadeOut(200);
       }
     }
Kinglish
  • 23,358
  • 3
  • 22
  • 43
  • Thank you so much! This solved it and now I have a better understanding of this stuff. Getting the code to do the json and other divs I get, never did anything like this though. Thank you so much! – BobDiggity Jun 29 '21 at 15:04
  • @BobDiggity You're welcome! Please mark this as the answer if it solved your question. Cheers – Kinglish Jun 29 '21 at 15:11
  • 1
    Returning the favour – mplungjan Jun 29 '21 at 16:12
0

The issue is that

card.addEventListener('click', function(){
  modalPop(prizeURL);
});

needs a closure or a scope change (use let for example)

But this can all be avoided if you delegate and store the URL in a data attribute

const modalPop = prizeURL => {
  console.log(prizeURL);
  $('#modalReplace').html(`<h4>${prizeURL}</h4>
    <span id="modalClose" class="close">&times;</span>
    <span id="widget-code">' +
    <iframe src="' + prizeURL + '" frameBorder="0" allowfullscreen></iframe>' +
    </span>`)
  $('#myModal').fadeIn(200).addClass('modal-active');
  
}

// When the user clicks anywhere outside of the modal, close it
$(window).on("click", event => {
  if ($(event.target).closest("#myModal").length===0 && !$(event.target).hasClass('close')) {
    $("#myModal").fadeOut(200);
  }
})

$.getJSON("https://cdn.shopify.com/s/files/1/2660/5202/files/data.json?v=1624391152",
  function(data) {
    $('#cardWrapper').html(
        data.map(item => `<div class="card" data-modal="${item.prizeDay}" data-url="${item.entryForm}">
  <div class="entry-form" ><span class="entry-url">${item.entryForm}</span></div>
  <div class="${item.prizeState}">
    <div class="prizeDay">Day ${item.prizeDay}</div>
    <div class="prizePhoto"> <img src="${item.prizePhoto}" /></div>
    <div class="prizeTitle">${item.prizeTitle}</div>
    <div class="prizeWinner">${item.prizeWinner} ${item.prizeCity}</div>
    <span class="button btn btn-default prizeEnterButton">Enter Contest</span>
  </div>
</div>`))
      .on("click", ".prizeEnterButton", function(e) { // clicking enter contest
        modalPop($(this).data("url"))
        e.stopPropagation();
      })
  })
#myModal { display: none; position:absolute; top:200px; background-color:white}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="myModal"><h1>MODAL</h1><div id="modalReplace"></div></div>
<div id="cardWrapper"></div>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • Actually the dupe is not very relevant to the issue in the question. I would bet OP would have no idea how they related – mplungjan Jun 29 '21 at 15:34
  • 2
    Seen it a few times recently, seems to be a worrying trend. A number of answers, then a gold user closes it as a duplicate and downvotes all the answers ("as they should know better" or some rubbish, but without comments). – freedomn-m Jun 29 '21 at 15:34
  • I SOMETIMES do that, but then it is an OBVIOUS dupe and all answers are variations of the OBVIOUS dupe or actual copies of the dupe. It is not to punish but to allow OP to delete – mplungjan Jun 29 '21 at 15:35