簡體   English   中英

當 observableArray 是其他模型的屬性時,淘汰賽不會更新 UI

[英]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 上使用 ()”。 我以前沒有注意這個事實。

  1. 我們真的可以省略 observable 的括號: ko observable

View 包含一個沒有括號的 observable :

<label>
<input type="checkbox" data-bind="checked: displayMessage" /> Display message
</label>

源代碼:

ko.applyBindings({
    displayMessage: ko.observable(false)
});
  1. 我們可以在 UI 上省略 observable 數組的括號: ko observable array

視圖包含: <ul data-bind="foreach: people"> ,而視圖模型有:

self.people = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);
  1. 我們可以省略 UI 上的括號用於 'leaf' observables 或 observables 數組。 這是您修改后的代碼示例 data-bind="if: selectedFeature"data-bind="foreach: selectedFeature().tasks">僅省略了葉子可觀察大括號。

  2. 最后,我們可以省略'父' observable 的括號嗎? 我們可以通過添加另一個 ko UI 語句(用而不是 if,示例 2)來實現。

with 綁定將根據關聯值是否為空/未定義動態添加或刪除后代元素

  1. 但是,我相信,我們不能在 UI 語句之外省略父節點的括號,因為它等於一個 javascript 語句: projectVM.selectedfeature().tasks 否則projectVM.selectedfeature.tasks將不起作用,因為 observables 沒有這樣的屬性任務。 相反,一個 observable 包含一個具有該屬性的對象,通過方括號 () 調用它來檢索該對象。 實際上,knockoutjs介紹頁面上有一個示例。 <button data-bind="enable: myItems().length < 5">Add</button>

下面的代碼使用以下事實(可以在此處找到,示例 2 ):

重要的是要了解 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM