可观察到的数组更改不会反映在第一次点击 - KnockoutJS

Posted

技术标签:

【中文标题】可观察到的数组更改不会反映在第一次点击 - KnockoutJS【英文标题】:Observable Array changes are not reflecting on first click - KnockoutJS 【发布时间】:2016-10-04 09:46:13 【问题描述】:

我有一个复选框列表的可观察数组,我正在使用可观察数组处理选中的事件。

现在,当我进行更改时,数组的值会立即更新,但不会反映在 DOM 上。但是当我单击其他项目时,更改会反映出来。

简而言之,数组值的变化不会在第一次点击时反映,但在第二次点击时会反映。

这是我的代码:

        /*--- Factory Objects ---*/
    var ModelFactory = function () 
        this.ModelTitle = ko.observable();
        this.ModelId = ko.observable();
        this.FamilyId = ko.observable();
    
    var SeriesFactory = function (SeriesTitle, SeriesId) 
        this.SeriesTitle = ko.observable();
        this.SeriesId = ko.observable();
    ;
    var OptionsFactory = function (SelectionFlag, OptionTitle, OptionId, OptionPrice, OptionType, ModelId) 
        var self = this;
        this.OptionTitle = ko.observable();
        this.OptionId = ko.observable();
        this.OptionType = ko.observable();
        this.OptionPrice = ko.observable();
        this.ModelId = ko.observable();
        this.SelectionFlag = ko.computed(function () 
            return self.OptionType() === "0" ? self.OptionId() : null;
        );
        this.FormattedOptionPrice = ko.computed(function () 
            return "USD " + self.OptionPrice();
        );
    ;
    /*--- Factory Objects End ---*/
    /*--- ViewModel ----*/
    function OpportunityViewModel() 
        var self = this;
        self.SeriesList = ko.observableArray([]);
        self.ModelList = ko.observableArray([]);
        self.OptionList = ko.observableArray([]);
        self.SelectedOptionsList = ko.observableArray([]);
        self.LoadSeries = function () 
            self.ClearFactory(self.SeriesList);
            for (var i = 0; i < familyList.length; i++) 
                self.SeriesList.push(new SeriesFactory().SeriesId(familyList[i].Id).SeriesTitle(familyList[i].FamilyTitle));
            
        ;
        self.LoadModels = function (seriesId) 
            self.ClearFactory(self.ModelList);
            for (var i = 0; i < productList.length; i++) 
                if (seriesId() === productList[i].FamilyId) 
                    self.ModelList.push(new ModelFactory().ModelId(productList[i].Id).ModelTitle(productList[i].ModelTitle).FamilyId(productList[i].FamilyId));
                
            
        ;
        self.SeriesClick = function (seriesObject, event) 
            if (seriesObject !== null && typeof seriesObject !== 'undefined') 
                self.LoadModels(seriesObject.SeriesId);
            
        ;
        self.ModelClick = function (modelObject, event) 
            if (modelObject !== null && typeof modelObject !== 'undefined') 
                self.LoadOptions(modelObject.ModelId);
            
        ;
        self.LoadOptions = function (modelId) 
            self.ClearFactory(self.OptionList);
            for (var i = 0; i < optionList.length; i++) 
                if (modelId() === optionList[i].ModelId) 
                    self.OptionList.push(new OptionsFactory()
                        .OptionId(optionList[i].Id)
                        .OptionTitle(optionList[i].OptionTitle)
                        .OptionPrice(optionList[i].OptionPrice)
                        .OptionType(optionList[i].OptionType)
                        .ModelId(optionList[i].ModelId)
                        );
                    if (optionList[i].OptionType === "0") 
                        self.SelectedOptionsList.push(optionList[i].Id);
                    
                
            
        ;
        self.SelectedOptions = function (selectedItem) 
            console.clear();
            for (var i = 0; i < self.SelectedOptionsList().length; i++) 
                if (self.SelectedOptionsList()[i] === selectedItem.OptionId()) 
                    self.SelectedOptionsList.remove(selectedItem.OptionId());
                    console.log(JSON.stringify(self.SelectedOptionsList()));
                    return;
                
            
            self.SelectedOptionsList.push(selectedItem.OptionId());
            console.log(JSON.stringify(self.SelectedOptionsList()));
        ;
        self.ClearFactory = function (observableFactory) 
            observableFactory([]);
        ;
    
    /*--- View Model End ---*/
    /*--- Init --- */
    $(function () 
        var opportunityVM = new OpportunityViewModel();
        opportunityVM.LoadSeries();
        ko.applyBindings(opportunityVM);
    );
    /*--- Init End ---*/

