web-dev-qa-db-ja.com

Angular.jsでモデルの状態を保存する場所

私はAngularのモデルの使用が混乱しているのを見つけています。 Angularは、モデルが好きなものにできるアプローチをとっているようです-IE Angularは明示的なモデルクラスを含まず、Vanilla JavaScriptオブジェクトをモデル。

私が見たほとんどすべてのAngularの例では、モデルは事実上、手動で作成された、またはリソースを介してAPI呼び出しから返されたオブジェクトです。ほとんどすべてのAngularの例はシンプルで、通常、コントローラーの$ scopeに保存されているモデルデータと、選択などのモデルに関連する状態もコントローラーの$ scopeに保存されます。シンプルなアプリ/例の場合、アプリがより複雑になると、これは過度に単純化されているように見えます。コントローラに保存されたモデルの状態は、例えばコンテキストが変更されるとコンテキストになり、失われるリスクがあります; selectedGalleryを保存するコントローラselectedPhotoは、ギャラリーごとにselectedImageではなく、グローバルselectedPhotoのみを保存できます。このような状況では、ギャラリーごとにコントローラーを使用すると、この問題が解消される可能性がありますが、おそらく無駄になり、おそらくUIの観点からは不適切で不要です。

Angularのモデルの定義は、サーバーとクライアント間で受け渡されるダムオブジェクトであるVO/DTOに近いと思われます。私の本能は、そのようなオブジェクトをモデルと考えるものにラップすることです-DTO/VOに関連する状態(選択など)を維持し、DTO/VOを操作するために必要に応じてミューテーターを提供し、残りを通知するクラス基になるデータへの変更の適用。明らかに、この最後の部分は、Angularのバインディングによってうまく処理されますが、最初の2つの責務の強力なユースケースがまだ見られます。

しかし、私が見た例でこのパターンが実際に使用されているのを見たことはありませんが、スケーラブルな代替案と考えられるものも見ていません。 Angularは、シングルトンを強制することにより、モデルとしてサービスを使用することを暗黙的に推奨しないようです(これを回避する方法があることは知っていますが、広く使用または承認されていないようです)。

では、モデルデータの状態をどのように維持する必要がありますか?

[編集] この質問 の2番目の答えは興味深く、現在使用しているものに近いものです。

71
Undistraction

状態(およびモデル)は$ scopeに保存されます

$ scopeは、Angularのデータストレージオブジェクトです。データベースに似ています。 $ scope自体はモデルではありませんが、モデルを$ scopeに保存できます。

各$ scopeには親$ scopeがあり、$ rootScopeまではDOMを緩やかにミラーリングするツリー構造を形成しています。 ng-controllerなど、新しい$ scopeを必要とするディレクティブを呼び出すと、新しい$ scopeオブジェクトが作成され、ツリーに追加されます。

$ scopeオブジェクトは、プロトタイプ継承を使用して接続されます。これは、ツリーの上位レベルにモデルを追加すると、すべての下位レベルで利用できることを意味します。これは、テンプレート作成者に対して$ scope階層をほとんど透過的にする、驚くほど強力な機能です。

コントローラーは$ scopeを初期化します

コントローラーの目的は$ scopeを初期化することです。同じコントローラーは、ページのさまざまな部分にある多くの$ scopeオブジェクトを初期化できます。コントローラーがインスタンス化され、$ scopeオブジェクトを設定して終了します。同じコントローラーを使用して、ページのさまざまな部分にある多くの$ scopeを初期化できます。

画像ギャラリーの場合、imageGalleryコントローラーがあり、ng-controllerディレクティブを使用して、ギャラリーにしたいDOMのすべての部分に適用します。ページのその部分は独自の$ scopeを取得し、これを使用してselectedPhoto属性を格納します。

プロトタイプスコープ

$ scopeは、$ rootScopeまでの親から単純な古いプロトタイプ継承を継承します。したがって、理にかなった階層のどこにでもオブジェクトを保存できます。現在のDOMにほぼ関連する$ scopeオブジェクトのツリーを取得します。 DOMが変更されると、必要に応じて新しい$ scopeオブジェクトが作成されます。

$ scopeは単なるJavaScriptオブジェクトです。複数のcurrentImageオブジェクトで配列を作成するよりも、複数の$ scopeオブジェクトを作成する方が無駄ではありません。これは、コードを整理する賢明な方法です。

このようにAngularはJavaScriptでよく見られる古い「データをどこに保存するか」という問題を解決します。これは、Angularから得られる非常に大きな生産性向上の源です。 。

グローバルデータ(たとえば、userId)を取得しましたか? $ rootScopeに保存します。ローカルデータ(たとえば、複数のギャラリーインスタンスがあるギャラリーのcurrentImage)を取得しましたか?そのギャラリーに属する$ scopeオブジェクトに保存します。

