Stephen
Stephen

Reputation: 31

How to generate HTML from Array Items?

I'm using this javascript code, to filter search items but i want to filter a div element not just plain text.

var searchBox = document.querySelector("input");
var resultList = document.getElementById("resultList");
var resultsArray = [
"Walt Disney",
"Which color do you like?",
"Where are we?",
"Which wells are the best?",
"Who's on first?",
"Cowboys wear white",
"Wells are awesome!",
"Whoooppppeeeeee",
"Which Witch is Which",
"What's going on?",
"Well look at that!"
];


searchBox.addEventListener('keyup', function() {
var searchTerm = searchBox.value.toLowerCase();

// reset ul by removing all li items
while (resultList.hasChildNodes()) {
    resultList.removeChild(resultList.lastChild);
}

// loop through array of sentences
for (var i = 0; i < resultsArray.length; i++) { 
    // if the array item starts with the search value AND the input box is not empty
    if(resultsArray[i].toLowerCase().startsWith(searchTerm) && searchTerm != "") {
        var li = document.createElement('li'); // create an li item
        li.innerHTML = resultsArray[i]; // add the sentence to the new li item
        resultList.append(li); // add new li item to resultList ul
    }
}

// if resultList is empty after going through loop display 'no results found'
if (!resultList.hasChildNodes() && searchTerm != "") {
    var li = document.createElement('li');
    li.innerHTML = "no results found";
    resultList.append(li);
}
});

i want to change var resultsArray items to div class items for example: "Walt Disney", to

 <div class="item"><a href="walt-disney.html"><img src="images/walt-disney.png" alt="walt disney" border="0" /></a>walt disney</div> 

Upvotes: 2

Views: 785

Answers (3)

Andria
Andria

Reputation: 5085

Stop creating, appending, and deleting HTMLElement, it's a hassle

To avoid tons of for loops and using document.createElement, .appendChild, and .removeChild. I would suggest using .innerHTML. Along with this, there is no need to rewrite the list of items in resultArray as an object, just modify the strings to match each attribute's requirements, like so:

JavaScript Code:

const searchBox = document.querySelector("input");
const resultList = document.getElementById("resultList");
const resultsArray = [
  "Walt Disney",
  "Which color do you like?",
  "Where are we?",
  "Which wells are the best?",
  "Who's on first?",
  "Cowboys wear white",
  "Wells are awesome!",
  "Whoooppppeeeeee",
  "Which Witch is Which",
  "What's going on?",
  "Well look at that!"
]

String.prototype.removePunctuation = function() {
  return this.replace(/['"`,!?:;.]/g, '')
}

String.prototype.toSnakeCase = function() {
  return this.split(' ').join('-').removePunctuation().toLowerCase()
}

searchBox.addEventListener('keyup', function() {
  const searchTerm = searchBox.value.toLowerCase().trim()
  resultList.innerHTML = ''

  if (searchTerm) {
    const renderedHTML = resultsArray
      .filter(result => result.toLowerCase().indexOf(searchTerm) !== -1)
      .map(result => `
        <div class='item'>
          <a href='${result.toSnakeCase()}.html'>
            <img src='images/${result.toSnakeCase()}.png' alt='${result.removePunctuation()}' border='0'/>
          </a>
        </div>
      `)

    resultList.innerHTML = renderedHTML.length > 0 ? renderedHTML.join('') : 'No results found'
  }
})

HTML Code:

<input type='text' />
<ul id='resultList'>
</ul>

Here are the changes I've made to your code:

  • Remove all elements in <ul> with .innerHTML = ''
  • .trim() whitespace before searching.
  • Iterate over resultsArray with .filter
    • This allows us to determine whether or not an item should be displayed while keeping everything in an array.
  • Then we can use .map to generate the HTML.
    • How does that work? We are using template strings to insert the values into a string to be inserted into .innerHTML

You'll also have noticed that I've created String.prototype.removePunctuation and String.prototype.toSnakeCase. While I wouldn't always suggest modifying String.prototype it does make this code significantly more readable, in my opinion. It wouldn't be hard to convert this to regular functions.

Don't think it works? Test out a working version here on JSFiddle

FYI, in your question you ask for a div with an a that contains an img. The only text showing is the alt='...' attribute, so if you wanted to display the text of the resultsArray you should just use string interpolation: ${result}

Upvotes: 1

Bharath Sampath Kumar
Bharath Sampath Kumar

Reputation: 22

The solution to filter an array of document elements is to look at their innerHTML property, which is a string that we can use to filter based on the search term.

Here's a working solution:

Notes:

  • To keep things simple, I have created the input resultsArray elements in the body and then grabbed them in my script using querySelectorAll() and then parsed them into an Array using Array.prototype.slice().
  • In the filter function, I am looking at the innerHTML property of this input element list array to find the matches.

var searchBox = document.querySelector("input");
var resultList = document.getElementById("resultList");
// Get the results nodes list
var resultsNodeList = document.querySelectorAll('#array-list>div');
// Parse the node list into an array list
var resultsArray = [].slice.call(resultsNodeList);


searchBox.addEventListener('keyup', function() {
  var searchTerm = searchBox.value.toLowerCase();

  // reset ul by removing all li items
  while (resultList.hasChildNodes()) {
    resultList.removeChild(resultList.lastChild);
  }

  // loop through array of sentences
  for (var i = 0; i < resultsArray.length; i++) { 
    // if the array item starts with the search value AND the input box is not empty
    if(searchTerm != "" && resultsArray[i].innerHTML.toLowerCase().indexOf(searchTerm) > -1) {
      var li = document.createElement('li'); // create an li item
      li.appendChild(resultsArray[i]); // add the sentence to the new li item
      resultList.append(li); // add new li item to resultList ul
    }
  }

  // if resultList is empty after going through loop display 'no results found'
  if (!resultList.hasChildNodes() && searchTerm != "") {
    var li = document.createElement('li');
    li.innerHTML = "no results found";
    resultList.append(li);
  }
});
#array-list{
 display: none; 
}
#resultList{
  list-style-type: none;
  -webkit-padding-start: 20px;
}
<div id="array-list">
  <div class="item"><a href="walt-disney.html"><img src="images/walt-disney.png" alt="walt disney" border="0" /></a>walt disney</div>
  <div class="item"><a href="which-color.html"><img src="images/color.png" alt="which color" border="0" /></a>which color</div>
  <div class="item"><a href="where.html"><img src="images/where.png" alt="where are we" border="0" /></a>where are we</div>
  <div class="item"><a href="best-wells.html"><img src="images/best-wells.png" alt="best wells" border="0" /></a>best wells</div>
</div>

<input type="text" placeholder="Type something to search">
<br><br>
<span>Suggestions:</span>
<ul id="resultList">

</ul>

Upvotes: 0

Barmar
Barmar

Reputation: 782584

Change resultsArray to an array of objects with all the information needed to construct the resulting HTML.

var resultsArray = [
{string: "Walt Disney", url: "walt-disney.html", img: "walt-disney.png", alt: "walt disney" },
{string: "Which color do you like?", url: "which-color.html", img: "which-color.png", alt: "which color" },
...
];


if (searchTerm != "") {
    resultsArray.forEach(({string, url, img, alt} => {
        // if the array item starts with the search value AND the input box is not empty
        if(string.toLowerCase().startsWith(searchTerm)) {

            var li = document.createElement('li'); // create an li item
            li.innerHTML = `<div class="item"><a href="${url}"><img src="images/${img}" alt="${alt}" border="0" /></a>${string}</div>`
            resultList.append(li); // add new li item to resultList ul
        }
    }
}

Upvotes: 1

Related Questions