web-dev-qa-db-ja.com

ビューモデルを実行するために常にそれを使用して、Knockoutマッピングプラグインを使いすぎていませんか?

私はまだKnockoutの適切な使用法を学習しており、ビューモデルを設定するときに_ko.observable_を入力する代わりに、オブジェクトリテラルを定義してマッピングプラグインに渡すだけで、

_var viewModel = ko.mapping.fromJS(data);
_

または、少なくとも、私のデータのすべてをviewModelの属性に詰め込むようなもの

_var viewModel = { 
    ... events etc ... , 
    "data": ko.mapping.fromJS(data)
}
_

正直なところ、これを行ってきた主な理由は、_ko.observable_と_ko.observableArray_を繰り返し入力する必要を回避するためです。これが良いアプローチであるかどうか、特定のvar x = ko.observable()宣言をすべて削除することのマイナス面があるかどうかを理解しようとしています。また、私はこれをすべてのロード時に実行しています。どのajax呼び出しなどにも応答していません。これは、マッピングプラグインが設計されたものであることがわかります。

ノックアウトを使用する作業でも、オブザーバブルを1つずつ手動で宣言しますか、それとも、私が使用するmapping.fromJSメソッドを使用しましたか?このように頻繁にマッピングプラグインを使用することの特定の欠点はありますか?

編集:

具体例

この記事では 、スティーブは次のようにしてビューモデルを設定します

_var initialData = [ { ... } , { ... } ]; // json from the serializer
var viewModel = {
    gifts : ko.observableArray(initialData)
};
_

通常、この状況でも_ko.mapping.fromJS_を使用するだけで、特に配列内のオブジェクトがオブザーバブルに確実に変換されるようにします。彼の行動を見ると、私のアプローチはやり過ぎのようで、不要なオーバーヘッドが少し追加されています。

56
Allen Rice

あなたへの私の提案は、私がちょうど答えた別の質問と同じです https://stackoverflow.com/questions/7499133/mapping-deeply-hierarchical-objects-to-custom-classes-using-knockout-mapping-plug 。

マッピングプラグインを使用する理由は合理的で、私が使用しています。なぜ必要以上のコードを入力するのですか?

ノックアウトの経験(4か月すべて)で、手動で実行し、ノックアウトルーチンに任せるほど、アプリの実行が向上することがわかりました。私の提案は、最初に最も簡単なアプローチを試すことです。それがニーズを満たさない場合は、単純なアプローチがどのようにそれを実行しているかを調べ、ニーズを満たすために何を変更する必要があるかを判断します。

22
photo_tom

Knockoutをもう少し使用した後、マッピングプラグインに、マッピングプロセスをより細かく制御できるいくつかの追加オプションがあることに気付きました。

生成されるプロパティのタイプと量を制御する

これを実現する方法はいくつかありますが、いくつか説明しますが、すべてが観察可能ではないため、最終的にはマッピングプラグインからの結果が軽くなります。

基本的に、変化しないと思うすべてのものを通常のプロパティとして残し、観察したい特定の項目からのみ観察可能にします。

特定のプロパティをmappingから除外する

ignoreincludeなどを指定することにより、マッピングプラグインで最終結果からプロパティを完全に除外することができます。これらは両方とも同じことを、反対の方法で実行します。

注:サンプルは knockout.jsマッピングプラグインのドキュメント からのものであり、コメントは私が追加しました

マッピングプラグイン引数:include

次のスニペットは、include引数を介して渡されたもの以外のソースオブジェクトからすべてのプロパティを省略します。

// specify the specific properties to include as observables in the end result 
var mapping = {
    // only include these two properties
    'include': ["propertyToInclude", "alsoIncludeThis"]
}

// viewModel will now only contain the two properties listed above, 
//    and they will be observable
var viewModel = ko.mapping.fromJS(data, mapping);

マッピングプラグイン引数:ignore

ソースオブジェクトから特定のプロパティを省略のみを使用する場合は、以下に示すようにignore引数を使用します。指定されたプロパティを除いて、ソースオブジェクトのすべてのプロパティからオブザーバブルを作成します。

// specify the specific properties to omit from the result, 
//    all others will be made observable
var mapping = {
    // only ignore these two properties
    'ignore': ["propertyToIgnore", "alsoIgnoreThis"]
}

// viewModel will now omit the two properties listed above, 
//    everything else will be included and they will be an observable
var viewModel = ko.mapping.fromJS(data, mapping);

どのプロパティが監視可能かどうかを制御する

プロパティを含める必要があるが、(何らかの理由で)プロパティを監視可能にする必要がないと思われる場合は、マッピングプラグインに役立つ機能があります。

マッピングプラグイン引数:copy

マッピングプラグインでプレーンプロパティを単にコピーし、それらを監視可能にしない場合は、以下に示すように、この引数を使用します。

// tell the mapping plugin to handle all other properties normally, 
//    but to simply copy this property instead of making it observable
var mapping = {
    'copy': ["propertyToCopy"]
}
var viewModel = ko.mapping.fromJS(data, mapping);

マッピングプロセスを完全に制御

マッピングプロセスで作成されるものを100%制御したい場合は、オブジェクトにクロージャとサブスクリプションを配置する機能を含めて、「作成」オプションを使用します。

計算されたプロパティを持つ単純な結果

これは、ajax呼び出しからのデータをresultsプロパティを持つオブジェクトにマッピングした例です。観察できるものは何も欲しくなく、オブジェクトの他の単純なプロパティで構成される単純な生成プロパティが必要でした。多分最も説得力のある例ではないかもしれませんが、それは機能を実証しています。

