4

Knockout.js を使用してゲスト リスト アプリを作成していますが、これまでのところ順調に進んでいます。ただし、ベストプラクティスの質問があります。私のアプリには、いくつかの異なるタイプのオブジェクトがあります: ゲストとその中のタグです。ゲストは複数のタグを持つことができ、タグは複数のゲストを持つことができます。アプリのさまざまなポイントで、両方の配列を個別に表示する必要があります。たとえば、すべてのゲストとそれに関連付けられたタグを表示できる「ゲスト」ビューと、すべてのタグとそれに関連付けられたゲストを表示できる「タグ」ビューがあります。現在、ゲストにタグを追加するためのコードは次のようになります。

var tag = function(opts) {
  this.guests = ko.observableArray()

  // Other tag code here...
}

var guest = function(opts) {
  this.tags = ko.observableArray()
  // Other guest code here...

  var self = this

  this.addTag = function(tag) {
    self.tags.push(tag)
    tag.guests.push(self)
  }
}

各 observableArray を個別に更新する以外に、Knockout でこの種の多対多の関係を行うためのより良い方法があるに違いないことはわかっています。これはまた、ゲストがタグを含むタグプロパティ/配列を持ち、ゲストを含むゲストプロパティ/配列を持ち、タグプロパティを持つ、一種の再帰的なアプリ構造につながります...あなたは写真を手に入れます。

現在、ViewModel 構造は次のようになっています。

- Parent Object
  - Guests ObservableArray
    - Guest Object
      - Tag Object as property of Guest
  - Tags ObservableArray
    - Tag Object
      - Guest Object as property of Tag

したがって、私の質問は 2 つあると思います: 1) 再帰的な配列を避けるために ViewModel を構造化するより良い方法はありますか? 2) タグ配列とゲスト配列の両方を個別に更新するのではなく、Knockout.js を使用して ViewModel を DRY で更新するにはどうすればよいでしょうか? ありがとう!

4

2 に答える 2

6

これを行う方法はおそらく他にもありますが、この方法では、適切なモデリングを犠牲にすることなく、重複が最小限に抑えられます。サーバーは、この形式のデータを問題なく生成できます。

ここでは、(大雑把なスタイルの)fiddleです。タグまたはゲストをクリックすると、その下の選択が更新されることに注意してください (最初のものがデフォルトで選択されています)。

基本的に、関係を ID で保存し、computed配列を使用して関連付けを表します。基本的なビューモデルは次のとおりです。

var ViewModel = function(guests, tags) {
    var self = this;
    self.guests = ko.observableArray(
        ko.utils.arrayMap(guests, function(i){ return new Guest(i); }
    ));
    self.tags= ko.observableArray(
        ko.utils.arrayMap(tags, function(i){ return new Tag(i); }
    ));

    self.selectedGuest = ko.observable(self.guests()[0]);
    self.selectedTag = ko.observable(self.tags()[0]);

    self.guestTags = ko.computed(function() {
        return ko.utils.arrayFilter(self.tags(), function(t) {
            return self.selectedGuest().tags().indexOf(t.id()) > -1;
        });        
    });

    self.tagGuests = ko.computed(function() {
        return ko.utils.arrayFilter(self.guests (), function(g) {
            return self.selectedTag().guests().indexOf(g.id()) > -1;
        });        
    });
};

アップデート

そこで、別の種類のマッピングを示すために新しいフィドルを作成しましたが、このコードは上記のビューモデルと簡単に共存できます。デモンストレーション用の唯一のセパレートです。選択を処理する代わりに、一般的なルックアップを提供するため、どのコードでもそれを使用できます。以下は、タグ (ゲストは対称) からの HTML とguestMap、viewmodel に追加された関数です。

名前がinputs になっていることに注意してください。名前を変更して、すべてのバインディングが最新の状態に保たれていることを確認できます。どう考えているか教えてください:

<div>Tags
    <ul data-bind="foreach: tags">
        <li>
            <input data-bind="value: name, valueUpdate: 'afterkeydown'" />
            </br><span>Tags</span>
            <ul data-bind="foreach: guests">
                <li><span data-bind="text: $parents[1].guestMap($data).name()"></span></li>
            </ul>
        </li>
    </ul>
</div>

self.guestMap = function(id) {
        return ko.utils.arrayFirst(self.guests(), function(g) {
            return id == g.id();
        });
    };   
于 2012-07-09T23:45:25.473 に答える
0

私は同じ種類の問題を抱えていました。関連するものを多対多に表示します。「グリッド」スタイルの表示を行い、更新メカニズムを組み込む必要がありました。

バックエンド DB にあった構造を複製することになりました。間に結合テーブルがある項目の 2 つのテーブル。3 つの配列からデータを取り出し、「結合」配列を更新し続けました。以下のテストデータと私のテストのフィドル。

var items = [{name: "T1",id: 1}, {name: "T2",id: 2}, {name: "T3",id: 3}, {name: "T4",id: 4}];
var cats = [{catname: 'C1', catid: 1}, {catname: 'C2',catid: 2}, {catname: 'C3',catid: 3}, {catname: 'C4',catid: 4}];
var catsItems = [{catid:1,itemid:2},{catid:2,itemid:1},{catid:4,itemid:2},{catid:3,itemid:4},{catid:3,itemid:1},{catid:1,itemid:3},{catid:2,itemid:4}];

テーブルフィドルに参加

この方法が大量のデータでどれほど効率的かはよくわかりませんが、必要なことは実行できました。

于 2013-04-05T17:24:43.580 に答える