アプリケーションのダウンロードと状態マネージャー
フレームワーク自体がロードされ、その依存関係とすべてのリクエストがバックグラウンドで処理されるまで、アプリケーションは非常に憂鬱に見えます。 そして、ほとんどの場合、 ng-cloakでさえも助けられません。 通常、そのような目的のために、サイトのメインコンテンツよりも大きいz-indexを持つdivが使用され、すべてのコンポーネントと状態がロードされるまでそれをオーバーラップします。 次のようになります。
<div class="loader" ng-show="loader"><div class="loader-content">Loading...</div></div>
彼のスタイルは次のとおりです。
.loader { position: fixed; width: 100%; height: 100%; z-index: 9; } .loader-content { width: 128px; height: 128px; overflow: auto; margin: auto; position: absolute; z-index: 10; top: 0; left: 0; bottom: 0; right: 0; }
AngularJSでは、ローダー変数を使用します。これは$ rootScopeに配置され、その値に応じて、divがブラウザーウィンドウで非表示または表示されます。 $ rootScopeの変数の値を絶えず変更するのはかなり不便です。同時にいくつかの操作が同時に実行される可能性があり、そのうちの1つが機能する瞬間に2番目の操作が完了しない場合があります。 この場合、ブートローダーは非表示になります。
このような場合を回避するために、すべての状態を保存するサービスを作成し、動作中の操作があるかどうかに応じて、$ rootScope.loaderの値を制御できます。 最も単純な形式では、次のように説明できます。
'use strict'; app.factory('StateManager', function StatemManager($rootScope, $log) { var stateContainer = []; return { add: function (service) { stateContainer.push(service); $rootScope.globalLoader = true; $log.log('Add service: ' + service); }, remove: function (service) { stateContainer = _.without(stateContainer, service); $log.log('Remove service: ' + service); if (stateContainer.length === 0) { $rootScope.globalLoader = false; $log.log('StateContainer is empty.'); } }, getByName: function (service) { return _.include(stateContainer, service) }, clear: function () { stateContainer.length = 0; $log.log('StateContainer clear.'); return true; } } });
この例では、アンダースコアライブラリを使用しています。 簡単に言えば、このサービスは渡されたプロセス名を配列に書き込み、要求に応じて削除します。 配列が空の場合、$ rootScope.loaderはfalseに設定されます。 そして使用例:
StateManager.add('Load_json_data'); var request = $http.get('/data.josn'); request.success(function(response) { console.log(response); StateManager.remove('Load_json_data'); });
もちろん、これは理想的なオプションではありませんが、動作原理を理解するには十分です。
イベントを受け取る
ng-clickなどによってコントローラー関数からイベントまたは要素を取得する必要がある場合があります 。 もちろん、これらの目的のためにディレクティブを使用する方が良いですが、何でも起こります。 幸いなことに、自由に使える$イベントがあります。
<ul> <li ng-repeat="name in names" ng-bind="name" ng-click="setActive($event);"></li> </ul>
$scope.names = ['John', 'Peter', 'Joe']; $scope.setActive = function (evt) { angular.element(evt.target).addClass('active'); }
この場合、リストから項目をクリックすると、クラスがアクティブになります。 実際、angle.elementはjqLiteであり、jQueryの愛好家が慣れ親しんでいるまさにそのメソッドを使用できます。
AngularJSとPHP
AngularJSの新規参入者の多くは、phpが送信されたPOST要求を処理できないことに驚いています。 彼は単にそれを見ません。 すべてが非常に簡単に説明されています。 開発者自身が言うように、AngularJSはRuby on Rails向けに設計されているため、データはphpには理解できないJSON形式でシリアル化されます。 この問題を取り除く方法を説明した優れた記事があります。 $ httpサービスをjQuery.ajaxスタイルで機能させる場合は、AngularJSアプリケーションに次のコードを含める必要があります。
Javascriptコード
angular.module('MyModule', [], function($httpProvider) { // Use x-www-form-urlencoded Content-Type $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'; // Override $http service's default transformRequest $httpProvider.defaults.transformRequest = [function(data) { /** * The workhorse; converts an object to x-www-form-urlencoded serialization. * @param {Object} obj * @return {String} */ var param = function(obj) { var query = ''; var name, value, fullSubName, subName, subValue, innerObj, i; for(name in obj) { value = obj[name]; if(value instanceof Array) { for(i=0; i<value.length; ++i) { subValue = value[i]; fullSubName = name + '[' + i + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if(value instanceof Object) { for(subName in value) { subValue = value[subName]; fullSubName = name + '[' + subName + ']'; innerObj = {}; innerObj[fullSubName] = subValue; query += param(innerObj) + '&'; } } else if(value !== undefined && value !== null) { query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&'; } } return query.length ? query.substr(0, query.length - 1) : query; }; return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data; }]; });
キャッシング($ cacheFactory)
初心者でもこのサービスを決して無視しません。 特定のルートに切り替えたときにPOSTリクエストを行い、アーティストのアルバムに関するデータを受信するコントローラーがあるとします:
var request = $http.get('/albums.json'); request.success(function (response) { $scope.albums = response; });
実際、ユーザーが別のリンクをクリックしてから戻ると、コードが再度実行され、アルバムのリクエストが再送信されます。 多くの場合、アプリケーション全体をダウンロードした後、サーバーに対して繰り返しリクエストを使用する必要はありません。 多くの状況があるかもしれません。 このために、$ cacheFactoryがあります。 最も簡単なキャッシュサービスを作成してみましょう。
app.factory('DataCache', function ($cacheFactory) { return $cacheFactory('dataCache', {}); });
コントローラーで使用します:
app.controller('AlbumsCtrl', function (DataCache) { var $scope.albums = DataCache.get('albums'); if (!$scope.albums) { var request = $http.get('/albums.json'); request.success(function (response) { DataCache.put('albums', response); $scope.albums = response; }); } });
現在、キャッシュにデータがある場合、アルバムのリクエストは実行されません。
おわりに
これらの手法は、最初の例では真実であると主張していません。 私が提案した方法以外の方法をコメントで見て喜んでいるでしょう。