KnockoutJS 映射不

Posted

技术标签:

【中文标题】KnockoutJS 映射不【英文标题】:KnockoutJS Mapping not 【发布时间】:2013-11-15 17:26:15 【问题描述】:

我有带有一系列诊断代码的视图模型。在我的 html 中,我有一个数据绑定到单击的按钮,该单击将空白诊断代码添加到数组中。这一切都有效。

我使用按钮添加诊断代码。这行得通。

我从外部源接收 JSON,然后尝试将其包装在 observable 中。因为它来自外部源,所以它没有我可以绑定的函数,所以我绑定到不属于 viewModel 的函数。

当我尝试将对象转换回 JSON 字符串时,新的诊断代码是空字符串(我在新代码时添加的默认值)。

代码如下:

 <h3>Diagnosis Codes<input type="button" value="Add" data-bind="click:AddDiagnosisCode"/></h3>
    <div data-bind="foreach:DiagnosisCodes">
        <div><input type="text"  data-bind="value:$data"/><input type="button" value="Remove" data-bind="click: function(data, event)  RemoveDiagnosisCode($parent, data, event) "/>
        </div>
    </div>

    <script type="text/javascript">
        function AddDiagnosisCode(item)
        
            item.DiagnosisCodes.push("");
        

        function RemoveDiagnosisCode(item, code) 
            item.DiagnosisCodes.remove(code);
        

        function submitJSON() 
            var test= ko.mapping.toJSON(viewModel); // have also tried ko.toJSON(viewModel)
            alert(test);
        

        var vm = 
           "DiagnosisCodes": ["2345","6789"]
        ;

        var viewModel = ko.mapping.fromJS(vm);     
         ko.applyBindings(viewModel);
    </script>

例如,如果我单击添加并键入代码 ABCD,然后调用 submitJSON,我会看到:


    DiagnosisCodes:["2345","6789",""]

我期待


    DiagnosisCodes:["2345","6789","ABCD"]

更新:看起来映射插件将简单类型(字符串、整数等)的数组转换为 observables 而不是 observableArrays。因此,在调用映射之前,我修改了(在 pax 的帮助下)将字符串数组转换为包含字符串的对象数组。然后在转换为 JSON 时,将它们转换回来:

<h3>Diagnosis Codes<input type="button" value="Add" data-bind="click:AddDiagnosisCode"/></h3>
    <div data-bind="foreach:DiagnosisCodes">
        <div><input type="text"  data-bind="value:code"/><input type="button" value="Remove" data-bind="click: $root.RemoveDiagnosisCode"/>
        </div>
    </div>
<button onclick="submitJSON()">Show</button>

function submitJSON() 
            //convert to JS object first
            var test= ko.mapping.toJS(viewModel);
            UnMapCodes(test);

            alert(ko.toJSON(test));
        

           function Code(code)
        
            var self=this;
            self.code = code;
        

        function MapToCodes(obj)
        
            var codes=[];

            for(var c=0; c<obj.DiagnosisCodes.length; c++)
            
                codes.push(new Code(obj.DiagnosisCodes[c]));
            

            obj.DiagnosisCodes=codes;
        

        function UnMapCodes(obj)
        
            var codes=[];

            for(var c=0; c<obj.DiagnosisCodes.length; c++)
            
                codes.push(obj.DiagnosisCodes[c].code);
            

            obj.DiagnosisCodes=codes;
        


        var vm =             
           "DiagnosisCodes": ["2345","6789"]
        ;

        vm.AddDiagnosisCode= function (item)
            
                self=this;
                self.DiagnosisCodes.push(new Code(""));
            ;
        vm.RemoveDiagnosisCode= function (code) 
                self=this;
                self.DiagnosisCodes.remove(code);
            ;

        MapToCodes(vm);

        var viewModel = ko.mapping.fromJS(vm);     
         ko.applyBindings(viewModel);

【问题讨论】:

【参考方案1】:

代码有几个问题,稍微重构了一下(小提琴:http://jsfiddle.net/VX9f2/2/):

html:

<button data-bind="click:submitJSON">submit json</button>
<h3>Diagnosis Codes<input type="button" value="Add" data-bind="click:AddDiagnosisCode"/></h3>
    <div data-bind="foreach:DiagnosisCodes">
        <div><input type="text"  data-bind="value:code"/><input type="button" value="Remove" data-bind="click: $root.RemoveDiagnosisCode"/>
        </div>
    </div>

js:

var Code = function(code)
    var self = this;
    self.code = ko.observable(code);


var VM = function()
    var self = this;
    self.DiagnosisCodes = ko.observableArray([
        new Code("2345"),
        new Code("6789")]);
    self.AddDiagnosisCode = function() 
        self.DiagnosisCodes.push(new Code(""));
    

    self.RemoveDiagnosisCode = function(item) 
         self.DiagnosisCodes.remove(item);
    

    self.submitJSON = function() 
        var test= ko.mapping.toJSON(self.DiagnosisCodes); // have also tried ko.toJSON(viewModel)
        alert(test);
        


       //var viewModel = ko.mapping.fromJS(new VM());     
         ko.applyBindings(new VM());

为了清楚起见,我用构造函数替换了最初的 ko.mapping 用法。如果您还想使用它,请告诉我。

【讨论】:

您好,谢谢您的回复。关于我正在尝试做的事情的更多背景信息:我从外部源接收 JSON,这就是为什么我使用映射插件将其映射到 observable 的原因。这也是我绑定到不属于 viewModel 的函数的原因。还有什么我可以做的吗? 当然,你可以从映射插件中获取可观察树,然后附加函数。你想让我重做代码来反映这一点吗? (拍脑门)没想到 - 我会试一试 仍有问题:可观察数组似乎正确地保持了数组中的行数,但未保存添加项的值 - 但它们必然具有值的文本框。 好的,用你当前的代码更新小提琴,我会尽力帮助你的。

以上是关于KnockoutJS 映射不的主要内容,如果未能解决你的问题,请参考以下文章

使用可观察数组进行 Knockoutjs 映射和验证

KnockoutJS:将 Observable 属性和函数添加到映射生成的 ObservableArray 中的对象

Knockoutjs 映射不会将 observables 添加到字符串数组中

ASP.NET MVC5 KnockoutJS 映射“未捕获的类型错误:无法读取未定义的属性 'fromJS'”错误

KnockoutJS 3.X API 第八章 映射(mapping)插件

KnockoutJs - 为啥初始化绑定处理程序只被调用一次?