【问题标题】:How to bind a function with sub-observables to an observable array?如何将具有子可观察对象的函数绑定到可观察数组?
【发布时间】:2017-09-05 11:00:39
【问题描述】:

我有以下 ViewModel:

var Order =  function(data) {
  this.fruits = ko.observableArray(ko.utils.arrayMap(data.Fruis, function(item) { return item; }));
  this.vegetables = ko.observableArray(ko.utils.arrayMap(data.Vegetables, function(item) { return item; }));
};

我需要定义一些绑定到具体实例的子属性和子可观察对象,以及水果和蔬菜的一些常用方法,:

var Items =  function(data, type) {
  var self = this;
  self.type = type;
  self.choice = ko.observable(-1);
  self.choice.select = ko.computed(function(){
    var id = self.choice();
    // do stuff
  });
  self.choice.remove = function() {
    var id = self.choice.peek();
    // do stuff
  };
  self.add = function(code) {
    //do stuff
    self.choice(id);
  };
};

这是绑定包含我的一组方法和子可观察对象的函数的正确方法,以便我可以使用如下方法:

orderViewModel.fruits.add("apples");
orderViewModel.fruits.add("bananas");
orderViewModel.fruits.choice(0);
orderViewModel.fruits.choice.remove();

console.log(ko.tpJSON(orderViewModel));
// prints: {fruits: [bananas], vegetables: []};

我认为没有必要使用 extenders,因为属性和方法不是通用的,并且不需要对所有 observables 都是通用的。

我尝试从我的 Item 函数返回一个可观察数组,但我无法让它工作,因为子属性和子可观察对象已经丢失。如何将Items 绑定到我的可观察数组?

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    即使您可能不想创建扩展器,但您在这里所做的是扩展可观察数组...

    如果你不想注册扩展程序,你可以创建一个小的帮助函数来创建一个observableArray,并在返回之前为其添加一些方法和属性。

    在下面的示例中,您可以看到一些示例代码。一些重要的建议:

    • 如果您使用这种方法,我建议不要覆盖observableArray 中的默认方法。例如:remove 默认取一个项目;您希望它与外部 choice 索引一起使用...最好选择一个不同的名称,以便继续支持两者。
    • 如果您最终经常使用该扩展,那么创建一个在内部存储可观察数组的干净视图模型可能是值得的。您可以定义一个toArray 方法来导出到普通数组。

    var obsCollection = function(initialItems) {
      
      var items = ko.observableArray(initialItems);
      
      items.choice = ko.observable(-1);
      items.add = items.push;
      
      var ogRemove = items.remove.bind(items);
      
      // I'd rename this to "deleteChoice"
      items.remove = function() {
        var index = items.choice();
        ogRemove(items()[index]);
        // Reset choice to -1 here?
      };
      
      
      return items;
    };
    
    var fruits = obsCollection(["Apple"]);
    
    log(fruits);
    fruits.add("Banana");
    fruits.choice(0);
    fruits.remove();
    log(fruits);
    fruits.remove();
    fruits.add("Mango");
    fruits.add("Lemon");
    log(fruits);
    
    function log(d) {
      console.log(JSON.stringify(ko.unwrap(d)));
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

    编辑以澄清this的使用(缺乏):

    由于我们不使用new 关键字,因此没有必要使用this。在内部,observableArray 创建了一个new 实例,但我们引用此实例的唯一方法是通过items。从数组中分离原型方法时,我们需要确保使用正确的上下文调用它们,通过 bind 或 .call(items)(或 apply)。

    如果您希望代码看起来像“类”,您可以这样做:var self = items; 并继续使用 self 关键字,或者将其重写为使用 new 关键字(我的答案中的最后一个要点)。

    var myArray = ko.observableArray([1,2,3]);
    
    try {
      // Reference the function without binding `this`:
      var removeFromMyArray = myArray.remove;
    
      // Internally, the observableArray.prototype.remove method
      // uses `this` to refer to itself. By the time we call it,
      // `this` will refer to `window`, resulting in an error.
      removeFromMyArray(2);
    } catch(err) {
      console.log("ERROR:", err.message);
      console.log(myArray());
    }
    
    
    // By binding to the array, we ensure that the function reference
    // is always called in the right context.
    var boundRemoveFromMyArray = myArray.remove.bind(myArray);
    boundRemoveFromMyArray(2);
    console.log(myArray());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

    【讨论】:

    • THX,用remove调整了错误,现在是choice.remove 能否请您更新您的答案?
    • 我快拿到了,我相信内部方法,items 应该是this
    • 我不确定你的意思...扩展时,跟踪你的this 上下文很重要,但是如果你在obsCollection 的闭包中定义所有方法,您可以只引用items 中的可观察数组实例。请注意,您可以使用bind 固定this。
    • 如果你想让type 暴露在外面,我会把它放在items 中(因为那是你返回的)。然后您可以通过items.type 引用它,无需使用this。如果type 是“私有”变量,您可以将其作为参数传递,使其在items 的闭包中可用。您可以不使用 var self = this,因为我们没有使用 new 关键字,并且当我们输入 obsCollection 时,this 上下文可以是任何内容,具体取决于调用者的上下文。跨度>
    • 您的回答对我帮助很大!我接受你的回答,因为它引导我找到一个可行的解决方案,我不能多次投票,但恕我直言,我认为它并没有完全解决 thisinside 附加到可观察的自定义方法中的使用..
    猜你喜欢
    • 2017-11-25
    • 2015-03-05
    • 2019-09-09
    • 2012-04-20
    • 2017-07-26
    • 1970-01-01
    • 2018-12-16
    • 2013-05-30
    • 1970-01-01
    相关资源
    最近更新 更多