Home > Software engineering >  How to use search/filter for HTML Divs generated from JSON data using JavaScript?
How to use search/filter for HTML Divs generated from JSON data using JavaScript?

Time:05-11

I'm trying to add a filter for the links/divs generated from JSON data.

I already have a search filter working here without a problem IF the data isn't generated via JSON format. But I really need to use JSON for faster loading and processing.

The problem is, it fails to filter the links when doing so. It's supposed to filter divs based on the text inside <a></a> tags, including some hidden texts inside the <span>..

In this example, it can filter only the first item in the JSON, but not for the rest.

// Links Filter
var input = document.getElementById("search-filter-cards");
input.addEventListener("input", searchFilterDivsMenu);

function searchFilterDivsMenu(e) {
  var filter = e.target.value.toUpperCase();
  var list = document.getElementById("links-list");
  var divs = list.getElementsByTagName("div");
  for (var i = 0; i < divs.length; i  ) {
    var a = divs[i].getElementsByTagName("a")[0];
    if (a) {
      if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
        divs[i].style.display = "";
      } else {
        divs[i].style.display = "none";
      }
    }
  }
}

// JSON Data for each links
const maincards = {
  "linksList": [{
      'name': 'Java Bookmarks',
      'title': 'Java Bookmarks',
      'favicon': '../assets/links-favicons/java-bookmarks.png',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
    {
      'name': 'Chrono',
      'title': 'Chrono',
      'favicon': '../assets/links-favicons/chrono.ico',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
    {
      'name': 'Kanban (May)',
      'title': 'EDEN Kanban',
      'favicon': '../assets/links-favicons/kanban.ico',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out, Kanban board',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
  ]
};

const createMainCardLinks = ({
  name,
  title,
  favicon,
  url,
  tags,
  linkattributes
}) => `
    <div >
      <img  src="${favicon}"/>
      <a  href="${url}" ${linkattributes} title="${title}">${name} <span >${tags}</span></a>
    </div>
  `;

const links = maincards.linksList.map(createMainCardLinks);
links.forEach(links => {
  document.getElementById("load-json-data").innerHTML  = links;
});
.h-0 {
  display: none;
}
<body>
  <input id="search-filter-cards" type="text" autocomplete="off" placeholder="Type here to search">
  <div id="links-list">
    <div ><a >Sample Links</a></div>
    <div id="load-json-data"></div>
  </div>
</body>

I'm a beginner in JS and I couldn't figure out this problem for some time now. Anyways, thanks in advance for any help.

CodePudding user response:

I have used jquery for appending, you can use javascript too.

const dataJSON = {
  "linksList": [{
      'name': 'Java Bookmarks',
      'title': 'Java Bookmarks',
      'favicon': '../assets/links-favicons/java-bookmarks.png',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
    {
      'name': 'Chrono',
      'title': 'Chrono',
      'favicon': '../assets/links-favicons/chrono.ico',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
    {
      'name': 'Kanban (May)',
      'title': 'EDEN Kanban',
      'favicon': '../assets/links-favicons/kanban.ico',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out, Kanban board',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
  ]
};

dataJSON.linksList.forEach((element) => {
$('#myUL').append(`
<li><a href="${element.url}"><img style="margin-right:10px;" src="${element.favicon}"/>${element.name}</a></li>
`);
})


function myFunction() {
    var input, filter, ul, li, a, i, txtValue;
    input = document.getElementById("myInput");
    filter = input.value.toUpperCase();
    ul = document.getElementById("myUL");
    li = ul.getElementsByTagName("li");
    for (i = 0; i < li.length; i  ) {
        a = li[i].getElementsByTagName("a")[0];
        txtValue = a.textContent || a.innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
            li[i].style.display = "";
        } else {
            li[i].style.display = "none";
        }
    }
}
* {
  box-sizing: border-box;
}

#myInput {
  background-position: 10px 12px;
  background-repeat: no-repeat;
  width: 100%;
  font-size: 16px;
  padding: 12px 20px 12px 40px;
  border: 1px solid #ddd;
  margin-bottom: 12px;
}

#myUL {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

#myUL li a {
  border: 1px solid #ddd;
  margin-top: -1px; /* Prevent double borders */
  background-color: #f6f6f6;
  padding: 12px;
  text-decoration: none;
  font-size: 18px;
  color: black;
  display: block
}

#myUL li a:hover:not(.header) {
  background-color: #eee;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj 3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>

<h2>Links Search</h2>

<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<ul id="myUL">
  
</ul>

CodePudding user response:

Took me forever to notice your got ALL the divs in the links-list instead of load-json-data

Here is an improved version. It is simplified and because I only toggle the divs in load-json-data it works

// Links Filter
var input = document.getElementById("search-filter-cards");
input.addEventListener("input", searchFilterDivsMenu);

function searchFilterDivsMenu(e) {
  var filter = e.target.value.toUpperCase();
  var list = document.getElementById("load-json-data");
  var divs = list.querySelectorAll("div");
  divs.forEach(div => {
    var a = div.querySelector("a");
    // console.log(filter, "|", a.textContent.toUpperCase(), "|", a.textContent.toUpperCase().indexOf(filter))
    div.hidden = !a || (filter && a.textContent.toUpperCase().indexOf(filter) === -1);
  })
}

// JSON Data for each links
const maincards = {
  "linksList": [{
      'name': 'Java Bookmarks',
      'title': 'Java Bookmarks',
      'favicon': '../assets/links-favicons/java-bookmarks.png',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
    {
      'name': 'Chrono',
      'title': 'Chrono',
      'favicon': '../assets/links-favicons/chrono.ico',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
    {
      'name': 'Kanban (May)',
      'title': 'EDEN Kanban',
      'favicon': '../assets/links-favicons/kanban.ico',
      'url': '#',
      'tags': 'Login, Logout, Log-in, Log in, Log-out Log out, Kanban board',
      'linkattributes': 'rel="noopener noreferrer" target="_blank"'
    },
  ]
};

const createMainCardLinks = ({
  name,
  title,
  favicon,
  url,
  tags,
  linkattributes
}) => `
    <div >
      <img  src="${favicon}"/>
      <a  href="${url}" ${linkattributes} title="${title}">${name} <span >${tags}</span></a>
    </div>
  `;

const links = maincards.linksList.map(createMainCardLinks);
document.getElementById("load-json-data").innerHTML = links.join("")
.h-0 {
  display: none;
}
<input id="search-filter-cards" type="text" autocomplete="off" placeholder="Type here to search">
<div id="links-list">
  <div ><a >Sample Links</a></div>
  <div id="load-json-data"></div>
</div>

  • Related