More Related Content
Similar to Angular js はまりどころ
Similar to Angular js はまりどころ (20)
Angular js はまりどころ
- 4. 開発対象概要
開発対象
Zac Enterprise(管理会計システム)
開発体制
日本3~4名
海外(ベトナム)1名
※将来的には、20~30名のエンジニアが開発する想定
技術構成
AngularJS + TypeScript + .NET
- 12. one-time binding
下記のように、AngularJS 1.3から使用できるone-time bindingを使うと、余計なdata-bindingを初回のみにすることができ
ます。これによって大量のリストも表示が可能になりました。
::を付けるだけ
<span>{{ ::item.title }}</span>
<span ng-bind="item.title></span>
<span>{{ ::('message' | translate) }}</span>
※angular-translateでone-time bindingを使う場合は、filterにする
- 16. スコープ
プリミティブな型のdata binding
scopeがtrue(継承)のdirective内でinputにプリミティブな型をng-modelでbindingすると、プロトタイプ継承の関係で想
定とは違う動作をすることがある。
このパターンはtitleが表示されない(myControllerで参照できない)
<body ng-controller="myController">
<div>{{ title | json }}</div>
<hoge-item>
<input type="text" ng-model="title">
</hoge-item>
</body>
これは動作する
<body ng-controller="myController">
<div>{{ obj.title | json }}</div>
<hoge-item> <!-- このディレクティブはscope=true -->
<input type="text" ng-model="obj.title">
</hoge-item>
</body>
title = "hoge" ← Set
obj.title = "hoge" ← Set
objが無い!ので上位
スコープを探索
このスコープからは参照できない
- 19. このように、scopeを指定してtranscludeすればOK
app.directive('hogeItem', function() {
return {
restrict: "EA",
template: "<div ng-transclude></div>",
transclude: true,
link: function(scope, element, attrs, ctrl, transclude) {
if (transclude) {
transclude(scope, function(clone) {
element.find('div').append(clone);
}
}
}
};
});
下記のissueで議論されていて、<div ng-transclude="parent, sibling, child"></div>で指定できるようになるかも。
https://github.com/angular/angular.js/issues/8609
- 20. ディレクティブ
input系のカスタムディレクティブを作るとき
独自に入力系ディレクティブを作る際、$viewValue, $modelValue, $renderをしっかり理解しないとはまる
たとえば、独自のselectタグのようなディレクティブを作りたい。まずは勢いとノリで実装してみる
link: function(scope, element, attrs, ngModelCtrl) {
// このinputは初期値を設定したいが、ng-repeatでelementが未生成だから遅延させよう
$timeout(function() {
ngModelCtrl.$setViewValue('initializeValue');
select(newValue);
});
// ngModelが変わったら、選択肢を変更しよう
scope.$watch("ngModel", function(newValue) {
select(newValue);
});
}
}無限に選択肢が変わる現象が発生・・・
- 22. ディレクティブ
良くあるフォームのリセットの処理をどうするか
link: function(scope, element, attrs, ngModelCtrl) {
var beforePristing;
scope.$watch(function() {
return beforePristine = ngModelCtrl.$pristine;
}, function() {
if (beforePristine == false && ngModelCtrl.$pristine) {
// リセット処理
}
};
}
こんなこともしてましたがいまいち・・・。みなさんどうしてるんでしょうか、教えてください
- 24. DI
Circular Dependency errorが発生
あるディレクティブでサービスAを使い、そこでサービスBを使ってたらそいつがサービスAを使ってた
app.directive('hogeDirective', ['serviceA', 'serviceB', function(serviceA, serviceB) {
return {
link: function() {
serviceA.method();
serviceB.method();
}
}
}]);
app.service('serviceA', ['serviceB', function(serviceB) {
this.method = function() {
alert("serviceA method!");
};
}]);
app.service('serviceB', ['serviceA', function(serviceA) {
this.method = function() {
serviceA.method();
};
});
Circular Dependency errorが発生する
https://docs.angularjs.org/error/$injector/cdep?p0=serviceA%20%3C-%20serviceB%20%3C-%20serviceA%20%3C-%20hogeInputDirective
- 25. DI
下記で解決
app.directive('hogeDirective', ['serviceA', 'serviceB', function(serviceA, serviceB) {
link: function() {
serviceA.method();
serviceB.method();
}
}]);
app.service('serviceA', ['serviceB', function(serviceB) {
this.method = function() {
alert("serviceA method!")
};
}]);
app.service('serviceB', ['$injector', function($injector) {
this.method = function() {
$injector.invoke(['serviceA', function(serviceA) {
serviceA.method();
}]);
};
}]);
$injectorサービスを使用する
- 27. angular-translate
多言語対応用のモジュール。下記の形にしておくと、各言語用の辞書データから読みだして、
表示される(動的に言語変更も簡単)
<div translate="APP_TITLE"></div>
serviceとしても使用可能だが、promiseが返ってくるのでthenが入って見づらい
app.controller("myController", ['$translate', function($translate) {
$translate("APP_TITLE").then(function(value) {
// タイトルを加工
scope.title = value;
});
});
instantを使うと値が返ってくる(読み出しが完了していることが前提)
app.controller("myController", ['$translate', function($translate) {
scope.title = $translate.instan("APP_TITLE");
});
- 29. AngularJS 1.3
isolated scope同士のdirectiveを同時に使用するとエラー
下記は、custom-buttonとtranslateでisolated scopeを使っているエラーになる
<custom-button translate="MESSAGE"></custom-button>
今回はtranslateがfilterでも使用できるので、そちらで回避
<custom-button>{{ ::('MESSAGE' | translate) }}</custom-button>
- 30. AngularJS 1.3
validationの実装方法が変更
以前は下記のような形でvalidationを実装していた("A"だけ許可する簡易なバリデーション)
ngModelCtrl.$parsers.unshift(function(viewValue) {
var valid = (value == "A") ? true : false;
ngModelCtrl.$setValidity("validA", valid);
return valid ? value : undefined;
});
この実装の場合、例えばvalidBを同時に使用していた場合、validAを評価した時点でその次のparserへの値は
undefinedになってしまうため、validBのバリデーションがうまく動作しなかった
1.3からは下記を使用する
ngModelCtrl.$validators['validA'] = function(modelValue, viewValue) {
var value = modelValue || viewValue;
return value == "A";
}