Home > Net >  Filter/display array results by value (JS)
Filter/display array results by value (JS)

Time:09-30

trying to create a card component for a site. Attempting to implement the ability to refine by type from an array when a checkbox is checked. For example, I want only Videos to appear when the videos checkbox is selected.

Have tried creating an event listener for each checkbox to get the value, but unsure about how to have the correct categories displayed when the checkbox is selected. I've also tried passing in the path as an argument (eg. loadCards(category) {func}) but filtered.category is an invalid entry. I have also stored the different categories into a separate array with the appropriate content but not sure where to go from here.

JS:

let data = [
  { category: "Video", title: "Video Title 1" },
  { category: "Video", title: "Video Title 2" },
  { category: "Video", title: "Video Title 3" },
  { category: "Article", title: "Article 1" },
  { category: "Article", title: "Article 2" },
  { category: "Article", title: "Article 3" },
];

let cards = "";
let filtered = {};

function makeCards() {
  for (var i = 0; i < data.length; i  ) {
    if (!filtered[data[i].category]) {
      filtered[data[i].category] = [];
    }
    filtered[data[i].category].push(data[i]);
  }
  for (var i = 0; i < data.length; i  ) {
    cards  = `
        <div >
            <h4 id="A" >${data[i].category}</h4>
            <h3 id="B" >${data[i].title}</h3>
        </div>
      `;
  }
  document.getElementById("data-list").innerHTML = cards;
}

document.addEventListener("load", makeCards());

HTML:

<body>
    <h2 >Resources Library</h2>
    <div >
        <div id="filterArticles">
            <h2 >Filter Resources</h2>
            <div >
                <h3 >Types</h3>
                <ul  id="filterList">
                    <input id="A"  type="checkbox" name="articles" value="Article">
                    <label for="articles">Articles</label><br>
                    <input id="B"  type="checkbox" name="video" value="Video">
                    <label for="video">Video</label><br>
                </ul>
            </div>
        </div>
        <div id="newsArticles">
            <div id="data-list" >
            </div>
        </div>
    </div>
    <script src="./index.js"></script>
</body>

Tried the following:

document.addEventListener("change", () => {
    const checkbox = document.getElementById("A");
    const isChecked = document.getElementById("A").checked;

    if (isChecked == true) {
        console.log(checkbox.value)
    }
}

and I think I'm on the right path, but there must be an easier way to achieve this so I don't have to create a separate function for each category. Any help would be greatly appreciated.

CodePudding user response:

Adding a categories paramater to the makeCards() function, to provide the type of cards for the function to display. And using filter() and forEach() to limit the cards displayed if there are any checkboxes checked, as indicated by the categories array parameter, and write those cards to the page.

Also, adding a change event handler to the ul element that contains the checkboxes, and upon the change of any checkbox get the value of all the checked boxes, and passing an array of these values to the makeCards() function. Here using filter() and map() to limit the categories array parameter to only checked boxes, and then return an array with only the checkbox values.

function makeCards(categories = []) {
  let dl = document.getElementById("data-list");
  dl.innerHTML = '';
  data.filter(function (card) {
    return ((categories && -1 < categories.indexOf(card.category)) || (0 === categories.length));
  })
    .forEach(function (card) {
      dl.innerHTML  = `
          <div >
              <h4 >${card.category}</h4>
              <h3 >${card.title}</h3>
          </div>
        `;
    });
}

document.querySelector('#filterList').addEventListener('change', function ({currentTarget}) {
  makeCards(
    Array.from(currentTarget.querySelectorAll('.checkbox'))
      .filter(function (cb) { return cb.checked; })
      .map(function (cb) { return cb.value;})
  );
});

let data = [
  { category: "Video", title: "Video Title 1" },
  { category: "Video", title: "Video Title 2" },
  { category: "Video", title: "Video Title 3" },
  { category: "Article", title: "Article 1" },
  { category: "Article", title: "Article 2" },
  { category: "Article", title: "Article 3" },
];

document.addEventListener("load", makeCards());
<h2 >Resources Library</h2>
<div >
  <div id="filterArticles">
    <h2 >Filter Resources</h2>
    <div >
      <h3 >Types</h3>
      <ul  id="filterList">
        <input id="A"  type="checkbox" name="articles" value="Article">
        <label for="articles">Articles</label><br>
        <input id="B"  type="checkbox" name="video" value="Video">
        <label for="video">Video</label><br>
      </ul>
    </div>
  </div>
  <div id="newsArticles">
    <div id="data-list" >
    </div>
  </div>
</div>


And here's a way to dynamically write the category options to the page, in this case using reduce() to compile the duplicated category names into an array of unique categories:

let data = [
  { category: "Video", title: "Video Title 1" },
  { category: "Video", title: "Video Title 2" },
  { category: "Video", title: "Video Title 3" },
  { category: "Article", title: "Article 1" },
  { category: "Article", title: "Article 2" },
  { category: "Article", title: "Article 3" },
];

(function makeCategories () {
  let fl = document.querySelector('#filterList');
  fl.innerHTML = '';
  data.reduce(function (prev, card) {
    if ( -1 === prev.indexOf(card.category) ) {
      prev.push(card.category);
    }
    return prev;
  }, [])
    .sort().forEach(function (category) {
      fl.innerHTML  = `<input  type="checkbox" name="articles" value="${category}">
  <label for="articles">${category}</label><br>`;
    });
}());
<ul  id="filterList">
</ul>

With these operations, adding cards and categories is a simple matter of updating the data array.

  • Related