KnockoutJS正在更新数组中的所有对象,而不仅仅是One

时间:2013-06-03 20:53:25

标签: javascript knockout.js

所以这是一个复杂的问题。我会尽力在这里解释一下,但已经设置了一个演示问题的小提琴......你可以找到它here

我首先创建了一个Javascript数据传输对象它不仅仅是一个简单的DTO,它试图结合KO映射功能,以便可以使用“GetKnockout()”方法将DTO的内容检索为KO对象。它存储KO对象以及用于在私有属性(_lotKO,_origData)内部初始化属性的对象。

var LotDTO = function (data) {

    //#region Public Properties
    var name            = (data != null) ? data.Name : null;
    var desc            = (data != null) ? data.Description : null;
    var model           = (data != null) ? data.Model : null;
    var buildStage      = (data != null) ? data.BuildStage : null;
    var softwareVersion = (data != null) ? data.SoftwareVersion : null;
    var config          = (data != null) ? data.Configuration : new Array();
    var serialNumbers   = (data != null) ? data.SerialNumbers : new Array();
    //#endregion 

    //#region Private Properties
    var _lotKO = null;
    var _origData = data;
    //#endregion

    //#region Public Methods
    var GetKnockout = function () {
        /// <summary>
        /// Returns a knockout object that can be used to bind to UI elements. It is important to remeber that the values in the knockout object do NOT sync up with the LotDTO values.
        /// </summary>
        /// 
        var self = this;
        if (_lotKO == null) {
            SetKnockout(self);
        }

        return _lotKO;
    }

    var Reset = function () {
        /// <summary>Reverts all the object properties back to their original values</summary>
        /// 
        var self = this;
        name            = (_origData != null) ? _origData.Name : null;
        desc            = (_origData != null) ? _origData.Description : null;
        model           = (_origData != null) ? _origData.Model : null;
        buildStage      = (_origData != null) ? _origData.BuildStage : null;
        softwareVersion = (_origData != null) ? _origData.SoftwareVersion : null;
        config          = (_origData != null) ? _origData.Configuration : new Array();
        serialNumbers   = (_origData != null) ? _origData.BrewerSerialNumbers : new Array();
        //
        // If the KO object has already been defined the reset it's definitions
        if (_lotKO != null) {
              //alert("resetting knockout");
            SetKnockout(self);
        }
    }
    //#endregion

    //#region Private Methods
    function SetKnockout(self) {

        _lotKO = {
            Name            : ko.observable(self.Name),
            Description     : ko.observable(self.Description),
            Model           : ko.observable(self.Model),
            BuildStage      : ko.observable(self.BuildStage),
            SoftwareVersion : ko.observable(self.SoftwareVersion),
            Configuration   : ko.observableArray(self.Configuration),
            SerialNumbers   : ko.observableArray(self.SerialNumbers)
        };
    }

    //#endregion

    return {
        Name            : name,
        Description     : desc,
        Model           : model,
        BuildStage      : buildStage,
        SoftwareVersion : softwareVersion,
        Configuration   : config,
        SerialNumbers   : serialNumbers,
        GetKnockout     : GetKnockout,
        Reset: Reset
    };
}

在我的JSFiddle example中,我还创建了一个函数,当调用它时,它将实例化DTO对象的多个实例并将它们返回到数组中。

到目前为止一直很好......

现在,当我运行小提琴时,表单填充正确,“名称”属性值显示在标签和文本框中。 “SerialNumbers”正确绑定到下拉列表框。

当您单击“Next”/“Prev”按钮时,将调用数组中下一个DTO的“GetKnockout()”函数并将其绑定到表单。 “GetKnockout()”将DTO映射到新的KO ViewModel,除非已经创建了KO ViewModel,然后它将返回现有的KO ViewModel。 ( 重要 :请记住,示例中只有3个DTO,我没有处理错误处理,所以请不要“下一个/上一个”太远!

function BtnNext_OnClick(event) {

    APPScreen.SelectedLotIDX = APPScreen.SelectedLotIDX + 1;
    ko.applyBindings(APPScreen.SelectedLot().GetKnockout(), $("#dvContainer")[0]);

}

到目前为止,一切都按预期工作:当你在DTO中移动时,你可以看到标签,文本框和下拉列表的内容发生了适当的变化。

以下是问题的起始位置...在文本框中,修改名称,然后单击“下一个”/“上一个”按钮之一转到下一个/上一个DTO。您会注意到,当您更改名称时,您可以为所有实例更改它们!所以这让我开始关注我对“this”的使用并引导我做出一些改变。我仍然感到困惑的是,为什么更改绑定文本框的值应该更新所有实例。当您点击“重置()”按钮时,它会正确地重置 的值,只显示正在显示的实例

1 个答案:

答案 0 :(得分:2)

您的问题是您绑定到模型,然后当您单击按钮时更改基础模型的值。你应该做什么是拥有一组模型,然后单击next / prev时只需切换正在显示/编辑的对象。

检查简化小提琴:http://jsfiddle.net/tkirda/BAXsS/1/

<div id="dvContainer">
    <div data-bind="with: CurrentItem">
         <h2 data-bind="text:Name"></h2>

        <input type="text" data-bind="value:Name" />
        <br />
        <select data-bind="options: $root.SerialNumbers"></select>
        <br />
    </div>
    <button id="btnPrev" data-bind="click: Prev">Prev</button>
    <button id="btnNext" data-bind="click: Next">Next</button>
    <button id="btnReset">Reset</button>
</div>

JavaScript的:

function Item(name) {
    this.Name = ko.observable(name);
}

var model = {
    items: ko.observableArray([new Item('A'), new Item('B'), new Item('C')]),
    SerialNumbers: ['1', '2', '3'],
    index: ko.observable(0)
};

model.CurrentItem = ko.observable(model.items()[0]);

model.Next = function () {
    model.index(model.index() + 1);
    model.CurrentItem(model.items()[model.index()]);
};

model.Prev = function () {
    model.index(model.index() - 1);
    model.CurrentItem(model.items()[model.index()]);
};

ko.applyBindings(model, $("#dvContainer")[0]);