【问题标题】:KnockoutJS: Create an observable from click bindingKnockoutJS:从点击绑定创建一个 observable
【发布时间】:2013-06-23 09:36:27
【问题描述】:

我可能想多了,但我想做的是从绑定到函数的点击事件中创建一个 observableArray。基本上,当我单击一个按钮时,我需要根据event.target.html() 过滤结果并创建一个可在页面后面的foreach 循环中使用的可观察对象。

首先,我有一个按钮。

<button data-bind="click: getData">Button Text</button> 

根据按钮文本过滤结果的功能

self.filterFunction = function(x) {
      // do things here
      return (obj);
}

Click 绑定到getData 函数,该函数使用来自click 的DOM 元素调用filterFunction 并创建一个可观察数组

self.getData = function(item, event) {
      viewModel.myFilteredData = ko.observableArray(self.filterFunction($(event.target).html()));  

}

然后我循环通过myFilteredData,但惨遭失败。

<!-- ko foreach: myFilteredData -->
       // Generate HTML here
<!-- /ko -->

有些东西告诉我我在逻辑上失败了,有一种更有效的方法可以做到这一点。我还想找到一种方法来根据一些预设的Button Text 预先填充myFilteredData,以便在单击任何按钮之前在初始页面加载时生成 HTML。

谢谢。

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    也许您遇到的问题是您的foreach 绑定绑定到与单击后生成的不同的可观察数组。这样想吧。鉴于此视图模型:

    {
        myFilteredData: ko.observableArray()
    }
    

    ...当ko.applyBindings 发生时,Knockout 订阅此ko.observableArray 以进行更新,并循环遍历(现在为空的)数组。

    现在,您的点击处理程序发生了:

    viewModel.myFilteredData = ko.observableArray(self.filterFunction($(event.target).html()));  
    

    上面建立的订阅没有被触发,因为可观察数组没有改变;相反,您将其替换为另一个。不幸的是,Knockout 不知道新的。

    我建议不要用新数组替换数组,而是用新数据填充现有数组:

    viewModel.myFilteredData(self.filterFunction($(event.target).html()));  
    

    【讨论】:

    • 不客气。使用 Ryan 建议的计算 observable 也是一个绝妙的主意。
    【解决方案2】:

    您为什么不在视图模型中设置一个 observableArray,创建一个绑定到您的按钮单击的函数,然后传入每个对象?将带有 a for each 的按钮绑定到某些可观察对象或实体,然后在单击按钮时有一个参数,您可以将其推入 observableArray

    【讨论】:

      【解决方案3】:

      Solefald,肯定有更好的方法来做到这一点。

      首先,将一组您自己的“过滤器”对象添加到您的视图模型,以及一个 ko.computed 以提供您过滤的数据。将过滤器按钮绑定到“过滤器”对象数组。像这样的:

      var viewModel = function(){
          var self = this;
          self.filters = [
              {buttonText:'Button Text', filterKey:'filterKeyOne'},
              {buttonText:'Other Button Text', filterKey:'filterKeyTwo'}
          ];
          self.selectedFilterKey = ko.observable('none');
          self.setFilter = function(){...}
      
          self.data = ko.observableArray([...]);
          self.filteredData = ko.computed(function(){...});
      }
      

      并像这样绑定:

      <div data-bind="foreach: filters">
          <button data-bind="click : $parent.setFilter, text: buttonText"></button>
      </div>
      <div data-bind="foreach: filteredData">
          ...
      </div>
      

      通过让 Knockout 对过滤器按钮进行点击绑定,您将获得整个过滤器对象作为“runFilter”函数中的第一个参数。然后,您可以像这样实现您的过滤器按钮单击处理程序(本例中为“setFilter”):

      self.setFilter = function(filterItem){
         self.selectedFilterKey(filterItem.filterKey);
      };
      

      通过将“selectedFilterKey”设置为 observable,您可以将您的过滤数据实现为 ko.computed,当“selectedFilterKey”更改时,它会自动更新 ui,如下所示:

      ...
      self.filteredData = ko.computed(function(){
          //pick the right filter function
          var filterFunction = filterOne;//assign the default filter function
          switch(self.selectedFilterKey()){
              case 'filterKeyOne':
                  filterFunction = self.filterOne;//your first filter
              break;
              case 'filterKeyTwo':
                  filterFunction = self.filterTwo;//your second filter
              break;
          }
          return ko.utils.arrayFilter(self.data(), function(item){        
              //return true if item passes filter
              return filterFunction(item);
          });
      });
      ...
      

      一种函数式方法

      如果您想使用功能更强大的编程方法,请尝试在过滤器对象中定义您的过滤器函数。

      self.filters = [
          {buttonText:'Button Text', filterFunction:function(item){...}},
          {buttonText:'Other Button Text', filterFunction:function(item){...}}
      ];
      

      并存储选择的功能,而不是键

      self.setFilter = function(filterItem){
         self.selectedFilterFunction(filterItem.filterFunction);
      };
      

      跳过switch语句

      ...
      self.filteredData = ko.computed(function(){
          return ko.utils.arrayFilter(self.data(), function(item){        
              //return true if item passes filter
              return self.selectedFilterFunction()(item);
          });
      });
      ...
      

      更多信息

      如果您想了解有关这种排序方法的更多信息,可以在我的博客上阅读:http://ryanrahlf.com/sorting-tables-by-column-header-with-knockout-js/

      我希望这会有所帮助!

      【讨论】:

      • 瑞恩,这太棒了!非常感谢。这解决了我一直试图弄清楚的许多其他事情
      • 太棒了!我很高兴能帮上忙!如果您愿意,请访问我的博客并订阅我的时事通讯。我大约每周发布一次类似的帖子,并为我名单上的人提供特别提示。祝你的项目好运!
      • Ryan,我说得太早了......虽然我有点按照你的例子在做,但我对 Knockout 和 JS 的理解总体上是相当有限的,昨晚花了几个小时之后,我仍然无法在filterFunction:function(){ // some code here }} 和这个函数应该返回什么之间建立联系?我可以在某处看到的过滤器对象中是否有过滤器函数的示例?我搜索了高低,但到目前为止没有任何成功。
      • +1 非常好的帖子!您可以直接传递函数,尽管在 arrayFilter 中而不是将其包装在另一个函数中,对吧?
      • 是的,本杰明,你绝对可以。好眼睛。我想我是这样写的,以反映我在上面部分中的内容,但不需要额外的函数包装器。
      猜你喜欢
      • 2015-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 2014-01-14
      • 2016-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多