【问题标题】:How to data bind to a list of objects with knockout?如何将数据绑定到具有淘汰赛的对象列表?
【发布时间】:2023-03-31 04:20:01
【问题描述】:

这是我的视图模型。

服务器端:

public class ShoppingListModel
{
    public string Name { get; set; }
    public List<ItemModel> Items{ get; set; }

    public ShoppingListModel()
    {
        Items=new List<ItemModel>();
    }
}

在客户端,我使用knockout.mapping

ShoppingListModel = function(data) {
    var vm = ko.mapping.fromJSON(data);
    return vm;
};

将服务器端模型绑定到客户端模型:

@{
    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>
}

以上代码:

  1. 使用JSON.NET 将服务器端Model 序列化为驼峰式json。
  2. 构建客户端视图模型。
  3. ko.applyBinding()

现在我想利用双向绑定。

首先我在Name上测试:

@Html.HiddenFor(model => model.Name, new { @data_bind="value:name"})
<input type="text" data-bind="value:name"/>

一切顺利,我能够编辑文本 input 上的 Name 值并将该值保存到隐藏的 input 中。提交表单时,更新的值可能会到达 POST 操作。

现在的问题是:如何实现对列表的绑定?

我的测试是从“项目”列表中删除一项:

@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>

console.log() 告诉我客户端模型已更新,但这一次,HiddenFor 上的绑定从未起作用!提交表单时,Items 始终为空。

我想这是合理的,因为在 Html 中:

<input type="hidden" value="xxx" />

我们期望输入的值是一个简单的值。

我正在考虑循环遍历列表并从那里进行数据绑定。但这也很困难。淘汰赛foreach 位于tbody 标签上,而C# foreach 位于tr 周围(在tbody 内)。

那么绑定列表的正确方法是什么?


这是我基于 Fabio 建议的解决方案:

  1. 在客户端 ko 模型中,

添加计算值以将列表绑定到 json 字符串。

vm.itemsJson = ko.computed(function() {
    return ko.toJSON(vm.items);
},this);
  1. 在 html 视图中,

添加一个隐藏的输入来保存 json 字符串并使用我们的表单发布。

<input name="itemsjson" type="hidden" data-bind="value:itemsJson"/>
  1. 在服务器端视图模型中,

另外

public List<ItemModel> Items{ get; set; }

添加另一个字符串属性来保存发布的 json。

public string ItemsJson { get; set; }

此时,我们可以看到ItemsJson 值已成功发送到控制器操作。

  1. 将json字符串解析到服务器端的List中。

由于是类型化模型,我们使用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);

确保使用JArray.Parse() 代替List 而不是JObject.Parse()

有效。

让我们看看有没有比手动解析json字符串更好的方法。否则,我会将 Fabio 的回答标记为本周末之后的解决方案。

【问题讨论】:

    标签: javascript asp.net-mvc knockout.js knockout-mapping-plugin


    【解决方案1】:

    您可以使用计算的 observables 来绑定隐藏字段,如下所示:

    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
    }
    

    欲了解更多信息http://knockoutjs.com/documentation/json-data.html

    编辑 1

    您不需要在控制器中转换 json。而是将 json 发送到您的服务器,而是使用隐藏字段列表发送集合。像这样:

    <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>
    

    然后你就可以发帖了,不用担心集合,当你改变了items observableArray时它会自动刷新。

    【讨论】:

    • 不错的建议。所以当隐藏输入中的 json 值被 POST 到服务器时,那个 Json 值会自动解析成一个 List,我猜?让我试着确认一下。
    • 很遗憾没有。隐藏输入中的 json 是一个字符串,不会自动解析到服务器端模型中。需要一些方法在服务器端进行模型绑定。
    • 我已经使它与手动 json 解析一起工作。将整个内容发布在问题的底部。想知道是否有更优雅的方式。一个大大的“谢谢”。
    • 我编辑了我的答案,现在您可以以更优雅的方式发布您的收藏。希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2013-12-30
    • 2014-03-07
    • 2013-07-17
    • 2013-02-04
    相关资源
    最近更新 更多