在Knockout中过滤observableArray

时间:2014-03-15 01:18:59

标签: javascript knockout.js filtering durandal

我被困在过滤Knockout中的observableArray。我显示了一个人员列表,并希望有一个复选框列表,根据选中的复选框实时更新人员列表(例如:年龄:18 -22,23-30,31-36,等)

I read Ryan Niemeyer's关于效用函数的文章,但我仍然陷入困境。我不知道如何使用随后过滤的项目更新可观察数组。

我正在使用DurandalDozerJS以及我目前拥有的标记和shell文件

<section class="main">
  <div class="main--contain">
    <a data-bind="click: find25to35">Between 25 and 35</a>

    <form>
        <input type="search" name="search" placeholder="Search" class="search-input">
    </form>

    <ul class="user-list" data-bind="foreach: people">
        <li>
            <h2 data-bind="text: username"></h2>
            <h2 data-bind="text: firstname + lastname"></h2>
        </li>
    </ul>
</div>

define(['knockout'], function (ko) {

  var ctor = {
    people: ko.observableArray(),

    activate: function () {
      var self = this;

      var request = $.ajax({
        url: '/api/users/',
        type: 'GET'
      });

      request.done(function (res) {
        if (res.data.length) {
          res.data.reverse();
          for (var i = 0, z = res.data.length; i < z; i++) {
            self.people.push(res.data[i])
          }
        }
      })
    },

    find25to35: function () {
      var self = this;

      self.people = [];

      ko.utils.arrayForEach(self.people(), function(person) {
        if (person.age >=18 && person.age <=25) {
          self.people.push(person);
        }
      });
}
  };

  return ctor;

});

1 个答案:

答案 0 :(得分:2)

以下行无效......

<h2 data-bind="text: firstname + lastname"></h2>

淘汰赛很聪明但不那么聪明。您需要将计算的observable添加到您的人员视图模型中,如此...

function Person(person) {
    var self = this;

    self.username = ko.observable(person.userName);
    self.firstname = ko.observable(person.firstName);
    self.lastname = ko.observable(person.lastName);
    self.age = ko.observable(person.age);
    self.name = ko.computed(function () {
        return self.firstname() + self.lastname();
    });
}

将您的绑定更改为...

<ul class="user-list" data-bind="foreach: people">
    <li>
        <h2 data-bind="text: username"></h2>
        <h2 data-bind="text: name"></h2>
    </li>
</ul>

然后,你可能想要添加一个过滤后的人员列表,该列表会加载符合条件的所有人,首先从所有人开始,然后清除它并与符合条件的人重新加载。如果有人想通过一套新标准找人,该怎么办?你真的想要进行一次AJAX调用再次获取所有人吗?我的经验是,除非您正在运行复杂的自定义搜索,否则最好只获取一次数据并让用户操纵它。这意味着你最终会得到一个与此类似的数组...

filteredPeople: ko.observableArray([]),

// -- your other relevant code goes here ---

find25to35: function () {
  var self = this;

  // set how many people are currently in array
  var count = filteredPeople().length;

  // loop through array to get rid of all elements to clear it,
  // making sure we're not modifying the collection as we are 
  // iterating through it which creates pointer errors
  for (var i = 0; i < count; i++) {
      filteredPeople().pop();
  }

  ko.utils.arrayForEach(self.people(), function(person) {
      if (person.age() >= 25 || person.age() <= 35) {
          filteredPeople.push(person);
      }
  });
}

不要忘记Knockout observables上的那些括号,因为那些observables实际上是返回一个对象的方法,你希望它们返回你放入它们的内容,而不是用于跟踪它们当前值的缩小(或完整)方法这将导致Undefined错误。哦,当你应用你的绑定时,为了安全起见,因为你正在使用顶级功能,你可能有必要像这样添加一个引用......

<a data-bind="click: $root.find25to35">Between 25 and 35</a>

您个人名单的绑定会发生变化以反映过滤...

<ul class="user-list" data-bind="foreach: filteredPeople">

最后,考虑使该功能更具动态性,以便能够将其重用于其他搜索条件,否则您将违反DRY principle。请考虑以下内容......

<a data-bind="click: $root.findByAge($data, minAge, maxAge)">Find By Age</a>

...并从那里开始,使您的输入功能和可重用性。请记住,如果使用jQuery来获取它们的值,它们不需要处于某种形式。

编辑注意事项:意识到我忘了清除正确的观察结果,并没有注意到该方法中的年龄已经关闭导致所有麻烦。代码已修复。