和模板

 <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#productSearch">
    Launch Modal
</button>
<div class="modal fade" id="productSearch" role="dialog" aria-labelledby="productDialogTitle">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title" id="productDialogTitle">Product Selection</h4>
            </div>
            <div class="modal-body">
                <div class="row">
                    <div class="col-md-4">
                        <div class="panel panel-primary">
                            <div class="panel-heading">
                                <h3 class="panel-title">Series Selection</h3>
                            </div>
                            <div class="panel-body">
                                <ul data-bind="foreach: SeriesList" id="ulFamilyList">
                                    <li><a class="btn btn-link series" data-bind="text: SeriesTitle, attr: Id: SeriesId, click: $parent.SeriesClick"></a></li>
                                </ul>
                            </div>
                            <div class="panel-footer">

                            </div>
                        </div>
                    </div>
                    <div class="col-md-4">
                        <div class="panel panel-primary">
                            <div class="panel-heading">
                                <h3 class="panel-title">Model Selection</h3>
                            </div>
                            <div class="panel-body">
                                <ul id="ulModelList" data-bind="foreach: ModelList">
                                    <li><a class="btn btn-link productModel" data-bind="text: ModelTitle, attr:Id: ModelId, click: $parent.ModelClick"></a></li>
                                </ul>
                            </div>
                            <div class="panel-footer">

                            </div>
                        </div>
                    </div>
                    <div class="col-md-4">
                        <div class="panel panel-primary">
                            <div class="panel-heading">
                                <h3 class="panel-title">Option Selection</h3>
                            </div>
                            <div class="panel-body">
                                <table class="table table-stripped table-hover table-bordered" id="ulOptionList" data-bind="foreach: OptionList">
                                    <tr class="optionListRow">
                                        <td>
                                            <input type="checkbox" data-bind="value: OptionId, click: $parent.SelectedOptions, checked: $parent.SelectedOptionsList" />
                                            <span data-bind="text: '&nbsp' + OptionTitle()"></span>
                                        </td>
                                        <td>
                                            <p data-bind="text: FormattedOptionPrice"></p>
                                        </td>
                                    </tr>
                                </table>
                            </div>
                            <div class="panel-footer">

                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
            </div>
        </div>
    </div>
</div>

我做错了什么?此外,我只是另一个菜鸟,刚刚开始使用 KnockoutJS。如果这里的专家也优化此代码并展示他们改进它的一些技能,我将不胜感激。

谢谢:)

更新

