AngularJS
AngularJSの落とし穴とトラップ
サーチ…
双方向データバインディングが機能しなくなる
次のことを覚えておいてください。
- Angularのデータバインディングは、JavaScriptのプロトタイプの継承に依存しているため、 可変シャドウイングの対象です 。
- 子スコープは、通常、プロトタイプ的に親スコープから継承します。 このルールの例外の1つは、プロトタイプ的に継承しないため、独立したスコープを持つディレクティブです。
-
ng-repeat
、ng-switch
、ng-view
、ng-if
、ng-controller
、ng-include
など、新しい子スコープを作成するディレクティブがいくつかあります。
つまり、子スコープの内部にあるプリミティブにデータを双方向でバインドしようとすると、そのようなことが期待どおりに機能しないことがあります。 次に 、AngularJS を「中断する」方法の例を示します。
この問題は、次の手順で簡単に回避できます。
- ありがとうございます。データをバインドするたびにHTMLテンプレート内
- 「ドット付き」オブジェクトへのバインディングの使用を促進するため、
controllerAs
構文を使用controllerAs
- $ parentは、子スコープではなく、親
scope
変数にアクセスするために使用できます。内部のようなng-if
、我々が使用することができng-model="$parent.foo"
..
上記の代わりにngModel
を引数で呼び出されたときにキャッシュされたモデルのバージョンを更新するgetter / setter関数にバインドするか、引数なしで呼び出されたときにモデルを返すことができます。 getter / setter関数を使用するには、 ngModal
属性を持つ要素にng-model-options="{ getterSetter: true }"
を追加し、その値を式に表示する場合はgetter関数を呼び出す必要があります(実施例 )。
例
表示:
<div ng-app="myApp" ng-controller="MainCtrl">
<input type="text" ng-model="foo" ng-model-options="{ getterSetter: true }">
<div ng-if="truthyValue">
<!-- I'm a child scope (inside ng-if), but i'm synced with changes from the outside scope -->
<input type="text" ng-model="foo">
</div>
<div>$scope.foo: {{ foo() }}</div>
</div>
コントローラ:
angular.module('myApp', []).controller('MainCtrl', ['$scope', function($scope) {
$scope.truthyValue = true;
var _foo = 'hello'; // this will be used to cache/represent the value of the 'foo' model
$scope.foo = function(val) {
// the function return the the internal '_foo' varibale when called with zero arguments,
// and update the internal `_foo` when called with an argument
return arguments.length ? (_foo = val) : _foo;
};
}]);
ベストプラクティス :Angularがコードの他の部分( 参考文献 )よりも頻繁に呼び出す可能性があるため、ゲッターを高速に保つのが最善です。
html5Modeを使用する場合の対処方法
html5Mode([mode])
を使用する場合は、次のことが必要です。
index.html
先頭に<base href="">
を付けて、アプリケーションのベースURLを指定します。base
タグは、urlリクエストを持つタグの前に来ることが重要です。それ以外の場合は、このエラーが発生する可能性があります。"Resource interpreted as stylesheet but transferred with MIME type text/html"
。例えば:<head> <meta charset="utf-8"> <title>Job Seeker</title> <base href="/"> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="/styles/main.css"> </head>
base
タグを指定したくない場合は、$locationProvider
をrequireBase:false
定義オブジェクトを$locationProvider.html5Mode()
渡すことで、base
タグを必要としないように設定します:$locationProvider.html5Mode({ enabled: true, requireBase: false });
HTML5 URLの直接読み込みをサポートするには、サーバー側のURL書き換えを有効にする必要があります。 AngularJS / Developer Guideから/ $ locationを使用する
このモードを使用するには、サーバー側でURLを書き換える必要があります。基本的には、すべてのリンクをアプリケーションのエントリポイント(例:
index.html
)に書き直す必要があります。<base>
タグを必要とすることは、アプリケーションベースであるURLの部分とアプリケーションによって処理されるべきパスとを区別することができるので、この場合にも重要です。さまざまなHTTPサーバーの実装に関するリクエスト書き換えの優れたリソースは、 ui-router FAQ - How to:html5Modeで動作するようにサーバーを構成する方法を参照してください 。たとえば、Apache
RewriteEngine on # Don't rewrite files or directories RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] # Rewrite everything else to index.html to allow html5 state links RewriteRule ^ index.html [L]
nginx
server { server_name my-app; root /path/to/app; location / { try_files $uri $uri/ /index.html; } }
エクスプレス
var express = require('express'); var app = express(); app.use('/js', express.static(__dirname + '/js')); app.use('/dist', express.static(__dirname + '/../dist')); app.use('/css', express.static(__dirname + '/css')); app.use('/partials', express.static(__dirname + '/partials')); app.all('/*', function(req, res, next) { // Just send the index.html for other files to support HTML5Mode res.sendFile('index.html', { root: __dirname }); }); app.listen(3006); //the port you want to use
AngularJSの7つの致命的な罪
以下は、AngularJSの機能の使用中に開発者がしばしば行ういくつかの間違いのリスト、いくつかの学習されたレッスンおよびそれらに対する解決策です。
1.コントローラを使ってDOMを操作する
それは合法ですが、避けなければなりません。コントローラは、依存関係を定義し、データをビューにバインドし、さらにビジネスロジックを作成する場所です。あなたは技術的にコントローラ内のDOMを操作することができますが、アプリケーションの別の部分で同じ操作または類似の操作が必要なときはいつでも、別のコントローラが必要になります。このアプローチのベストプラクティスは、すべての操作を含むディレクティブを作成し、そのディレクティブをアプリケーション全体で使用することです。したがって、コントローラはビューをそのまま残して、それは仕事です。ディレクティブでは、リンキング関数はDOMを操作する最も良い場所です。スコープと要素に完全にアクセスできるため、ディレクティブを使用すると、再利用性を利用することもできます。
link: function($scope, element, attrs) {
//The best place to manipulate DOM
}
関数内のDOM要素には、 element
パラメータ、 angular.element()
メソッド、または純粋なJavascriptなど、いくつかの方法でアクセスできます。
2.移転時のデータバインディング
AngularJSは、双方向のデータバインディングで有名です。しかし、あなたのデータがディレクティブ内で一方向に束縛されていることが時々あります。そこに止まって、AngularJSは間違っているのではないが、おそらくあなた。ディレクティブは、子スコープと分離スコープが関係しているため、少し危険です。 1つのトランジションで次の指示があるとします
<my-dir>
<my-transclusion>
</my-transclusion>
</my-dir>
私の中には、外側の範囲にあるデータにバインドされた要素がいくつかあります。
<my-dir>
<my-transclusion>
<input ng-model="name">
</my-transclusion>
</my-dir>
上記のコードは正しく動作しません。ここでは、transclusionによって子スコープが作成され、変数nameを取得できますが、この変数に加えた変更はそのまま残ります。ですから、この変数に$ parent.nameとして本当にアクセスできます。しかし、この使用法はベストプラクティスではないかもしれません。より良いアプローチは、オブジェクト内の変数を折り返すことです。たとえば、コントローラで次のように作成できます。
$scope.data = {
name: 'someName'
}
結局のところ、この変数に 'data'オブジェクトを介してアクセスし、双方向バインディングが完全に動作することを確認することができます。
<input ng-model="data.name">
結論だけでなく、アプリ全体を通して、ドット付き表記を使用することをお勧めします。
3.複数の指令をまとめて
同じ要素内に2つのディレクティブを一緒に使用するのは実際には合法です。ルールに従う限り、2つの独立したスコープは同じ要素に存在することはできません。一般に、新しいカスタムディレクティブを作成するときは、簡単なパラメータ渡しのために独立したスコープを割り当てます。ディレクティブmyDirAとmyDirBがisoletedスコープを持ち、myDirCがそうでないと仮定すると、次の要素は有効です。
<input my-dir-a my-dirc>
次の要素はコンソールエラーを引き起こします:
<input my-dir-a my-dir-b>
したがって、スコープを考慮して、指示を賢明に使用する必要があります。
4. $ emの不正使用
$ emit、$ broadcast、$ onの場合、これらは送信側 - 受信側の原理で動作します。言い換えれば、それらはコントローラ間の通信の手段です。例えば、次の行は、コントローラーAからの「someEvent」を発行し、関係するコントローラーBによって捕捉されます。
$scope.$emit('someEvent', args);
そして、次の行は 'someEvent'
$scope.$on('someEvent', function(){});
これまでのところすべてが完璧と思われます。しかし、コントローラBがまだ起動されていなければ、イベントは捕捉されないことを覚えておいてください。つまり、エミッタとレシーバの両方のコントローラを呼び出す必要があります。また、$ emitを必ず使用する必要があるかどうか分からない場合は、サービスを構築する方が良い方法と思われます。
$スコープの誤用。$ watch
$ scope。$ watchは変数の変更を監視するために使用されます。変数が変更されるたびに、このメソッドが呼び出されます。しかし、よくある間違いの1つは、$ scope内の変数を変更することです。これにより、ある時点で不一致と無限$のダイジェストループが発生します。
$scope.$watch('myCtrl.myVariable', function(newVal) {
this.myVariable++;
});
したがって、上記の関数では、myVariableとnewValに操作がないことを確認してください。
6.ビューへのメソッドのバインド
これは致命的な罪の一つです。 AngularJSには双方向バインディングがあり、何かが変更されたときはいつでも、ビューは何度も更新されます。そのため、ビューの属性にメソッドをバインドすると、そのメソッドが100回呼び出される可能性があり、デバッグ中に夢中になります。ただし、ng-click、ng-blur、ng-on-changeなど、メソッドをバインドするために構築された属性は一部しかありません。たとえば、マークアップに次のビューがあるとします。
<input ng-disabled="myCtrl.isDisabled()" ng-model="myCtrl.name">
ここでは、isDisabledメソッドを介してビューの無効状態をチェックします。コントローラmyCtrlには、以下があります。
vm.isDisabled = function(){
if(someCondition)
return true;
else
return false;
}
理論的には、正しいと思われるかもしれませんが、技術的には、メソッドが無限に実行されるため、オーバーロードが発生します。これを解決するには、変数をバインドする必要があります。あなたのコントローラには、以下の変数が存在する必要があります:
vm.isDisabled
コントローラの起動時にこの変数を再度開始することができます
if(someCondition)
vm.isDisabled = true
else
vm.isDisabled = false
条件が安定していない場合、これを別のイベントにバインドすることができます。次に、この変数をビューにバインドする必要があります。
<input ng-disabled="myCtrl.isDisabled" ng-model="myCtrl.name">
さて、ビューのすべての属性は期待どおりで、メソッドは必要なときにのみ実行されます。
7. Angularの機能を使用しない
AngularJSは、コードを単純化するだけでなく、コードをより効率的にするなど、いくつかの機能を非常に便利に提供します。これらの機能の一部を以下に示します。
- angular.forループのために(注意、あなたは "壊すことはできません"それはあなたが身体に入ることを防ぐことができますので、ここでパフォーマンスを考慮してください。)
- DOMセレクタのangular.element
- angular.copy :メインオブジェクトを変更しない場合に使用します
- フォームのバリデーションはすでに素晴らしいです。汚い、素朴な、触れた、有効な、必要なものなどを使用してください。
- Chromeデバッガーの他に、モバイル開発用のリモートデバッグも使用します。
- Batarangを使用していることを確認してください。これは、スコープを簡単に検査できる無料のChrome拡張機能です 。