可观察到的数组更改不会反映在第一次点击 - 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">×</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: ' ' + 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:模板未在可观察数组更改时更新(仅在添加时,在删除时有效)