这是我正在使用的一些测试数据。

        familyList = [
         FamilyTitle: "3 Series", Id: "9e55c0ae-37d0-0d89-808f-acccfb58562f" ,
         FamilyTitle: "5 Series", Id: "3d9d6640-a8b5-b4ed-56d2-ef9d1d6f8544" ,
         FamilyTitle: "7 Series", Id: "c395c655-f302-852a-ccca-1a5e9bf10e0e" ,
         FamilyTitle: "X Series", Id: "3e31300f-1dcb-1d50-f796-c58c76cb4ab2" 
    ];
    productList = [
         ModelTitle: "325i", Id: "e1d17dbf-3142-4bde-89bd-830caa09eb93", FamilyId: "9e55c0ae-37d0-0d89-808f-acccfb58562f" ,
         ModelTitle: "525i", Id: "9ac7da72-5224-6046-3913-c2700c486682", FamilyId: "3d9d6640-a8b5-b4ed-56d2-ef9d1d6f8544" ,
         ModelTitle: "X5", Id: "e64d76e4-73f8-36e5-9eca-27166bcc890b", FamilyId: "3e31300f-1dcb-1d50-f796-c58c76cb4ab2" ,
         ModelTitle: "X6", Id: "b104e806-5652-a21b-0180-a8956246a045", FamilyId: "3e31300f-1dcb-1d50-f796-c58c76cb4ab2" ,
         ModelTitle: "X3", Id: "b3447f56-a51b-a451-29de-26b4b3fd98e9", FamilyId: "3e31300f-1dcb-1d50-f796-c58c76cb4ab2" ,
         ModelTitle: "530i xDrive", Id: "30595eef-d0a7-a234-dc7f-6670a588c00e", FamilyId: "3d9d6640-a8b5-b4ed-56d2-ef9d1d6f8544" ,
         ModelTitle: "740Li", Id: "f19aed7c-f2a8-6777-4ed2-93ef2b717ac3", FamilyId: "c395c655-f302-852a-ccca-1a5e9bf10e0e" ,
         ModelTitle: "325Li xDrive", Id: "eaabc23e-d040-34ee-1e59-b1f6b9bc3cff", FamilyId: "9e55c0ae-37d0-0d89-808f-acccfb58562f" ,
         ModelTitle: "M3", Id: "e200ffba-e70c-e743-e8b5-8dd39061bd7d", FamilyId: "9e55c0ae-37d0-0d89-808f-acccfb58562f" ,
         ModelTitle: "M5", Id: "3d37e4b7-61be-a467-d4b9-aba784dea17b", FamilyId: "3d9d6640-a8b5-b4ed-56d2-ef9d1d6f8544" ,
         ModelTitle: "320i", Id: "398ee891-4847-5f29-b7c9-b98249d6b582", FamilyId: "9e55c0ae-37d0-0d89-808f-acccfb58562f" ,
         ModelTitle: "550i Sedan", Id: "49e7ca96-d801-ff2c-c112-245b1707e6c1", FamilyId: "3d9d6640-a8b5-b4ed-56d2-ef9d1d6f8544" ,
         ModelTitle: "750Li xDrive", Id: "9193cc24-58a8-cb8b-c7d4-f10eddb110b6", FamilyId: "c395c655-f302-852a-ccca-1a5e9bf10e0e" ,
    ];
    optionList = [
         Id: "option01", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "120", OptionType: "0", OptionTitle: "325i Moonroof" ,
         Id: "option02", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "150", OptionType: "1", OptionTitle: "325i 19\" Alloy Wheels" ,
         Id: "option03", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "180", OptionType: "1", OptionTitle: "325i Remote Keyless Entry" ,
         Id: "option04", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "200", OptionType: "0", OptionTitle: "325i Power Locks" ,
         Id: "option05", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "520", OptionType: "0", OptionTitle: "325i 6 Speed Automatic" ,
         Id: "option06", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "600", OptionType: "1", OptionTitle: "325i Pedal Shifters" ,
         Id: "option07", ModelId: "e1d17dbf-3142-4bde-89bd-830caa09eb93", OptionPrice: "540", OptionType: "1", OptionTitle: "325i Heated Front and Back Seats" ,
         Id: "option06", ModelId: "f19aed7c-f2a8-6777-4ed2-93ef2b717ac3", OptionPrice: "690", OptionType: "1", OptionTitle: "740Li Touring Package" ,
         Id: "option09", ModelId: "f19aed7c-f2a8-6777-4ed2-93ef2b717ac3", OptionPrice: "960", OptionType: "0", OptionTitle: "740Li Illuminating" ,
         Id: "option10", ModelId: "9ac7da72-5224-6046-3913-c2700c486682", OptionPrice: "600", OptionType: "0", OptionTitle: "525i 20\" Alloy Wheels" ,
         Id: "option11", ModelId: "9ac7da72-5224-6046-3913-c2700c486682", OptionPrice: "320", OptionType: "0", OptionTitle: "525i Tech Package" ,
         Id: "option12", ModelId: "9ac7da72-5224-6046-3913-c2700c486682", OptionPrice: "542", OptionType: "1", OptionTitle: "525i Premium Package" ,
         Id: "option13", ModelId: "9ac7da72-5224-6046-3913-c2700c486682", OptionPrice: "520", OptionType: "1", OptionTitle: "525i Sports Package" ,
         Id: "option14", ModelId: "9ac7da72-5224-6046-3913-c2700c486682", OptionPrice: "540", OptionType: "0", OptionTitle: "525i Heated Back Seats" ,
         Id: "option15", ModelId: "9ac7da72-5224-6046-3913-c2700c486682", OptionPrice: "770", OptionType: "1", OptionTitle: "525i Smart Cruise Control" ,
         Id: "option16", ModelId: "e64d76e4-73f8-36e5-9eca-27166bcc890b", OptionPrice: "670", OptionType: "1", OptionTitle: "X5 Moonroof" ,
         Id: "option17", ModelId: "e64d76e4-73f8-36e5-9eca-27166bcc890b", OptionPrice: "450", OptionType: "0", OptionTitle: "X5 Blind Spot Detection" ,
         Id: "option18", ModelId: "b3447f56-a51b-a451-29de-26b4b3fd98e9", OptionPrice: "340", OptionType: "0", OptionTitle: "X3 Heated Seats" ,
         Id: "option19", ModelId: "9193cc24-58a8-cb8b-c7d4-f10eddb110b6", OptionPrice: "550", OptionType: "0", OptionTitle: "750Li Smart Stop System" ,
         Id: "option20", ModelId: "9193cc24-58a8-cb8b-c7d4-f10eddb110b6", OptionPrice: "870", OptionType: "0", OptionTitle: "750Li Blind Spot Detection" ,
         Id: "option21", ModelId: "e200ffba-e70c-e743-e8b5-8dd39061bd7d", OptionPrice: "230", OptionType: "0", OptionTitle: "M3 6 Cylinder Direct Injecton Engine" ,
         Id: "option22", ModelId: "e200ffba-e70c-e743-e8b5-8dd39061bd7d", OptionPrice: "450", OptionType: "1", OptionTitle: "M3 8 Speed Automatic Transmission" ,
         Id: "option23", ModelId: "e200ffba-e70c-e743-e8b5-8dd39061bd7d", OptionPrice: "650", OptionType: "0", OptionTitle: "M3 6 Speed Manual Transmission" ,
         Id: "option24", ModelId: "3d37e4b7-61be-a467-d4b9-aba784dea17b", OptionPrice: "980", OptionType: "1", OptionTitle: "M5 Automatic Moonroof" ,
    ];

