[英]How to data bind to a list of objects with knockout?
Here is my view model. 这是我的视图模型。
Server side: 服务器端:
public class ShoppingListModel
{
public string Name { get; set; }
public List<ItemModel> Items{ get; set; }
public ShoppingListModel()
{
Items=new List<ItemModel>();
}
}
On the client side, I use knockout.mapping
. 在客户端,我使用
knockout.mapping
。
ShoppingListModel = function(data) {
var vm = ko.mapping.fromJSON(data);
return vm;
};
To bind the server-side model to the client-side model: 要将服务器端模型绑定到客户端模型:
@{
var jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var data = new JavaScriptSerializer().Serialize(JsonConvert.SerializeObject(Model, jsonSerializerSettings));
}
@section scripts {
<script src="~/App/ShoppingListModel.js"></script>
<script>
var vm = ShoppingListModel(@Html.Raw(data));
ko.applyBindings(vm);
</script>
}
The code above: 上面的代码:
JSON.NET
to serialize the server-side Model
into a camel cased json. JSON.NET
将服务器端Model
序列化为驼峰式json。 Now I want to take advantage of the two-way binding. 现在,我想利用双向绑定。
First I tested on the Name
: 首先,我测试了
Name
:
@Html.HiddenFor(model => model.Name, new { @data_bind="value:name"})
<input type="text" data-bind="value:name"/>
It went well, I was able to edit the Name
value on a text input
and persist the value into the hidden input
. 一切顺利,我能够在文本
input
编辑Name
值,并将该值保留到隐藏的input
。 The updated value could reach the POST action when the form is submitted. 提交表单后,更新后的值可能会达到POST操作。
Now the question: how to implement the binding on the list? 现在的问题是:如何在列表上实现绑定?
My test is to remove one item from the 'Items' list: 我的测试是从“项目”列表中删除一项:
@Html.HiddenFor(model => model.Items, new { data_bind = "value: items" })
<tbody data-bind="foreach:items">
<tr>
<td>
<span data-bind="text:name"></span>
</td>
<td><span data-bind="text:count"></span></td>
<td>
<button class="btn btn-xs" data-bind="click:$parent.remove">
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
</tbody>
A console.log()
tells me that the client-side model has been updated, but this time, the binding on the HiddenFor
has never worked! console.log()
告诉我客户端模型已经更新,但是这次, HiddenFor
上的HiddenFor
从未起作用! When the form is submitted, Items
is always null. 提交表单后,
Items
始终为null。
I guess it is reasonable because in Html: 我认为这是合理的,因为在HTML中:
<input type="hidden" value="xxx" />
we are expecting the value of an input to be a simple value. 我们期望输入的值是一个简单的值。
I was thinking about loop through the list and data-bind from there. 我正在考虑遍历列表并从那里进行数据绑定。 But it is also difficult.
但这也是困难的。 The knockout
foreach
is on tbody
tag while a C# foreach
is placed around tr
(inside tbody
). 敲除
foreach
在tbody
标签上,而C# foreach
放在tr
周围( tbody
内部)。
Then what is the correct way to bind the list? 那么绑定列表的正确方法是什么?
Here is my solution based on Fabio's suggestion: 这是根据Fabio的建议我的解决方案:
add a computed value to bind the list into a json string. 添加计算值以将列表绑定到json字符串中。
vm.itemsJson = ko.computed(function() {
return ko.toJSON(vm.items);
},this);
add a hidden input to hold the json string and post with our form. 添加一个隐藏的输入来保存json字符串并以我们的表单发布。
<input name="itemsjson" type="hidden" data-bind="value:itemsJson"/>
besides 除了
public List<ItemModel> Items{ get; set; }
Add another string property to hold the posted json. 添加另一个字符串属性以保存发布的json。
public string ItemsJson { get; set; }
At this point, we are able to see the ItemsJson
value successfully sent to the controller action. 至此,我们可以看到
ItemsJson
值已成功发送到控制器操作。
Since it is typed model, we are to use JSON.Net
to deserialize. 由于它是类型化模型,因此我们将使用
JSON.Net
进行反序列化。
var items=JArray.Parse(model.ItemsJson);
model.Items = items.
Select(i => new ItemModel {Name = (string) i["name"], Count = (int) i["count"]})
.ToList();
return View(model);
Be sure to use JArray.Parse()
for a List
instead of JObject.Parse()
. 确保将
JArray.Parse()
用于List
而不是JObject.Parse()
。
It works. 有用。
Let's see if there is any better way than manually parsing json string. 让我们看看是否有比手动解析json字符串更好的方法。 Otherwise, I would mark Fabio's answer as our solution after this weekend.
否则,我将在本周末之后将法比奥的答案标记为我们的解决方案。
You could use computed observables to bind the hidden field, like this: 您可以使用计算的可观察值绑定隐藏字段,如下所示:
function YourViewModel() {
var self = this;
self.items = ko.observableArray(); //fill it with your stuff;
self.valueForHiddenField = ko.computed(function() {
return ko.toJSON(self.items);
}, this); //use this observable as value of your hidden field
}
For more information http://knockoutjs.com/documentation/json-data.html 有关更多信息,请访问http://knockoutjs.com/documentation/json-data.html
EDIT 1 编辑1
You don't need to convert the json inside your controller. 您无需在控制器内部转换json。 Instead sending a json to your server, send the collection using list of hidden fields.
而不是将json发送到您的服务器,而是使用隐藏字段列表发送集合。 Like this:
像这样:
<form>
<!-- ko foreach: items -->
<input type="hidden" data-bind="value: property1, attr: { name: 'Items[' + $index() + '].Property1' }">
<input type="hidden" data-bind="value: property2, attr: { name: 'Items[' + $index() + '].Property2' }">
<!-- /ko -->
</form>
Then you can send the post, and don't need to worry about the collection, it will refresh automatically when you changed the items observableArray. 然后,您可以发送帖子,而不必担心集合,当您更改项目observableArray时,它将自动刷新。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.