1. akkun_choi

    No comment

    akkun_choi
Changes in body
Source | HTML | Preview
@@ -1,204 +1,259 @@
+## angular雑感 2014-04-30
-# $provide
+シングルページのWebアプリケーションにはとても相性が良いです。サーバー側でAPIだけ定義しておけば、$resourceで簡単にCRUDするモデルを扱うことができ、$routeProviderを使えばルーティングができます。
-http://docs.angularjs.org/api/AUTO.$provide
+ただ残念ながらこれまでのjQuery資産の9割は使えないと思います。うまくプラグイン化されていれば使うことは可能です。どうしても使いたい場合は、ディレクティブを定義して$applyを呼び出したりして、angularの世界に合わせる必要があります。
-## service, factory, provider
+学習コストは最初は低いですが、ある程度複雑なことをやろうとすると、一気に高くなります。フレームワークというのは往々にしてそういうものですね。特にDI、スコープ、ディレクティブが肝であり鬼門だと思います。
-これらは結局どれも`provider`を呼ぶことになります。
-`service`,`factory`は`provider`を楽に記述できるようにしたユーティリティ。特にserviceはCoffeeScript生成したクラスをそのまま入れることができて便利そうです。
+
+# provider, factory, serviceに関して
+
+## provider
+
+http://jsfiddle.net/akkunchoi/Dcpq2/
+
+```
+var app = angular.module('sample', []);
+
+app.provider('api', function(){
+ return {
+ $get: function(){
+ return 'api';
+ },
+ connect: function(){
+ // 処理...
+ }
+ };
+});
+app.provider('person', function(apiProvider){
+ apiProvider.connect();
+ return {
+ init: function(){
+ // 設定とか...
+ },
+ $get: function(){
+ return 'person';
+ }
+ };
+});
+
+
+// config: ここでは主にproviderの設定を行う
+// 例えば $routeProvider
+app.config(function(personProvider){
+ personProvider.init();
+ console.log(personProvider);
+});
+
+// run: $get()した結果を取得
+// 例えば $route
+app.run(function(person){
+ console.log(person);
+});
+
+```
+
+`app.config()`には`app.provider()`か`app.constant()`で登録したものしか注入できません。プロバイダーは`Provider`を付ける必要があります。
+
+`app.run()`には`app.constant()`や、プロバイダーが`$get`した戻り値であるインスタンスを注入できます。
## factory
+http://jsfiddle.net/akkunchoi/QR7FZ/
+
```javascript:
var sample = angular.module('sample', []);
// core factoryを定義
-sample.factory('core', function(){
+sample.factory('person', function(){
return {
- name: 'This is a core'
+ name: 'akkunchoi'
};
});
// 依存性注入により、上で定義したオブジェクトが入る
-sample.run(function(core){
- console.log(core.name); // => This is a core
+sample.run(function(person){
+ console.log(person.name); // => 'akkunchoi'
});
```
## service
-クラスを用意します。
+http://jsfiddle.net/akkunchoi/37LGj/
```javascript:
-var MyUser = (function(){
+var sample = angular.module('sample', []);
+
+var MyUserService = (function(){
var number = 0;
- MyUser = function(){
+ MyUserService = function(){
this.number = ++number;
- this.name = 'Thomas';
};
- MyUser.prototype.getName = function(){
- return this.name;
- }
- MyUser.prototype.getNumber = function(){
+ MyUserService.prototype.getNumber = function(){
return this.number;
- }
- return MyUser;
+ };
+ return MyUserService;
})();
-```
-
-モジュールに登録します。
-
-```javascript:
-sample.service('myUserService', MyUser);
-```
-実行します。
+sample.service('person', MyUserService);
-```javascript:
-sample.run(function(myUserService) {
- console.log(myUserService.getName(), myUserService.getNumber()); // => Thomas 1
+// 依存性注入により、上で定義したオブジェクトが入る
+sample.run(function(person){
+ console.log(person.getNumber()); // => 1
});
-sample.run(function(myUserService) {
- // 同じインスタンス
- console.log(myUserService.getName(), myUserService.getNumber()); // => Thomas 1
+sample.run(function(person){
+ console.log(person.getNumber()); // => 1
});
```
-## provider
+MyUserServiceクラスをnewした結果が、注入するオブジェクトになります。そのため、functionやプリミティブな値を注入することはできません。
-```javascript:
-sample.provider('myProvider', function(){
- return {
- $get: function(){
- return {
- name: 'This is a provider'
- }
- }
- }
-});
-sample.run(function(myProvider) {
- // ...
-});
-```
-## 依存性注入
+## constant, value, service, factory, providerの使い分け
-factory, service, providerで登録したやつ(コンポーネント)から他のコンポーネントを呼び出すことができます。
+- constant: プロバイダーに注入したい時や、configフェーズで使いたい場合。絶対不変な値。decoratorできない
+- value: factory, serviceに注入したい時や、runフェーズで使いたい場合。値が変わる可能性がある場合。
+- service: CoffeeScriptのclassで定義したものを使いたい場合
+- factory: runフェーズで注入したい場合
+- provider: インスタンス化する前にconfigフェーズで設定する必要がある場合
-```javascript:
-// 実行する度に異なるオブジェクトを生成する関数
-sample.factory('myFactory', function(core){
- var number = 0;
- return function(){
- return core.name + ' #' + ++number;
- };
-});
+`value`も`factory`も`service`も、結局は`provider`の機能制限版のようなものなので、よくわからない場合は`factory`だけ使っていれば済むと思います。
-sample.run(function(myFactory){
- console.log(myFactory()); // => This is a changed core #1
-});
-sample.run(function(myFactory){
- console.log(myFactory()); // => This is a changed core #2
-});
-sample.run(function(myFactory){
- console.log(myFactory()); // => This is a changed core #3
-});
-```
+詳細はこちら https://docs.angularjs.org/guide/providers
-## value
-```javascript:
-sample('appName', 'MyCoolApp');
-sample.run(function(appName){
- console.log(appName); // MyCoolApp
-});
-```
-# angular.module
-http://docs.angularjs.org/api/angular.module
+# angular.module
登録したモジュールは `ng-app` で指定すると実行されます。
```html:
<html ng-app="sample">
```
-別の依存モジュールを指定できます。
+`angular.module`の第二引数では依存モジュールを指定できます。実行順は依存関係の一番深いモジュールが先になります。
-例えば ng-appを main というモジュールにしたとします。
+循環した場合でも起点(ng-app)があるのでエラーは出ないです。
-```html:
-<html ng-app="main">
-```
+依存モジュールを指定した場合、注入できるのは先に読んだモジュールで定義されたproviderだけのようです。
+http://jsfiddle.net/akkunchoi/2DLKc/
-そして、mainモジュールを作成。第2引数に、依存モジュールを指定します。文字列にすると読み込み順を気にしなくていいね。
-```javascript:
-var main = angular.module('main', ['someModule', 'otherModule']);
+
+# directive
+
+## 簡単な例
+
+```html:
+<div sample-code>Content</div>
```
```javascript:
-var someModule = angular.module('someModule', ['sample']);
-someModule.run(function(core){
- console.log('SOME', core);
-});
-var otherModule = angular.module('otherModule', []);
-// sampleモジュールは指定してないけど、すでに別のモジュールで指定されていれば良いみたい
-otherModule.run(function(core){
- console.log('OTHER', core);
-
+app.directive('sampleCode', function(){
+ return function(scope, element, attrs){
+ console.log(scope, element, attrs);
+ };
+
});
```
+- scopeは[ng.$rootScope.Scope](http://docs.angularjs.org/api/ng.$rootScope.Scope)
+- elementはjQuery(またはjQuery Lite)
+- attrsは [ng.$compile.directive.Attributes](http://docs.angularjs.org/api/ng.$compile.directive.Attributes)
+属性名はコロン、アンダーバー、ハイフンで単語を区切りますが、 **directive定義する時はキャメルケースになることに注意!**
+
+## 代表的なディレクティブのオプション
+
+http://jsfiddle.net/akkunchoi/dGLUT/
+
+
+- restrict: デフォルトは'A'。以下のを指定する
+E: 要素名
+A: 属性名
+AE: 属性名、要素名
+
+- scope: {}を指定すると isolated scope を作成。ディレクティブ内での名称 => 属性名のマッピングを行う。
+
+'=' は 属性名が同じ意味
+'&' は 関数として実行可能
+'@' は 常に文字列として解釈
+
+- template: HTMLを記述する
+- templateUrl: URLを指定する
+
+- link: function link(scope, element, attrs) { ... }
+- transclude: trueにするとng-transcludeが使えるようになる。ディレクティブのDOM内部のデータが、テンプレート内で"ng-transclude"した場所に埋め込まれるようになる。
+- controller: 実行したいコントローラーを指定できる
+- require: 必須のcontrollerを指定する
+- replace: テンプレートで内容を置き換える
+
+## その他
+
+- 同じ名前のディレクティブで何度も定義できる
+- 未定義のディレクティブをテンプレートに記述してもエラーにはならない。
+- decoratorする場合は"〜Directive"
+- element.on('$destroy', ...)またはscope.$on('$destroy', …) でクリーンアップするコードを書く必要がある(??)
+
+当然なんだけど、ng-controllerもdirectiveのひとつ。内部でcontrollerオプションを指定しているだけ。
+
+# スコープ
+
+- スコープに関して http://qiita.com/akkun_choi/items/f9db1e920069a2909602
+- $applyと$digestについて http://qiita.com/akkun_choi/items/22048f31f9add7fda2c5
-# その他
## $scope event list
-- $viewContentLoaded: viewの読み込みが完了した時。jQueryMobileの`pageinit`的なやつ。以下のようにして使う。
-関連:ng-init
-
+- $viewContentLoaded: ng-viewによって中身の読み込みが完了した時に呼ばれます。jQueryMobileの`pageinit`的なもの。
+
```javascript:
$scope.$on('$viewContentLoaded', function() {
//call it here
});
```
-以下使い方不明
+- $includeContentLoaded: ng-includeによって中身の読み込みが完了した時。
+
+その他のイベント
- $locationChangeStart
- $locationChangeSuccess
- $routeUpdate
- $routeChangeStart
- $routeChangeSuccess
- $routeChangeError
- $destroy
-- $includeContentLoaded
+# その他
+
## ng-classである条件の時だけクラスをつけたい
-`selected`にbooleanが入るようして、
+http://jsfiddle.net/akkunchoi/95VJR/
+
+`flag`にbooleanが入るようして、`selected`というCSSクラスを付けたい場合
```html:
-<span ng-class="{true: 'selected'}[selected]">なんか</span>
+<span ng-class="{selected: flag]">項目</span>
```
-「もし値が設定されてなかったら」ってしたい場合、angularのexpression(上記ng-class属性の値の部分)にnullとかundefinedの概念がないので、そのまま変数を突っ込んでもダメ。`!selected`のようにboolean変換すれば良い。
+こういう書き方もできる
-## デフォルト値
+```html:
+<span ng-class="{true: 'js-selected'}[flag]">項目</span>
+```
-http://stackoverflow.com/questions/16523076/angular-template-default-value-if-binding-null-undefined-with-filter
+## デフォルト値
```html:
{{gallery.date || 'Various'}}
```