AngularJS。 データ編成

アプリケーションが成長するにつれて、JSONオブジェクトのセットとしてデータを表示するのはあまり便利ではなくなります。 この記事では、アプリケーションでデータを扱う作業を整理する方法について説明します。



簡単な例から始めましょう。 本に関する情報を含むページを作成します。 コントローラー:



app.controller('BookController', ['$scope', function($scope) { $scope.book = { id: 1, name: 'Harry Potter', author: 'JK Rowling', stores: [ { id: 1, name: 'Barnes & Noble', quantity: 3}, { id: 2, name: 'Waterstones', quantity: 2}, { id: 3, name: 'Book Depository', quantity: 5} ] }; }]);
      
      





コントローラーは、ビューで使用されるブックモデルを初期化します。



 <div ng-controller="BookController"> Id: <span ng-bind="book.id"></span> <br/> Name:<input type="text" ng-model="book.name" /> <br/> Author: <input type="text" ng-model="book.author" /> </div>
      
      





書籍データをバックエンドサーバーから受信する必要がある場合、$ httpサービスを使用できます。



 app.controller('BookController', ['$scope', '$http', function($scope, $http) { var bookId = 1; $http.get('ourserver/books/' + bookId).success(function(bookData) { $scope.book = bookData; }); }]);
      
      





bookDataはまだJSONオブジェクトであることに注意してください。



ほとんどの場合、データを操作する必要があります。 例えば

必要なサイズに応じて、書籍を削除したり、書籍に関する情報を更新したり、カバーURLを生成したりします。 これを可能にするメソッドは、コントローラーコードで定義できます。



 app.controller('BookController', ['$scope', '$http', function($scope, $http) { var bookId = 1; $http.get('ourserver/books/' + bookId).success(function(bookData) { $scope.book = bookData; }); $scope.deleteBook = function() { $http.delete('ourserver/books/' + bookId); }; $scope.updateBook = function() { $http.put('ourserver/books/' + bookId, $scope.book); }; $scope.getBookImageUrl = function(width, height) { return 'our/image/service/' + bookId + '/width/height'; }; $scope.isAvailable = function() { if (!$scope.book.stores || $scope.book.stores.length === 0) { return false; } return $scope.book.stores.some(function(store) { return store.quantity > 0; }); }; }]);
      
      





ビューでこれらのメソッドを使用します。



 <div ng-controller="BookController"> <div ng-style="{ backgroundImage: 'url(' + getBookImageUrl(100, 100) + ')' }"></div> Id: <span ng-bind="book.id"></span> <br/> Name:<input type="text" ng-model="book.name" /> <br/> Author: <input type="text" ng-model="book.author" /> <br/> Is Available: <span ng-bind="isAvailable() ? 'Yes' : 'No' "></span> <br/> <button ng-click="deleteBook()">Delete</button> <br/> <button ng-click="updateBook()">Update</button> </div>
      
      





複数のコントローラーでモデルを使用する



メソッドとブックデータが1つのコントローラーのみで使用されている場合、ジョブは完了です。

