在 Knockout 中更新 ViewModel
Update ViewModel in Knockout
我是 Knockout 的新手。我正在尝试使用 Knockout 开发购物车功能。
我的问题是,当我想在我的购物车中放置一个 计数器 时,计数器将应用于所有购物车内容。
var FoodVM = function() {
self.ID = ko.observable();
self.Name = ko.observable();
self.Price = ko.observable();
self.Clicks = ko.observable(0);
self.clickCounterAdd = function() {
self.Clicks(self.Clicks() + 1);
};
};
var FoodsListVM = function() {
this.FoodsList = ko.observableArray([new FoodVM()]);
};
$(document).ready(function() {
var model = new FoodsListVM();
ko.applyBindings(model);
var data = [{
ID: 1,
Name: "Test 1",
Price: 25000
},
{
ID: 2,
Name: "Test 2",
Price: 30000
},
{
ID: 3,
Name: "Test 3",
Price: 35000
}
];
model.FoodsList(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Add</th>
<th>Count</th>
</tr>
<tbody data-bind="foreach: FoodsList">
<tr>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Price"></td>
<td>
<button data-bind="click: clickCounterAdd" style="width: 73px;">Add</button>
</td>
<td>
<input type="text" data-bind="value: Clicks" style="width: 20px;">
</td>
</tr>
</table>
JSFiddle 演示。
你能告诉我我的错误在哪里吗?
您的第一个错误是忘记在 FoodVM
中定义 self
。
var self = this;
因此,您将所有可观察对象和 clickCounterAdd
函数附加到 self
恰好在全局范围内的任何内容,而不是您的视图模型。
下一个错误是您使用单个 FoodVM
...
初始化 FoodsList
属性
this.FoodsList = ko.observableArray([new FoodVM()]);
...但片刻之后,您会用一个简单的 JS 对象覆盖它,data
。
model.FoodsList(data);
这意味着 FoodVM
丢失了 - data
中的项目不会自行变成 FoodVM
。需要某种循环才能将数据数组中的普通对象转换为 FoodVM
个实例。通常这是通过 .map()
调用完成的。
这是构建视图模型的更好方法。
以从参数对象(即从模型)初始化自己的方式编写视图模型。使数据的 属性 名称与视图模型的 属性 名称匹配。
function someViewmodel(params) {
this.data = ko.observable(params.data);
}
在你的例子中有两个视图模型,Food
和 FoodsList
(我觉得称它们为 *VM
是多余的,所以我没有那样做)。我在模型 (foods
) 中添加了一层以匹配 FoodsList
.
中同名的 属性
var Food = function(params) {
var self = this;
self.ID = ko.observable(params.ID);
self.Name = ko.observable(params.Name);
self.Price = ko.observable(params.Price);
self.clicks = ko.observable(0);
self.countClick = function () {
self.clicks(self.clicks() + 1);
};
};
var FoodsList = function(params) {
var self = this;
self.foods = ko.observableArray(params.foods.map(function (item) {
return new Food(item);
}));
};
// ----------------------------------------------------------------------
var model = {
foods: [
{ ID: 1, Name: "Test 1", Price: 25000 },
{ ID: 2, Name: "Test 2", Price: 30000 },
{ ID: 3, Name: "Test 3", Price: 35000 }
]
};
var vm = new FoodsList(model);
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Add</th>
<th>Count</th>
</tr>
<tbody data-bind="foreach: foods">
<tr>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Price"></td>
<td>
<button data-bind="click: countClick" style="width: 73px;">Add</button>
</td>
<td>
<input type="text" data-bind="value: clicks" style="width: 20px;">
</td>
</tr>
</table>
请注意在初始化过程中一切都是如何自我引导的,new FoodsList(model)
构建了一个完整的嵌套视图模型。
顺便说一句,这个任务很常见,所以有一个 knockout 插件可以为您完成:http://knockoutjs.com/documentation/plugins-mapping.html。花点时间阅读它的文档。
看看下面的变化
var Food = function(params) {
var self = this;
self.ID = ko.observable(params.ID);
self.Name = ko.observable(params.Name);
self.Price = ko.observable(params.Price);
self.clicks = ko.observable(0);
self.countClick = function () {
self.clicks(self.clicks() + 1);
};
};
var FoodsList = function(params) {
var self = this;
self.foods = ko.observableArray(params.foods.map(function (item) {
return new Food(item);
}));
};
// ----------------------------------------------------------------------
var model = {
foods: [
{ ID: 1, Name: "Test 1", Price: 25000 },
{ ID: 2, Name: "Test 2", Price: 30000 },
{ ID: 3, Name: "Test 3", Price: 35000 }
]
};
var vm = new FoodsList(model);
ko.applyBindings(vm);
我是 Knockout 的新手。我正在尝试使用 Knockout 开发购物车功能。
我的问题是,当我想在我的购物车中放置一个 计数器 时,计数器将应用于所有购物车内容。
var FoodVM = function() {
self.ID = ko.observable();
self.Name = ko.observable();
self.Price = ko.observable();
self.Clicks = ko.observable(0);
self.clickCounterAdd = function() {
self.Clicks(self.Clicks() + 1);
};
};
var FoodsListVM = function() {
this.FoodsList = ko.observableArray([new FoodVM()]);
};
$(document).ready(function() {
var model = new FoodsListVM();
ko.applyBindings(model);
var data = [{
ID: 1,
Name: "Test 1",
Price: 25000
},
{
ID: 2,
Name: "Test 2",
Price: 30000
},
{
ID: 3,
Name: "Test 3",
Price: 35000
}
];
model.FoodsList(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Add</th>
<th>Count</th>
</tr>
<tbody data-bind="foreach: FoodsList">
<tr>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Price"></td>
<td>
<button data-bind="click: clickCounterAdd" style="width: 73px;">Add</button>
</td>
<td>
<input type="text" data-bind="value: Clicks" style="width: 20px;">
</td>
</tr>
</table>
JSFiddle 演示。
你能告诉我我的错误在哪里吗?
您的第一个错误是忘记在 FoodVM
中定义 self
。
var self = this;
因此,您将所有可观察对象和 clickCounterAdd
函数附加到 self
恰好在全局范围内的任何内容,而不是您的视图模型。
下一个错误是您使用单个 FoodVM
...
FoodsList
属性
this.FoodsList = ko.observableArray([new FoodVM()]);
...但片刻之后,您会用一个简单的 JS 对象覆盖它,data
。
model.FoodsList(data);
这意味着 FoodVM
丢失了 - data
中的项目不会自行变成 FoodVM
。需要某种循环才能将数据数组中的普通对象转换为 FoodVM
个实例。通常这是通过 .map()
调用完成的。
这是构建视图模型的更好方法。
以从参数对象(即从模型)初始化自己的方式编写视图模型。使数据的 属性 名称与视图模型的 属性 名称匹配。
function someViewmodel(params) {
this.data = ko.observable(params.data);
}
在你的例子中有两个视图模型,Food
和 FoodsList
(我觉得称它们为 *VM
是多余的,所以我没有那样做)。我在模型 (foods
) 中添加了一层以匹配 FoodsList
.
var Food = function(params) {
var self = this;
self.ID = ko.observable(params.ID);
self.Name = ko.observable(params.Name);
self.Price = ko.observable(params.Price);
self.clicks = ko.observable(0);
self.countClick = function () {
self.clicks(self.clicks() + 1);
};
};
var FoodsList = function(params) {
var self = this;
self.foods = ko.observableArray(params.foods.map(function (item) {
return new Food(item);
}));
};
// ----------------------------------------------------------------------
var model = {
foods: [
{ ID: 1, Name: "Test 1", Price: 25000 },
{ ID: 2, Name: "Test 2", Price: 30000 },
{ ID: 3, Name: "Test 3", Price: 35000 }
]
};
var vm = new FoodsList(model);
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Add</th>
<th>Count</th>
</tr>
<tbody data-bind="foreach: foods">
<tr>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Price"></td>
<td>
<button data-bind="click: countClick" style="width: 73px;">Add</button>
</td>
<td>
<input type="text" data-bind="value: clicks" style="width: 20px;">
</td>
</tr>
</table>
请注意在初始化过程中一切都是如何自我引导的,new FoodsList(model)
构建了一个完整的嵌套视图模型。
顺便说一句,这个任务很常见,所以有一个 knockout 插件可以为您完成:http://knockoutjs.com/documentation/plugins-mapping.html。花点时间阅读它的文档。
看看下面的变化
var Food = function(params) {
var self = this;
self.ID = ko.observable(params.ID);
self.Name = ko.observable(params.Name);
self.Price = ko.observable(params.Price);
self.clicks = ko.observable(0);
self.countClick = function () {
self.clicks(self.clicks() + 1);
};
};
var FoodsList = function(params) {
var self = this;
self.foods = ko.observableArray(params.foods.map(function (item) {
return new Food(item);
}));
};
// ----------------------------------------------------------------------
var model = {
foods: [
{ ID: 1, Name: "Test 1", Price: 25000 },
{ ID: 2, Name: "Test 2", Price: 30000 },
{ ID: 3, Name: "Test 3", Price: 35000 }
]
};
var vm = new FoodsList(model);
ko.applyBindings(vm);