テンプレートの正しい部分で$ scopeが自動的に使用可能になります。

角度モデルは薄い

Railsバックグラウンドから来て、太ったモデルと細いコントローラーを強調していますが、Angularの「ほとんど存在しない」モデルは驚くべきものでした。 RailsのUserモデルで時々見られるように、注意しないと、維持できなくなるまで成長する行です。

angularモデルは、単にJavaScriptオブジェクトまたはプリミティブです。

任意のオブジェクトをモデルにすることができます。モデルは通常、コントローラーでJSONを使用して定義されるか、サーバーからAJAXされます。モデルはJSONオブジェクトの場合もあれば、単なる文字列、配列、または数値の場合もあります。

もちろん、必要に応じてモデルに関数を追加してJSONオブジェクトに保存することを止めることはできませんが、これは、Angularに実際には適合しないパラダイムに移植されます。

角度オブジェクトは通常、関数ではなくデータのリポジトリです。

フロントエンドのモデルは実際のモデルではありません

もちろん、クライアントで保持しているモデルは実際のモデルではありません。あなたの実際のモデル、あなたの唯一の真実の源はサーバーにあります。 APIを使用して同期しますが、2つの間に矛盾がある場合は、データベース内のモデルが明らかに究極の勝者です。

これにより、割引コードなどのプライバシーが確保されます。フロントエンドにあるモデルは、リモートの実際のモデルのパブリックプロパティの同期バージョンです。

ビジネスロジックはサービス内で使用できます。

たとえば、モデルに対して何かを実行したり、同期したり、検証したりするメソッドを記述したいとします。他のフレームワークでは、これを行う方法でモデルを拡張したくなるかもしれません。 Angularでは、サービスを記述する可能性が高くなります。

サービスはシングルトンオブジェクトです。他のJavaScriptオブジェクトと同様に、関数またはデータをそれらに入れることができます。 Angularには、$ httpなどの組み込みサービスが多数付属しています。独自のサービスを構築し、依存関係の注入を使用して自動的にコントローラーに提供できます。

サービスには、たとえばRESTful APIと通信したり、データやその他の必要な作業を検証したりするためのメソッドが含まれている場合があります。

サービスはモデルではありません

もちろん、サービスをモデルとして使用すべきではありません。物事を行うことができるオブジェクトとしてそれらを使用してください。時々、彼らはあなたのモデルに何かをします。それは別の考え方ですが、実行可能なものです。

28
superluminary

まず、AngularはWebベースのフレームワークであり、オブジェクトのみで「状態を維持する」場合、ユーザーがブラウザで更新を押しても生き残れないことを忘れないでください。したがって、 Webベースのアプリケーションでモデルデータの状態を維持する方法を理解するということは、コードがブラウザ環境で機能するように、データを永続化する方法を把握することを意味します。

Angularを使用すると、以下を使用して状態を永続化することが非常に簡単になります。

  1. RESTfulな$ resourceへの呼び出し
  2. モデルのインスタンスを表すURL

簡単な例では、selectedGalleryselectedPhotoなどのユーザーアクションの保存は、次のようなURLを使用して表すことができます。

// List of galleries
.../gallery

// List of photos in a gallery
.../gallery/23

// A specific photo
.../gallery/23/photo/2

ユーザーがbackおよびforwardボタンを使用してブラウザー履歴をナビゲートできるようにするため、URLは重要です。この状態をアプリケーションの他の部分と共有したい場合、Webアプリケーションは、cookie/localStorage、非表示のフレーム/フィールド、またはサーバーに保存することを実現するための豊富なメソッドを提供します。

アプリケーションのさまざまな状態を永続化する方法に関する戦略を定義したら、.serviceまたは.factoryを介したインスタンスが提供するシングルトンオブジェクトを使用して、これらの永続化情報にアクセスするかどうかを簡単に決定できるはずです。

7
marcoseu

Angularには、「モデルオブジェクト」と呼ばれるものをどのように保存するかについての意見はありません。 Angular controller _$scope_は、UIを管理するための「ビューモデル」としてのみ存在します。コード内でこれら2つの概念を分離することをお勧めします。

Angularスコープ変更通知(_$watch_))が必要な場合は、必要に応じてスコープオブジェクトを使用してモデルデータを保存できます(var myScope = $rootScope.$new()) 。UIがバインドされているのと同じスコープオブジェクトを使用しないでください。

このためにカスタムサービスを作成することをお勧めします。したがって、データフローは次のようになります。

AJAX->カスタムサービス->モデルスコープオブジェクト->コントローラー-> UIスコープオブジェクト-> DOM

またはこれ:

AJAX->カスタムサービス->プレーンな古いJavaScriptオブジェクト->コントローラー-> UIスコープオブジェクト-> DOM

1
djsmith