简体   繁体   中英

How do you nest a map method inside a map method using jquery, json and custom data attributes

I am building a rails application. I am using a data attribute to grab the json.

  <% @image_urls.each_slice(5) do |row| %>
    <% row.each do |_, urls| %>
      <li class="square-image" data-urls=<%= urls.to_json %>>
        <span class="user-image"><%= image_tag(urls.sample) %></span>
      </li>
    <% end %>
  <% end %>

With this json, I'm trying to update the src attribute every second by looping through the different URLs that are in the json. The timing is working. When I do the first map, I successfully grab the urls.

However, when I do the nested map, I get the error "Uncaught TypeError: undefined is not a function." Right now I don't have the updating the src portion since I am just trying to grab each url within one.

Things I've tried:

  • Change map to each = not successful.
  • Play with syntax of $(url) and $(u).

     var time = setInterval(function(){updateImage()}, 1000); var square_urls = ($($(".square-image")[0]).data("urls")); function updateImage(){ square_urls.map(function(urls){ urls.map(function(u){ console.log(u); }); }); } 

If I don't do the second map, I successfully get the URLs.

The second map gives me the error: "Uncaught TypeError: undefined is not a function."

I reworked my thinking to first focus on updating one image; I believe I was trying to do too much at once and needed to further break it down. In the updateImage function, I am updating one square's image by finding the length, updating it randomly and then calling the randomized url into in the array.

After the updateImage worked, I then focused on updating all of the images. In the updateAllImages function, I am able to use the updateImage function and not have to nest and therefore clutter my code. Note, at first I was thrown off since I didn't realize jquery's each method calls the index and the value (unlike Ruby), so I had to make sure to add an argument for the index ( in this case _).

The updateAllImages function is called through the time function which updates every second.

View

  <ul>
  <% @image_urls.each_slice(5) do |row| %>
    <% row.each do |_, urls| %>
      <li class="square-image" data-urls=<%= urls.to_json %>>
        <span class="user-image"><%= image_tag(urls.sample) %></span>
      </li>
    <% end %>
  <% end %>
  </ul>  

JQuery

  var squares = $(".square-image");
  var time = setInterval(function(){updateAllImages(squares)}, 1000);

  function updateAllImages(squares) {
    $.each(squares, function(_, square) {
      updateImage(square);
    });
  }

  function updateImage(square) {
    var urls = $(square).data("urls");
    var urlCount = urls.length;
    var randomIndex = Math.floor(Math.random() * urlCount);
    var newUrl = urls[randomIndex];

    // the image currently lives in a span so that's why I
    // need to call children twice
    var image = $(square).children().children()[0];
    image.src = newUrl;
  }
});

I think this is what you're going for:

var $squares = $(".square-image");
var urls = $squares.map(function(square) { return $(square).data("urls"); });

According to jQuery's documentation:

A returned array will be flattened into the resulting array.

So assuming data-urls has an array in it, there should be no more work necessary to produce all the URLs from all the images.

Note that jQuery's map function is intended to be a selector. It's not intended to have side-effects.

// Use `each` when you want to *do* something instead of *select* something.
$.each(urls, function(url) { console.log(url); });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM