1

私は Knockout の経験が豊富ですが、コンポーネントを使用するのはこれが初めてなので、明らかな何かが欠けていることを本当に望んでいます! 私の問題を説明するために、ユースケースを少し単純化しようとします。

Index という HTML および JS ファイルがあります。Index.html にはコンポーネントのデータ バインドがあり、Index.js にはko.components.register呼び出しがあります。

索引.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 に置き換えられますが (デバッグ ツールで見られるように)、この更新はブラウザーに反映されません。

基本的に、私が本当に求めているのは、バインド後にコンポーネント テンプレートのコンテンツを更新する方法はありますか?

あなたが考えるかもしれない上記を解決するオプションはテンプレートを要求することであることは知っていますが、私は上記を本当に単純化し、完全な実装ではこれを行うことができないため、なぜ HTML が API によって返されるのか.

どんな助けでも大歓迎です!現在、機能するソリューションがありますが、JSコードを構造化して機能させる方法が本当に好きではないため、上記のソリューションが理想的です。

ありがとう。

4

2 に答える 2

1

コンポーネント内でテンプレートバインディングを使用できます。

テンプレートバインドの通常の使用法は次のとおりです。

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

tmplDatatmplNameobservable の両方を作成できるため、バインドされたデータを更新したり、テンプレートを変更したりできます。はtmplName、コンテンツがテンプレートとして使用される要素の ID です。この構文を使用する場合は、 required を持つ要素が必要なidので、succes ハンドラーで jQuery などを使用して適切な を持つ新しい要素を作成しidtmplnameテンプレートのコンテンツが更新されるように を更新できます。

*これは機能しません: もう 1 つのオプションは、別の方法でテンプレート バインディングを使用することです。

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

この場合、ノードをテンプレートに直接指定できます。つまり、要素で初期化される tmplNodes オブザーバブルを作成します<h3>Loading...</h3>。次に、サーバーから受信したノードを保持するように変更します。

nodesオブザーバブルをサポートしていないため:

nodes — テンプレートとして使用する DOM ノードの配列を直接渡します。これは観測不可能な配列である必要があり、要素が現在の親から削除されることに注意してください。name に空でない値も渡した場合、このオプションは無視されます。

したがって、最初のオプションを使用する必要があります。新しい要素を作成し、それを既知の ID でドキュメント DOM に追加し、その ID をテンプレート名として使用します。デモ:

// 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>

于 2015-11-18T14:30:11.223 に答える