var searchMappingConfig = {
    // specific configuration for mapping the results property
    "results": {
                    // specific function to use to create the items in the results array
        "create": function (options) {
            // return a new function so we can have the proper scope/value for "this", below
            return new function () {

                // instead of mapping like we normally would: ko.mapping.fromJS(options.data, {}, this);
                // map via extend, this will just copy the properties from the returned json element to "this"
                // we'll do this for a more light weight vm since every last property will just be a plain old property instead of observable
                $.extend(this, options.data);

                // all this to add a vehicle title to each item
                this.vehicleTitle = this.Year + "<br />" + this.Make + " " + this.Model;
                }, this);
            };
        }
    }
}

サブスクリプションとクロージャーとマッピング

別の状況として、結果に閉鎖とサブスクリプションが必要な場合があります。この例は長すぎるため、全体を含めることはできませんが、車両のメーカー/モデルの階層には当てはまります。モデルが有効化されていない場合、特定のmake(親)のすべてのモデル(子)を無効化する必要があり、サブスクリプションを使用してこれを実行する必要がありました。

// here we are specifying the way that items in the make array are created, 
//    since makes has a child array (Models), we will specify the way that 
//    items are created for that as well
var makesModelsMappingConfig = {
   // function that has the configuration for creating makes
   "create": function (options) {
      // return a new function so we can have the proper 
      //    scope/value for "this", below
      return new function () {

         // Note: we have a parent / child relationship here, makes have models. In the 
         //    UI we are selecting makes and then using that to allow the user to select 
         //    models. Because of this, there is going to be some special logic in here 
         //    so that all the child models under a given make, will automatically 
         //    unselect if the user unselects the parent make.

         // make the selected property a private variable so it can be closure'd over
         var makeIsSelected = ko.protectedComputed(false);

         // expose our property so we can bind in the UI
         this.isSelected = makeIsSelected;

         // ... misc other properties and events ...

         // now that we've described/configured how to create the makes, 
         //    describe/configure how to create the models under the makes
         ko.mapping.fromJS(options.data, {
            // specific configuration for the "Models" property                  
            "Models": {
               // function that has the configuration for creating items 
               //    under the Models property
               "create": function (model) {

                  // we'll create the isSelected as a local variable so 
                  //    that we can flip it in the subscription below, 
                  //    otherwise we wouldnt have access to flip it
                  var isSelected = ko.protectedComputed(false);

                  // subscribe to the parents "IsSelected" property so 
                  //    the models can select/unselect themselves
                  parentIsSelected.current.subscribe(function (value) {
                     // set the protected computed to the same 
                     //    value as its parent, note that this 
                     //    is just protected, not the actual value
                     isSelected(value);
                  });


                  // this object literal is what makes up each item 
                  //    in the Models observable array 
                  return {
                     // here we're returning our local variable so 
                     //    we can easily modify it in our subscription
                     "isSelected": isSelected,

                     // ... misc properties to expose 
                     //     under the item in the Model array ...

                  };
               }
            }
         }, this);
      };
   }
};

全体として、私が見つけたのは、プラグインに渡すオブジェクトの100%が必要になることはほとんどなく、監視するためにオブジェクトの100%が必要になることはほとんどないということです。マッピング構成オプションを調べて、あらゆる種類の複雑で単純なオブジェクトを作成します。アイデアは、必要なすべてのものを入手することであり、多かれ少なかれ何も入手しないことです。

58
Allen Rice

アレン、Knockout.jsを使った私の最近の学習経験はあなたのものと似ています。サーバーからの深い階層オブジェクトグラフを使用して、基本的な構造を維持する明示的なインスタンス化可能なビューモデル関数を定義しました。

各プロパティを関連するビューモデルのオブザーバブルとして明示的に定義することから始めましたが、すぐに手に負えなくなりました。また、マッピングプラグインの使用に切り替える主な理由は、グラフをサーバーに頻繁にAjaxで投稿し、永続化されたバージョンとマージしてから、多数のプロパティができるようにサーバーで検証する必要があることです。変更とコレクションが変更され、新しいインスタンスがAjaxの結果として返され、クライアントの表現と再マージする必要があります。これは非常に困難になり、マッピングプラグインは、追加/削除/更新を解決するための識別子の指定を可能にし、更新されたグラフを元のグラフに再マッピングすることで大きな時間を助けました。

また、サブビューモデルの「作成」オプションを使用することで、元のグラフの作成にも役立ちました。各ビューモデルコンストラクターで、親ビューモデルと子ビューモデルを構築するためのデータへの参照を受け取り、渡された子データから孫を作成するための追加のマッピングオプションを作成します。

この質問 で詳しく説明されているように、私が最近見つけた唯一の(わずかな)欠点は、ko.mapping.toJSONを実行するときに、あなたのプロトタイプで定義したtoJSONオーバーライドにフックしないことですプロパティをシリアル化から除外するためにモデルを表示します。その投稿でRyan Niemeyerが推奨しているように、マッピング解除で無視オプションを指定することで、これを回避することができました。

要約すると、私は間違いなくマッピングプラグインを使い続けます。 Knockout.jsルール。

4
Tom Hall

よりシンプルですが、ヘルプが充実したアドオンは knockout-data-projections になります。

現在、jsからviewmodelへのマッピングは処理していませんが、view modelからJSへのマッピングは非常にうまく処理しています。

1