将js对象更改为使用嵌套的可观察数组敲除js视图模型

Change js object to knockout js view model with nested observable arrays

本文关键字:js 数组 观察 模型 视图 嵌套 对象      更新时间:2023-09-26

我从服务器上获得了一个特定的JSON,并希望能够在嵌套数组(变体列表、变体和列)中添加/编辑/删除项,但我不知道如何使用knockout.js来做到这一点。

我知道我需要将JSON对象中的属性更改为observables,并且我使用"Binding"下显示的映射插件来执行此操作,并且所有值都已正确绑定-但如果我更改输入字段中的值,则模型/视图不会自动更新。

为什么?我是不是错过了什么?

那么knockout.js是否支持原生嵌套数组而无需编写自己的代码?如何将这个JSON转换为一个完整的knockout.js视图模型?

我使用当前可用的版本(淘汰版:v2.1.0,映射插件:v2.3.2)。

JSON

{
    "VariantList": [
        {
            "ColumnCount": 1,
            "Variants": [
                {
                    "Title": "One column 100%",
                    "Columns": [
                        "100 %"
                    ]
                }
            ]
        },
        {
            "ColumnCount": 2,
            "Variants": [
                {
                    "Title": "Two columns 50%/50%",
                    "Columns": [
                        "50%",
                        "50%"
                    ]
                },
                {
                    "Title": "Two columns 75%/25%",
                    "Columns": [
                        "75%",
                        "25%"
                    ]
                }
            ]
        }
    ]
}

HTML

<div data-bind="foreach: VariantList">
    <h2 data-bind="text: ColumnCount"></h2>
    <div data-bind="foreach: Variants">
        <h3 data-bind="text: Title"></h3>
        <table style="width:500px">
            <tr>
                <!-- ko foreach: Columns -->
                <th><input data-bind="value: $data"/></th>
                <!-- /ko -->
            </tr>
            <tr>
                <!-- ko foreach: Columns -->
                <td data-bind="style: {width:$data}, text:$data"></td>
                <!-- /ko -->
            </tr>
        </table>
   </div>
</div>

绑定

var viewModel;
$(function(){
   viewModel = ko.mapping.fromJS(myJson);
   ko.applyBindings(viewModel);
});

问题是映射插件默认情况下不会将数组中的基元值转换为可观测值。即使是这样,当您将$data与输入绑定时,您也会得到它的展开值,而不是可观察值。

实现这一点的最简单方法是对数据进行如下结构:

var data = {
    "VariantList": [
        {
            "ColumnCount": 1,
            "Variants": [
                {
                    "Title": "One column 100%",
                    "Columns": [
                        { value: "100 %" }
                    ]
                }
            ]
        },
        {
            "ColumnCount": 2,
            "Variants": [
                {
                    "Title": "Two columns 50%/50%",
                    "Columns": [
                        { value: "50%" },
                        { value: "50%" }
                    ]
                },
                {
                    "Title": "Two columns 75%/25%",
                    "Columns": [
                        { value: "75%" },
                        { value: "25%" }
                    ]
                }
            ]
        }
    ]
};

然后在Columns上的循环中与value绑定。以下是一个示例:http://jsfiddle.net/rniemeyer/MCnMX/

如果您无法在此结构中提取数据,那么您可以考虑使用映射选项,将其转换为这样的结构。以下是一个示例:http://jsfiddle.net/rniemeyer/sH3r2/

var mappingOptions = {
    Columns: {
        create: function(options) {
            return { value: ko.observable(options.data) };  
        }
    }        
};
var viewModel = ko.mapping.fromJS(data, mappingOptions);

如果您需要以收到JSON的相同格式将其发送回服务器,那么有几个选项。我有点喜欢这样做:http://www.knockmeout.net/2011/04/controlling-how-object-is-converted-to.html.以下是您的数据示例:http://jsfiddle.net/rniemeyer/Eed2R/

var Value = function(val) {
    this.value = ko.observable(val);  
};
Value.prototype.toJSON = function() {
    return ko.utils.unwrapObservable(this.value);  
};
var mappingOptions = {
    Columns: {
        create: function(options) {
            return new Value(options.data);
        }
    }        
};
var viewModel = ko.mapping.fromJS(data, mappingOptions);