[英]Knockout does not update UI when observableArray is a property of other model
我有 2 個相互連接的 observableArray。 單擊“功能”時,我嘗試顯示它的“任務”。 但是,當我單擊某個功能時,KO 不會更新 UI。 在控制台上,我可以跟蹤我的 viewModel,並且我可以看到在 selectedFeature 上成功加載的任務。 但是,UI 不會更新,甚至所有數組都定義為可觀察的。
請告訴我我在哪里失蹤?
function GetFeatures() {
var url = "/Project/GetFeatures";
$.get(url, "", function (data) {
$.each(JSON.parse(data), function (i, item) {
projectVM.features.push(new featureViewModelCreator(item, projectVM.selectedFeature));
});
});
};
function GetTasks(selectedFeature) {
var url = "/Task/GetTaskList";
$.get(url, { "FeatureId": selectedFeature.FeatureId }, function (data) {
$.each(JSON.parse(data), function (i, item) {
selectedFeature.tasks.push(new taskViewModelCreator(item, selectedFeature.selectedTask));
});
});
};
function taskViewModelCreator(data, selected) {
var self = this;
self.TaskId = data.TaskId;
self.Title = data.Name;
self.Status = data.Status.Name;
self.CreatedDate = data.CreatedDate;
self.UserCreatedFullName = data.UserCreated.FullName;
this.IsSelected = ko.computed(function () {
return selected() === self;
});
}
function featureViewModelCreator(data, selected) {
var self = this;
self.FeatureId = data.FeatureId;
self.Name = data.Name;
self.Status = data.Status.Name;
self.CreatedDate = data.CreatedDate;
self.UserCreatedFullName = data.UserCreated.FullName;
self.tasks = ko.observableArray();
this.IsSelected = ko.computed(function () {
return selected() === self;
});
self.selectedTask = ko.observable();
self.taskClicked = function (clickedTask) {
var selection = ko.utils.arrayFilter(self.model.tasks(), function (item) {
return clickedTask === item;
})[0];
self.selectedTask(selection);
}
}
function projectViewModelCreator() {
var self = this;
self.ProjectId = 1;
self.features = ko.observableArray();
self.selectedFeature = ko.observable();
self.featureClicked = function (clickedFeature) {
self.selectedFeature(clickedFeature);
GetTasks(clickedFeature);
}
}
var projectVM = new projectViewModelCreator();
ko.applyBindings(projectVM, $('.taskmanTable')[0]);
GetFeatures();
在用戶界面上
<div class="taskmanTable">
<table class="table table-hover featureList">
<thead>
<tr>
<th>Title</th>
</tr>
</thead>
<tbody data-bind="foreach: features">
<tr data-bind="click: $root.featureClicked, css: { active : IsSelected } ">
<td><span data-bind="text: Name"> </span></td>
</tr>
</tbody>
</table>
<table class="table table-hover taskList">
<thead>
<tr>
<th>Title</th>
</tr>
</thead>
<tbody data-bind="foreach: selectedFeature.tasks">
<tr>
<td><span data-bind="text:Title"></span></td>
</tr>
</tbody>
</table>
</div>
這是帶有關鍵注釋的正確版本: here 。 KO 文檔非常詳細。
您提到了一個關於 UI 代碼樣式的有趣說明:“據我所知,我們不在 UI 上使用 ()”。 我以前沒有注意這個事實。
View 包含一個沒有括號的 observable :
<label>
<input type="checkbox" data-bind="checked: displayMessage" /> Display message
</label>
源代碼:
ko.applyBindings({
displayMessage: ko.observable(false)
});
視圖包含: <ul data-bind="foreach: people">
,而視圖模型有:
self.people = ko.observableArray([
{ name: 'Bert' },
{ name: 'Charles' },
{ name: 'Denise' }
]);
我們可以省略 UI 上的括號用於 'leaf' observables 或 observables 數組。 這是您修改后的代碼示例。 data-bind="if: selectedFeature"
和data-bind="foreach: selectedFeature().tasks">
僅省略了葉子可觀察大括號。
最后,我們可以省略'父' observable 的括號嗎? 我們可以通過添加另一個 ko UI 語句(用而不是 if,示例 2)來實現。
with 綁定將根據關聯值是否為空/未定義動態添加或刪除后代元素
projectVM.selectedfeature().tasks
。 否則projectVM.selectedfeature.tasks
將不起作用,因為 observables 沒有這樣的屬性任務。 相反,一個 observable 包含一個具有該屬性的對象,通過方括號 () 調用它來檢索該對象。 實際上,knockoutjs介紹頁面上有一個示例。 <button data-bind="enable: myItems().length < 5">Add</button>
重要的是要了解 if 綁定對於使此代碼正常工作至關重要。 如果沒有它,在資本為空的“Mercury”上下文中嘗試評估 capital.cityName 時會出現錯誤。 在 JavaScript 中,不允許評估 null 或未定義值的子屬性。
function GetFeatures() { var data = { Name: "Test Feature", FeatureId: 1 } projectVM.features.push(new featureViewModelCreator(data, projectVM.selectedFeature)); }; function GetTasks(selectedFeature) { var data = { Title: "Test Feature", TaskId: 1 } selectedFeature().tasks.push(new taskViewModelCreator(data, selectedFeature().selectedTask)); }; function taskViewModelCreator(data, selected) { var self = this; self.TaskId = data.TaskId; self.Title = data.Title; // Step 3: you can omit $root declaration, I have removed it // just to show that the example will work without $root as well. // But you can define the root prefix explicitly (declaring explicit // scope may help you when you models become more complicated). // Step 4: data-bind="if: selectedFeature() statement was added // to hide the table when it is not defined, this statement also // helps us to avoid 'undefined' error. // Step 5: if the object is defined, we should referense // the observable array via -> () as well. This is the KnockoutJS // style we have to make several bugs of that kind in order // to use such syntax automatically. this.IsSelected = ko.computed(function() { return selected() === self; }); } function featureViewModelCreator(data, selected) { var self = this; self.FeatureId = data.FeatureId; self.Name = data.Name; self.tasks = ko.observableArray(); this.IsSelected = ko.computed(function() { return selected() === self; }); self.selectedTask = ko.observable(); } function projectViewModelCreator() { var self = this; self.ProjectId = 1; self.features = ko.observableArray(); self.selectedFeature = ko.observable(); self.featureClicked = function(clickedFeature) { self.selectedFeature(clickedFeature); GetTasks(self.selectedFeature); } } var projectVM = new projectViewModelCreator(); ko.applyBindings(projectVM, $('.taskmanTable')[0]); GetFeatures();
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="taskmanTable"> <table class="table table-hover featureList"> <thead> <tr> <th>Title</th> </tr> </thead> <tbody data-bind="foreach: features"> <tr data-bind="click: $root.featureClicked, css: { active : IsSelected } "> <td><span data-bind="text: Name"> </span></td> </tr> </tbody> </table> <hr/> <table data-bind="if: selectedFeature()" class="table table-hover taskList"> <thead> <tr> <th>Title</th> </tr> </thead> <tbody data-bind="foreach: selectedFeature().tasks()"><!-- $root --> <tr> <td><span data-bind="text: Title"></span></td> </tr> </tbody> </table> </div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.