0

I have been struggling to get round an issue with filtering multiple data attributes that I have stored in an array. I have 2 different filter types (filter topic and filter content type) topics being article topics and type being video or post etc. I am using data-attributes on the articles to manage these different types of filter.

So from there I have a click event looking at different li elements on the page, these have the data attributes assigned to them also.

<li class="filter-pill" data-category-type="Arts & Creative Industries">Arts & Creative Industries</li>
<li class="filter-pill" data-category-name="Video">Video</li>

I store this data in an array and then show the articles that match the array data. However when clicking the first filter nothing shows until the second filter (video or post) is clicked.

I need to be able to filter by AND and OR and can not work this part out.

Here is a fiddle of all my code https://jsfiddle.net/dfwpmLt6/

8
  • This line return filterArray.includes($(this).data('category-type')) && filterArray.includes($(this).data('category-name')); says you have to have both type and name selected - if either filter is unselected, you get nothing. Commented Feb 21, 2023 at 15:34
  • Off topic: note that your UI category type/name are the opposites of the data- type/name attributes. Commented Feb 21, 2023 at 15:36
  • Updated the UI the category type/name to match Commented Feb 21, 2023 at 15:55
  • When I use OR it displays all the video articles but ignores the category Commented Feb 21, 2023 at 15:56
  • I think you should move the push to the filterArray to the else block. Commented Feb 21, 2023 at 16:08

1 Answer 1

0

When you say, "I need to be able to filter by AND and OR", what I understand you to mean is this:

  • If some Names and some Types are selected: show the articles whose Name and Type are both selected.
  • If some Names are selected, but no Types: show the articles whose Name is selected, regardless of Type.
  • If some Types are selected, but no Names: show the articles whose Type is selected, regardless of Name.

If this understanding is correct, I think it will be very difficult to accomplish is tracking the selected filters in a single array. This is because we need to check separately if any names are selected as well as any types. My recommendation would be to store these selected filters separately. For example:

const selectedFilters = {
  names: [],
  types: []
};

We would then need to update the logic that updates the selectedFilters:

const changedFilters = {
  names: $this.data('category-name'),
  types: $this.data('category-type')
};

['names', 'types'].forEach(key => {
  if (!changedFilters[key]) { return; }
    
  const value = changedFilters[key];
  const index = selectedFilters[key].indexOf(value);
    
  if (index > -1) {
    selectedFilters[key] = selectedFilters[key].slice(0, index).concat(selectedFilters[key].slice(index + 1));
  } else {
    selectedFilters[key].push(value);
  }
});

Finally, we loop through each .article-child and determine whether to show or hide it (using jQuery's .toggle method). The logic will filter by Name only if there are selected Names and will filter by Type only if there are selected Types:

$('.article-child').each(function () {
  const $this = $(this);
  const categoryName = $this.data('category-name');
  const categoryType = $this.data('category-type');

  let isVisible = true;
  if (selectedFilters.names.length) {
    isVisible = isVisible && selectedFilters.names.includes(categoryName);
  }
  if (selectedFilters.types.length) {
    isVisible = isVisible && selectedFilters.types.includes(categoryType);
  }

  $this.toggle(isVisible);
});

Here is an example fiddle.

Sign up to request clarification or add additional context in comments.

1 Comment

This is great thank you, I have created 2 arrays and then used if and else if statements but I think the function will be more efficient.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.