簡體   English   中英

異步在Knockout組件中加載模板

[英]Async loading a template in a Knockout component

我對Knockout很有經驗,但這是我第一次使用組件,所以我真的希望我缺少一些明顯的東西! 我將嘗試簡化用例以解釋我的問題。

我有一個名為Index的HTML和JS文件。 Index.html具有組件的數據綁定,而ko.components.register具有ko.components.register調用。

的index.html

<div data-bind="component: { name: CurrentComponent }"></div>

Index.js

var vm = require("SectionViewModel");
var CurrentComponent = ko.observable("section");
ko.components.register("section", {
    viewModel: vm.SectionViewModel,
    template: "<h3>Loading...</h3>"
});
ko.applyBindings();

然后,我還有另一個HTML和JS文件-Section.html和SectionViewModel.js。 正如您在上面看到的,SectionViewModel是我指定為組件的視圖模型的對象。

Section.html

<div>
    <span data-bind="text: Section().Name"></span>
</div>

SectionViewModel.js

var SectionViewModel = (function() {
    function SectionViewModel() {
        this.Section = ko.observable();
        $.get("http://apiurl").done(function (data) {
            this.Section(new SectionModel(data.Model)); // my data used by the view model
            ko.components.get("dashboard", function() {
                component.template[0] = data.View; // my html from the api
            });
        });
    }
    return SectionViewModel;
});
exports.SectionViewModel = SectionViewModel;

作為SectionViewModel構造函數的一部分,我調用了API以獲取填充視圖模型所需的所有數據。 此API調用還會返回我需要在模板中使用的HTML(基本上是從Section.html中讀取的)。

顯然,直到我調用了applyBindings才調用此構造函數,因此當我進入API調用的成功處理程序時,組件上的模板已設置為默認文本。

我需要知道的是,我可以更新此模板嗎? 我在成功處理程序中嘗試了以下操作,如上所示:

ko.components.get("section", function(component) {
    component.template[0] = dataFromApi.Html;
});

實際上,這確實用我的API返回的html替換了我的默認文本(如調試工具中所示),但此更新未反映在瀏覽器中。

所以,基本上,我真正要問的是,是否有辦法在綁定后更新組件模板的內容?

我知道解決上述問題的一種方法,您可能會想到需要模板,但是我確實簡化了上述內容,並且在完整的實現中,我無法做到這一點,因此為什么API返回HTML 。

任何幫助,不勝感激! 目前我確實有一個可行的解決方案,但是我真的不喜歡我必須構造JS代碼以使其正常工作的方式,因此上述解決方案將是理想的選擇。

謝謝。

您可以在組件內部使用模板綁定

模板bindign的正常用法是這樣的:

<div data-bind="template: { name: tmplName, data: tmplData }"></div>

您可以使tmplDatatmplName觀察,因此您可以更新綁定的數據並更改模板。 tmplName是元素的ID,其內容將用作模板。 如果使用此語法,則需要一個具有所需id的元素,因此,在成功處理程序中,您可以使用類似jQuery的東西來創建一個具有適當id的新元素,然后更新tmplname ,以便更新模板內容。

*這將不起作用:另一個選擇是以不同的方式使用模板綁定:

<div data-bind="template: { nodes: tmplNodes, data: tmplData }"></div>

在這種情況下,您可以直接將節點提供給模板。 即,使tmplNodes成為可觀察到的,並使用您的<h3>Loading...</h3>元素對其進行初始化。 然后更改它以保存從服務器接收的節點。

因為 nodes不支持可觀察對象:

節點-直接傳遞DOM節點數組以用作模板。 這應該是一個不可觀察的數組 ,請注意,如果元素中有一個元素,則將從當前父元素中刪除它們。 如果您還為name傳遞了非空值,則將忽略此選項。

因此,您需要使用第一個選項:創建一個新元素,將其添加到具有已知ID的文檔DOM中,然后使用該ID作為模板名稱。 DEMO:

 // Simulate service that return HTML var dynTemplNumber = 0; var getHtml = function() { var deferred = $.Deferred(); var html = '<div class="c"> \\ <h3>Dynamic template ' + dynTemplNumber++ + '</h3> \\ Name: <span data-bind="text: name"/> \\ </div>'; setTimeout(deferred.resolve, 2000, html); return deferred.promise(); }; var Vm = function() { self = this; self.tmplIdx = 0; self.tmplName = ko.observable('tmplA'); self.tmplData = ko.observable({ name: 'Helmut', surname: 'Kaufmann'}); self.tmplNames = ko.observableArray(['tmplA','tmplB']); self.loading = ko.observable(false); self.createNewTemplate = function() { // simulate AJAX call to service self.loading(true); getHtml().then(function(html) { var tmplName = 'tmpl' + tmplIdx++; var $new = $('<div>'); $new.attr('id',tmplName); $new.html(html); $('#tmplContainer').append($new); self.tmplNames.push(tmplName); self.loading(false); self.tmplName(tmplName); }); }; return self; }; ko.applyBindings(Vm(), byName); 
 div.container { border: solid 1px black; margin: 20px 0;} div {padding: 5px; } .a { background-color: #FEE;} .b { background-color: #EFE;} .c { background-color: #EEF;} 
 <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 id="byName" class="container"> Select template by name: <select data-bind="{options: tmplNames, value: tmplName}"></select> <input type="button" value="Add template" data-bind="click: createNewTemplate"/> <span data-bind="visible: loading">Loading new template...</span> <div data-bind="template: {name: tmplName, data: tmplData}"></div> </div> <div id="tmplContainer" style="display:none"> <div id="tmplA"> <div class="a"> <h3>Template A</h3> <span data-bind="text: name"></span> <span data-bind="text: surname"></span> </div> </div> <div id="tmplB"> <div class="b"> <h3>Template B</h3> Name: <span data-bind="text: name"/> </div> </div> </div> 

component.template[0] = $(data)[0]

我知道這很舊,但是我發現它試圖做同樣的事情,而approcah幫助我提出了這個建議,模板似乎是一個元素,而不僅僅是原始的html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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