简体   繁体   English

如何使用jQuery基于多个数据属性筛选列表项?

[英]How do I filter through list items based on multiple data attributes with jQuery?

Here is my HTML with all of my filters: 这是我的所有过滤器的HTML:

  <div class="search-filters">
    <div class="filter-block">
      <label for="employee_type">Employee Type</label>
      <select id="employee_type" class="category">
        <option value="0">All</option>
        <option value="designer">Designer</option>
        <option value="manager">Manager</option>
        <option value="developer">Developer</option>
        <option value="quality-assurance">Quality Assurance</option>
      </select>
    </div>
    <div class="filter-block">
      <label for="years_xp">Years Experience</label>
      <select id="years_xp" class="category">
        <option value="0">Select years Experience</option>
        <option value="1">1 year</option>
        <option value="2">2 years</option>
        <option value="3">3 years</option>
      </select>
    </div>

  </div>

And my result list is below: 我的结果列表如下:

 <ul class="result-set">
   <li class="result" data-employee-type="designer" data-xp="3" >John Smith</li>
   <li class="result" data-employee-type="manager" data-xp="2" >Billy Joe</li>
   <li class="result" data-employee-type="developer" data-xp="5" >John Appleseed</li>
 </ul>

So what I'm trying to do is filter the results with jQuery using the data attributes and select drop-downs on change. 所以我要做的是使用数据属性使用jQuery过滤结果并选择更改下拉列表。 Right now only one or the other filter works with my jQuery code below. 现在只有一个或另一个过滤器可以使用下面的jQuery代码。 I tried using the .filter function in Jquery but it still only works when one drop-down is changed. 我尝试在Jquery中使用.filter函数,但它仍然只在一个下拉列表更改时才有效。 If I change both it seems to be ignoring one condition. 如果我改变它们似乎忽略了一个条件。

My jQuery: 我的jQuery:

var category_filters = [];

$('.category').on('change', function() {
    category_filters = [];

    $('.search-filters select').each(function() {
        if ($(this).val() != 0) {
            var category = $(this).val();
            category_filters[$(this).attr('id')] = category;
        }
    });

    var employee_type = "";
    var years_xp = "";

    if ('employee_type' in category_filters) {
        employee_type = category_filters['employee_type'];
    }
    if ('years_xp' in category_filters) {
        years_xp = category_filters['years_xp'];
    }

    $(".result-set .result").hide().filter(function() {
        if (employee_type != "") {
            if ($(this).attr('data-employee-type') == employee_type) {
                return true;
            }
        }
        if (years_xp != "") {
            if ($(this).attr('data-xp') == years_xp) {
                return true;
            }
        }
    }).show();

});

Any ideas on what i'm doing wrong? 关于我做错什么的任何想法? I've been stuck on this for almost 6 hours now and have looked at other examples but they just don't seem to work with my case. 我已经坚持了近6个小时了,看了看其他的例子,但它们似乎与我的情况无关。

Ok, so you want both filters to apply at the same time, not just show an item as soon as a single filter matches. 好的,所以你想要同时应用两个过滤器,而不是只要一个过滤器匹配就显示一个项目。 In your filter function you are returning true as soon as you find a match, so that is where the problem lies. 在您的过滤器功能中,一旦找到匹配项就会返回true,这就是问题所在。

I went ahead and updated your code a bit: 我继续并稍微更新了你的代码:

$('.category').on('change', function() {
  var category_filters = [];

  $('.search-filters select').each(function() {
    if ($(this).val() != 0) {
      category_filters[$(this).attr('id')] = $(this).val();
    }
  });

  $(".result-set .result").hide().filter(function() { 
    var show = true;
    for (var category in category_filters) {
       show = show && $(this).data(category) == category_filters[category];
    }

    return show;
  }).show();

});

And a demo: https://jsfiddle.net/04v4bqw5/1/ 并演示: https//jsfiddle.net/04v4bqw5/1/

As you will notice I did some refactoring as well. 你会注意到我也进行了一些重构。 This code assumes that the id of the filter matches exactly with the name of the data attribute you want to apply the filter to, so make sure to check the updated HTML as well. 此代码假定过滤器的id与要应用过滤器的数据属性的名称完全匹配,因此请务必检查更新的HTML。

The javascript has a lot less repetition, and you can add as much additional filters and matching data attributes as you want, and they will work without having to change the javascript. javascript的重复次数要少得多,你可以根据需要添加额外的过滤器和匹配的数据属性,并且无需更改javascript即可运行。

As for the filter function, let me add some comments to explain 至于过滤功能,让我添加一些注释来解释

// assume we'll want to show the item
var show = true;
// go over each active filter
for (var category in category_filters) {
   // check if the filter value matches the data attribute value, and any
   // previous filters did not exclude this item yet (show &&)
   show = show && $(this).data(category) == category_filters[category];
}

return show;

The reason you're getting this result is because of the behaviour of return true; 你得到这个结果的原因是因为return true;的行为return true; . Think of this as a break statement - as soon as this is reached in the .filter function, it thinks its work there is done and it can stop processing. 可以把它想象成一个break语句 - 只要在.filter函数中达到它,就会认为它的工作已经完成,它可以停止处理。 To overcome this, use some local booleans and then evaluate them both at the end of the function to decide whether to return true or not: 要解决这个问题,请使用一些本地布尔值,然后在函数末尾对它们进行评估,以决定是否返回true:

var etMatch = false, xpMatch = false;

if (employee_type != "") {
    if ($(this).attr('data-employee-type') == employee_type) {
        etMatch = true;
    }
}

if (years_xp != "") {
    if ($(this).attr('data-xp') == years_xp) {
        xpMatch = true;
    }
}

if (etMatch && xpMatch) { return true; }

You should use for each filter its function for comparison: 你应该为每个过滤器使用它的功能进行比较:

var compare = {
  "employee-type": function(a,b) { return a===b},
  "years-xp": function(a,b) { return (1*a)<=(1*b) }
}

$(".result-set .result").show().filter(function() {

  var self = this;

  return 
    !Object
     .keys(category_filters)
     .reduce( function(result, i) {

       var filterValue = category_filters[i];
       var itemValue = $(self).attr('data-'+i);

       return result && compare[ i ]( filterValue, itemValue)

     }, true)

}).hide();

[ https://jsfiddle.net/qqc9w4xm/ ] [ https://jsfiddle.net/qqc9w4xm/ ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM