javascript - 如何将具有子可观察值的函数绑定(bind)到可观察数组?

标签 javascript knockout.js

我有以下 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; }));
};

我需要定义一些绑定(bind)到特定实例的子属性和子可观察量,以及一些水果和蔬菜的常用方法,:

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);
  };
};

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

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: []};

我认为没有必要使用扩展器,因为属性和方法不是通用的,并且不需要对所有可观察对象都是通用的。

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

最佳答案

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

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

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

  • 如果您使用这种方法,我建议不要覆盖 observableArray 中的默认方法。例如:remove默认获取一个项目;您希望它与外部选择索引一起使用...最好选择不同的名称,以便继续支持两者。
  • 如果您最终经常使用该扩展,那么创建一个在内部存储可观察数组的干净 View 模型可能是值得的。您可以定义一个 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。当从数组中分离原型(prototype)方法时,我们需要确保使用正确的上下文调用它们,通过 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>

关于javascript - 如何将具有子可观察值的函数绑定(bind)到可观察数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43322516/

相关文章:

javascript - Firebase 用户上传和个人资料图片

performance - Knockoutjs 在 Internet Explorer 中运行速度极慢

javascript - knockoutjs 通过 subscribe 获取 element.id

Javascript 从基于另一个数组的数组中删除元素

javascript - 动态设置 knockout 下拉值

javascript - 默认情况下限制所有 observable 的速率

javascript - 如何在 Cypress 中获取所有特定按钮并单击具有特定数据 ID 的每个按钮

javascript - OAuth 身份验证 - 使用 JavaScript 的访问 token (CORS 策略)错误

javascript - 使用 Javascript 在弹出窗口中显示页面

javascript - 无法在 NodeJS MySQL 中使用全局变量