我有以下 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/