Dynamically select which array to run through funciton

Viewed 54

I am trying to make a jQuery function dynamically decide which array gets run through it based on a button click. Ideally, this is how it would work:

  • User clicks one of the "View More ..." buttons.
  • The program loads the next 3 images of that specific category (Sports, Concerts, etc.).

Below is a version of that function working, but, only for the Concerts section:

var altConcert = [
  "Concert 1",
  "Concert 2",
  "Concert 3",
  "Concert 4",
  "Concert 5",
  "Concert 6"
];

var imgConcert = [
  "https://via.placeholder.com/101/000000",
  "https://via.placeholder.com/102/000000",
  "https://via.placeholder.com/103/000000",
  "https://via.placeholder.com/104/000000",
  "https://via.placeholder.com/105/000000",
  "https://via.placeholder.com/106/000000"
];

var altSport = [
  "Sport 1",
  "Sport 2",
  "Sport 3",
  "Sport 4",
  "Sport 5",
  "Sport 6"
];

var imgSport = [
  "https://via.placeholder.com/101/0000FF",
  "https://via.placeholder.com/102/0000FF",
  "https://via.placeholder.com/103/0000FF",
  "https://via.placeholder.com/104/0000FF",
  "https://via.placeholder.com/105/0000FF",
  "https://via.placeholder.com/106/0000FF"
];

var count = 0;

$(".load-more-concerts").click(function() {
  //Load the next 3 images
  for (i = 0; i < 3; i++) { 
      
    $("#extraConcert").append(
      '<div">' +
        '<h3>'+altConcert[count]+'</h3>' +
        '<img src="'+imgConcert[count]+'" alt="'+altConcert[count]+'"/>' +
      '</div>');

    count++;
  }

  //Scroll to the top (+100px) of the newly loaded images
  $('<div id="new-concert-div'+count+'">&nbsp;</div>').appendTo('#extraConcert');
  $('body, html').animate({ scrollTop: $('#new-concert-div'+count+'').offset().top - 100}, 1000);

  //Remove the "View More" button when out of images
  if (count >= imgConcert.length) {
    $(".view-more-concerts").css("display", "none");
    return;
  }
});
#Concerts { float: left; padding-right: 100px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="Concerts">    
  <div id="extraConcert">
    <div id="new-concert-div1">&nbsp;</div>
  </div>

  <div class="load-more-concerts">
    <button class="view-more-concerts">View More Concerts</button>
  </div>
</div>


<div id="Sports">
  <div id="extraSports">
    <div id="new-sports-div1">&nbsp;</div>
  </div>

  <div class="load-more-sports">
    <button class="view-more-sports">View More Sports</button>
  </div>
</div>

Is there a way that I could use the ID name ("Sports" or "Concerts") of a div or perhaps pass the array as a parameter to the jQuery function? Or is there some other easier method to solving this that I am completely missing? I am confident I could get this to work if I just duplicated the function with different names, but I am trying to follow the DRY Principle.

3 Answers

You can use data html attributes to achieve what you are looking for.

And in your js file you can just get those data attributes and validate them as i did in the code below.

var altConcert = [
  "Concert 1",
  "Concert 2",
  "Concert 3",
  "Concert 4",
  "Concert 5",
  "Concert 6"
];

var imgConcert = [
  "https://via.placeholder.com/101/000000",
  "https://via.placeholder.com/102/000000",
  "https://via.placeholder.com/103/000000",
  "https://via.placeholder.com/104/000000",
  "https://via.placeholder.com/105/000000",
  "https://via.placeholder.com/106/000000"
];

var altSport = [
  "Sport 1",
  "Sport 2",
  "Sport 3",
  "Sport 4",
  "Sport 5",
  "Sport 6"
];

var imgSport = [
  "https://via.placeholder.com/101/0000FF",
  "https://via.placeholder.com/102/0000FF",
  "https://via.placeholder.com/103/0000FF",
  "https://via.placeholder.com/104/0000FF",
  "https://via.placeholder.com/105/0000FF",
  "https://via.placeholder.com/106/0000FF"
];

var count = 0;

$(".load-more").click(function() {
    let alt = window[$(this).attr('data-alt')];
  let img = window[$(this).attr('data-img')];
  let target = $(this).attr('data-target');
  //Load the next 3 images
  for (i = 0; i < 3; i++) { 
      
    $(`#${target}`).append(
      '<div">' +
        '<h3>'+alt[count]+'</h3>' +
        '<img src="'+img[count]+'" alt="'+alt[count]+'"/>' +
      '</div>');

    count++;
  }

  //Scroll to the top (+100px) of the newly loaded images
  $('<div id="new-concert-div'+count+'">&nbsp;</div>').appendTo('#extraConcert');
  $('body, html').animate({ scrollTop: $('#new-concert-div'+count+'').offset().top - 100}, 1000);

  //Remove the "View More" button when out of images
  if (count >= imgConcert.length) {
    $(".view-more-concerts").css("display", "none");
    return;
  }
});
#Concerts { float: left; padding-right: 100px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="Concerts">    
  <div id="extraConcert">
    <div id="new-concert-div1">&nbsp;</div>
  </div>

  <div class="load-more-concerts load-more" data-alt="altConcert" data-img="imgConcert" data-target="extraConcert">
    <button class="view-more-concerts">View More Concerts</button>
  </div>