**更新 2 **

这里我把所有东西都放在了 JSFiddle

https://jsfiddle.net/hhkrjus3/

【问题讨论】:

大量的代码。你能提供一个最小的例子吗?并准确说出出了什么问题? 事情是这样的。当我单击一次复选框时,可观察数组的值会发生变化,但不会反映在 DOM 上。但是当我单击其他元素时,更改会反映先前所做的更改。您可以看到小提琴来观察行为,因为我认为我的陈述令人困惑。道歉。对不起,冗长的代码:) 【参考方案1】:

我解决了。点击事件阻止了选择。我不知道为什么,但是当我删除点击事件时,它起作用了。 我选择的解决方法是:我在工厂方法中创建了一个计算标志。 如果有人能回答为什么绑定点击事件会阻止结果表单反映在 DOM 上,那将非常有帮助。

谢谢大家:)

【讨论】:

【参考方案2】:

在处理复选框时,您应该使用“checked”绑定。 http://knockoutjs.com/documentation/checked-binding.html

这可能会解决你的问题:)

编辑:我有点快在那里,我看到你一直在使用检查绑定。但是您也在使用值绑定。您应该只使用其中一个,在这种情况下检查

【讨论】:

以上是关于可观察到的数组更改不会反映在第一次点击 - KnockoutJS的主要内容,如果未能解决你的问题,请参考以下文章

从可观察到的返回数据的角度 forEach 循环(Firebase 驱动)

KnockoutJS:模板未在可观察数组更改时更新(仅在添加时,在删除时有效)

尽管可观察到的变化,但计算的可观察到的不会触发

来回更改路线后可观察到的数据消失了

状态更新没有立即反映。如何使用 useEffect 的依赖数组来显示更改?

是否可以使用ngrx加载块中的可观察更改