简体   繁体   中英

How to reorder images and descriptions using HTML and JavaScript based on an array?

I am trying to make a website that contains images with text right below them (the text and images match up) that can be reordered.

I have arrays with the image URLs, descriptions, and webpage links that the images link to. For ex:

var imgArray = ["dog.jpg", "cat.jpg", "frog.jpg", "mouse.jpg"] //but with actual URLs for the image
var linkArray = ["dog.html", "cat.html", "frog.html", "mouse.html"]
var descArray = ["Dog", "Cat", "Frog", "Mouse"] //text that will be displayed below the image

The images that I want to show up on the screen are based on another condition that results in an array called works (ex. works = [1, 4] which means images 1 and 4 should show up on the screen). I plan on accessing the details for images 1 and 4 through the aforementioned arrays.

Also, if the user selects from a dropdown, they can change the order of the images that are displayed (ex: instead of image 1 then 3 then 4, it will change to image 4 then 1 then 3, based on another array).

Right now, what I have for the images (there will be no more than 15 displayed, but can be less based on the condition) is just:

<div class = "wrapper">
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
    <div class = "gallery" name="gallery" id = "gallery"><div name = "desc" class = "desc"></div></div>
</div>

I am sure this is bad style, but I could not find a better way to do it, in order for it to work with my next part and allow it to be stylized based on "gallery" and "desc". Then, in order to actually display the images (based on the starting order), I have:

var imgGallery = document.getElementsByName("gallery");
var imgDesc = document.getElementsByName("desc");

for(i=0;i<works.length;i++){
      var a = document.createElement('a');
      var img = document.createElement("IMG");
      a.setAttribute('href', linkArray[works[i]-1]);
      img.setAttribute('src', imgUrls[works[i]-1]);
      img.setAttribute('width', '300');
      img.setAttribute('height', '225');
      a.appendChild(img);
      var desc = document.createElement("P")
      desc.innerText = descArray[works[i]-1];
      imgGallery[i].appendChild(desc);
      imgDesc[i].appendChild(a);

    }

    }

Note: works is the array that contains the images that should be displayed - ex. works = [1, 2, 4] Also, I know it looks like desc and gallery switched, but it works when I do this.

Then, using certain conditions, I have arr2, which is an array that has the same numbers but in a different order - ex: arr2 = [1, 4, 2]. This next code displays the images in the arr2 order:

var wrapper = document.getElementsByClassName("wrapper");
var items = wrapper[0].children;
var elements = document.createDocumentFragment();

arr2.forEach(function(idx) {
  elements.appendChild(items[idx].cloneNode(true));
});

wrapper[0].innerHTML = null;
wrapper[0].appendChild(elements);

*I got this code from a user on Stack Overflow from a different question.

Now, for the issue:

This code works just fine if the works and arr2 arrays contain all of the images possible (ex. [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] as there are fifteen total images possible - I did not show all of them in the imgArray, linkArray, descArray example).

However, if there are fewer than fifteen images (for ex. just [1, 5, 7, 15]) then it will not work, and not all of the images that should show up do (such as maybe just image 1 and 7 show up). I would like to know how to make this work no matter how many images are in the "works" array.

BTW: If someone has a better approach in doing this entirely, that would be appreciated as well. In summary, what I am trying to do is:

  1. Display specific images based on an array that changes per the user (ex: works = [1, 4, 7] - I would like to display images 1, 4, 7 with their respective descriptions)

  2. If a dropdown option is selected, change the ordering of the images (and the corresponding descriptions).

I do not think I can just do document.createElement with imgs randomly in the body because I need to put them in the "gallery" and "desc" classes in order to stylize them.

EDIT: I used this answer from a different post, so now I am sort of able to reorder the images. I have this code (similar to what I had above):

if (document.getElementById('search').value == "option1") {
    //code that finds goodArray for option2
}
if (document.getElementById('search').value == "option2") {
    //code that finds goodArray for option2
}

    var wrapper = document.getElementsByClassName("wrapper");
    var items = wrapper[0].children;
    var elements = document.createDocumentFragment();

    goodArray.forEach(function(idx) {
        elements.appendChild(items[idx].cloneNode(true)); //line 353
    });

    wrapper[0].innerHTML = null;
    wrapper[0].appendChild(elements);

goodArray is the array that has the order of the images - ex: arr2 = [1, 4, 7, 8] based on option # search is the id of my dropdown option1 is the value of the first option in my dropdown, option2 is value of second option, etc.

The other code (staring with var wrapper and onwards) is being shared by all dropdowns. My current issue is that the first dropdown that is clicked (assuming the page starts blank) will work, but the next dropdown that is clicked will not change the images, even though it would work by itself. I am not sure how to make it so the code starting at "var wrapper = " and onwards will work and "restart" every time a new option is clicked. I tried placing it in the individual ifs but this did not work either.

The error that I am getting after selecting the second dropdown is:

Uncaught TypeError: Cannot read property 'cloneNode' of undefined
    at choice.html:354
    at Array.forEach (<anonymous>)
    at change (choice.html:353)
    at HTMLSelectElement.onchange (choice.html:56)

Now to answer your question: you use an array which holds the order of your dropdown which you mention you already have. I presume that the value in the dropdown -1 corresponds with the index of the 3 arrays where your data is?

If this is the case use:

const imgArray = ["dog.jpg", "cat.jpg", "frog.jpg", "mouse.jpg"]
const linkArray = ["dog.html", "cat.html", "frog.html", "mouse.html"]
const descArray = ["Dog", "Cat", "Frog", "Mouse"]

const arr2 = [2,3,1,4]

// assuming you only have one wrapper
const wrapper = document.querySelector(`.wrapper`)

arr2.map(element=>{
    const div = document.createElement(`div`);
    // adding a class to element 
    div.classList.add(`gallery`)

    const a = document.createElement(`a`)
    // element coresponds to 2 for the first run, then 3 then 1 then 4
    a.setAttribute('href', linkArray[element-1]);

    const p =document.createElement(`p`)
    p.innerText = descArray[element-1]

    div.appendChild(a)
    div.appendChild(p)
    //..... you get the idea

}) 

This will clean up some of the code and also generate the displayed elements in the right order so you don't have to sort them again.

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