ただし、アプリケーションが大きくなると、複数のコントローラーで1つのモデルを使用する必要が生じます。 複数のコントローラーで使用できるようにするために、ブックサービスを作成します。これは、ブックの状態と動作を記述するオブジェクトのプロトタイプです。



 app.factory('Book', ['$http', function($http) { function Book(bookData) { if (bookData) { this.setData(bookData): } //-,       }; Book.prototype = { setData: function(bookData) { angular.extend(this, bookData); }, load: function(id) { var scope = this; $http.get('ourserver/books/' + bookId).success(function(bookData) { scope.setData(bookData); }); }, delete: function() { $http.delete('ourserver/books/' + bookId); }, update: function() { $http.put('ourserver/books/' + bookId, this); }, getImageUrl: function(width, height) { return 'our/image/service/' + this.book.id + '/width/height'; }, isAvailable: function() { if (!this.book.stores || this.book.stores.length === 0) { return false; } return this.book.stores.some(function(store) { return store.quantity > 0; }); } }; return Book; }]);
      
      





コントローラーではSevris Bookを使用します。



 app.controller('BookController', ['$scope', 'Book', function($scope, Book) { $scope.book = new Book(); $scope.book.load(1); }]);
      
      





すべてのロジックがモデルに組み込まれたので、コントローラーコードに残っているのは、bookオブジェクトの作成とバックエンドサーバーからのデータの受信の2行だけです。 データがロードされると、ビューに表示され、次のようになります。



 <div ng-controller="BookController"> <div ng-style="{ backgroundImage: 'url(' + book.getImageUrl(100, 100) + ')' }"></div> Id: <span ng-bind="book.id"></span> <br/> Name:<input type="text" ng-model="book.name" /> <br/> Author: <input type="text" ng-model="book.author" /> <br/> Is Available: <span ng-bind="book.isAvailable() ? 'Yes' : 'No' "></span> <br/> <button ng-click="book.delete()">Delete</button> <br/> <button ng-click="book.update()">Update</button> </div>
      
      





そのため、Bookサービスと、書籍で動作するいくつかのコントローラーがあります。 提示されたアーキテクチャには欠点があります。 2つのコントローラーが同じ本を操作できる場合はどうなりますか?

2つのページがあるとします。1つは本のリスト、もう1つは本管理フォームです。 各ページにコントローラーが作成されます。 最初のコントローラーはサーバーのバックエンドから書籍のリストを受け取り、2番目はそれらの1つに関する情報を受け取ります。 ユーザーは2番目のページに移動し、本の名前を変更して「保存」ボタンをクリックします。 更新が成功し、書籍のタイトルが変更されます。 ただし、最初のページに移動すると、書籍のリストに古い名前が表示されます。 これは、同じ本の2つのコピーがあるためです。1つは本のリストページ用で、もう1つは本の管理ページ用です。 ユーザーは、ブック管理ページ用に作成されたインスタンスでのみ名前を変更しました。2番目のコピーは変更されませんでした。

この問題を解決するには、すべてのコントローラーがブックオブジェクトの同じインスタンスを使用する必要があります。 この場合、2番目のページで本の名前を変更すると、本に関する情報を使用して、最初のページと他のすべてのページの両方で変更されます。

ソリューションを実装するために、bookManagerサービスを作成します(サービスの名前は、相続人のいないオブジェクトになるため、大文字で書かれていません)。これは、書籍を管理し、データの受信を担当します。 要求された本がロードされていない場合、bookManagerはそれをロードします。それ以外の場合は、すでにロードされたコピーを返します。 バックエンドサーバーから書籍を受信するためのすべてのメソッドは、このデータを提供する唯一のコンポーネントである必要があるため、bookManagerサービスでのみ定義されることに注意してください。



 app.factory('booksManager', ['$http', '$q', 'Book', function($http, $q, Book) { var booksManager = { _pool: {}, _retrieveInstance: function(bookId, bookData) { var instance = this._pool[bookId]; if (instance) { instance.setData(bookData); } else { instance = new Book(bookData); this._pool[bookId] = instance; } return instance; }, _search: function(bookId) { return this._pool[bookId]; }, _load: function(bookId, deferred) { var scope = this; $http.get('ourserver/books/' + bookId) .success(function(bookData) { var book = scope._retrieveInstance(bookData.id, bookData); deferred.resolve(book); }) .error(function() { deferred.reject(); }); }, /* */ /*    */ getBook: function(bookId) { var deferred = $q.defer(); var book = this._search(bookId); if (book) { deferred.resolve(book); } else { this._load(bookId, deferred); } return deferred.promise; }, /*    */ loadAllBooks: function() { var deferred = $q.defer(); var scope = this; $http.get('ourserver/books') .success(function(booksArray) { var books = []; booksArray.forEach(function(bookData) { var book = scope._retrieveInstance(bookData.id, bookData); books.push(book); }); deferred.resolve(books); }) .error(function() { deferred.reject(); }); return deferred.promise; }, /*  */ setBook: function(bookData) { var scope = this; var book = this._search(bookData.id); if (book) { book.setData(bookData); } else { book = scope._retrieveInstance(bookData); } return book; }, }; return booksManager; }]);
      
      





提出コードは変更されません。



これで、各ブックについて1つのオブジェクトのみが保存され、このオブジェクトに対するすべての変更が、それを使用するすべてのページに表示されます。



オリジナル: www.webdeveasy.com/angularjs-data-model



All Articles