1

所以这是一个复杂的问题。我会尽我所能在这里解释它,但已经设置了一个 Fiddle 来演示这个问题......你可以在这里找到它

我首先创建了一个 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 示例中,我还创建了一个函数,当调用该函数时,它将实例化 DTO 对象的几个实例并将它们返回到一个数组中。

到目前为止,一切都很好...

现在,当我运行 Fiddle 时,表单会正确填写,“名称”属性值显示在标签和文本框中。“序列号”正确绑定到下拉列表框。

当您单击“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”的使用,并让我做出了一些改变。但是,我仍然对为什么更改绑定文本框的值应该更新所有实例感到困惑。当您点击“Reset()”按钮时,它会正确重置正在显示的实例的值。

4

1 回答 1

2

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

检查简化的小提琴: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]);
于 2013-06-03T21:19:24.607 回答