</div>


<div id="Sports">
  <div id="extraSports">
    <div id="new-sports-div1">&nbsp;</div>
  </div>

  <div class="load-more-sports load-more" data-alt="altSport" data-img="imgSport" data-target="extraSports">
    <button class="view-more-sports">View More Sports</button>
  </div>
</div>

In my code im getting the data attribute that has been clicked in that case i've used data-target, data-alt and data-img.

  • data-target will the target using an id.
  • data-alt will be the alt array.
  • data-img will be the img array.

In javascript code i've used window to get the variables from the data-* string returned.

It starts to throw undefined when the count is bigger then the array length, but this can made with a validation like if(alt[count] !== undefined).

More information about data attributes can be found here: https://www.w3schools.com/tags/att_data-.asp

The selected button should be accessible as $(this) within it's bound click function. You can check for the class of the clicked button. So sticking with your original code and data structure this should work:

$(".view-more-concerts, .view-more-sports").click(function() {
  
  if($(this).is('.view-more-concerts')) {
    var alts = altConcert;
    var imgs = imgConcert;
    var subject = 'concert';
    var container = 'Concert';
  }
  else ($(this).is('.view-more-sports')) {
    var alts = altSport;
    var imgs = imgSport;
    var subject = 'sport';
    var container = 'Sport';
  }
  else {
    return false;
  }

  //Load the next 3 images
  for (i = 0; i < 3; i++) { 
      
    $("#extra"+container).append(
      '<div">' +
        '<h3>'+alts[count]+'</h3>' +
        '<img src="'+imgs[count]+'" alt="'+alts[count]+'"/>' +
      '</div>');

    count++;
  }

  //Scroll to the top (+100px) of the newly loaded images
  $('<div id="new-'+concert+'-div'+count+'">&nbsp;</div>').appendTo('#extra'+container);
  $('body, html').animate({ scrollTop: $('#new-'+concert+'-div'+count+'').offset().top - 100}, 1000);

  //Remove the "View More" button when out of images
  if (count >= imgs.length) {
    $(".view-more-"+subject).css("display", "none");
    return;
  }
});

This is just a quick stab at an answer. I'd probably combine the alt and img arrays into a single array with { alt: '', img: '' }, but I don't have time...

Basically, the idea is, structure the data to fit your needs!

var arrays = {
  concert: {
    alt: [
      "Concert 1",
      "Concert 2",
      "Concert 3",
      "Concert 4",
      "Concert 5",
      "Concert 6"
    ],
    img: [
      "https://via.placeholder.com/101/000000",
      "https://via.placeholder.com/102/000000",
      "https://via.placeholder.com/103/000000",
      "https://via.placeholder.com/104/000000",
      "https://via.placeholder.com/105/000000",
      "https://via.placeholder.com/106/000000"
    ]
  },
  sport: {
    alt: [
      "Sport 1",
      "Sport 2",
      "Sport 3",
      "Sport 4",
      "Sport 5",
      "Sport 6"
    ],
    img: [
      "https://via.placeholder.com/101/0000FF",
      "https://via.placeholder.com/102/0000FF",
      "https://via.placeholder.com/103/0000FF",
      "https://via.placeholder.com/104/0000FF",
      "https://via.placeholder.com/105/0000FF",
      "https://via.placeholder.com/106/0000FF"
    ]
  }
};

var count = 0;

$(".load-more-concerts").click(function() {
  //Load the next 3 images
  for (i = 0; i < 3; i++) {

    $("#extraConcert").append(
      '<div">' +
      '<h3>' + arrays.concert.alt[count] + '</h3>' +
      '<img src="' + arrays.concert.img[count] + '" alt="' + arrays.concert.alt[count] + '"/>' +
      '</div>');

    count++;
  }

  //Scroll to the top (+100px) of the newly loaded images
  $('<div id="new-concert-div' + count + '">&nbsp;</div>').appendTo('#extraConcert');
  $('body, html').animate({
    scrollTop: $('#new-concert-div' + count + '').offset().top - 100
  }, 1000);

  //Remove the "View More" button when out of images
  if (count >= arrays.concert.alt.length) {
    $(".view-more-concerts").css("display", "none");
    return;
  }
});
#Concerts {
  float: left;
  padding-right: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="Concerts">
  <div id="extraConcert">
    <div id="new-concert-div1">&nbsp;</div>
  </div>

  <div class="load-more-concerts">
    <button class="view-more-concerts">View More Concerts</button>
  </div>
</div>


<div id="Sports">
  <div id="extraSports">
    <div id="new-sports-div1">&nbsp;</div>
  </div>

  <div class="load-more-sports">
    <button class="view-more-sports">View More Sports</button>
  </div>
</div>

Related