[AngularJS] 複数Contoller間で、Service,$rootScope,$emitを利用して変数を共有した時のメモ

angularは変数の共有がなかなか慣れるまで面倒くさい。
詰まったポイントをメモします。

# 要件

- 異なるコントローラー間で変数を受け渡したい
   - そのために変数共有用のgetter/setterを実装したserviceを作成
   - serviceを通して変数を共有する

# NGだったパターン

ファイルは４つ。

- haml:template.html.haml
- coffeescript:shared_number.js.coffee
- coffee:parent_controller.js.coffee
- coffee:child_controller.js.coffee 

```haml:template.html.haml

-# SET-NUMBERをクリックすると、直下のdivのchild_numに番号が表示されることを期待
%div( ng-controller='ParentController')
  %a( ng-click='set_child_num(69)' ) SET-NUMBER!
  %div( ng-controller='ChildController')
    {{child_num}}


```

```coffeescript:shared_number.js.coffee
App.factory 'SharedNumberFactory', ['$rootScope', ($rootScope) ->
  number = ''

  return{
    number:{
      get: ()->
        return parseInt(number)
      set: (i)->
        number = i
        $rootScope.$broadcast('event:onSetNumber')
    }
  }
] 
```

```coffee:parent_controller.js.coffee
App.controller "ParentController", ($scope, SharedNumberFactory) ->
  $scope.set_child_num = (num) ->
    SharedNumberFactory.number.set(num)
```

```coffee:child_controller.js.coffee                                                                                                                                                                                                                                              
App.controller "ChildController", ($scope, SharedNumberFactory) ->
  $scope.$on('event:onSetNumber', () ->
    $scope.child_num = SharedNumberFactory.number.get()
    console.log 'set child_num'
```


と記述した。

イメージしたプロセスは以下のとおり

- 1.ParentControllerのset_child_num をng-clickで実行。
  - SharedNumberFactory内のset(num)で、SharedNumberFactoryに番号をセット。
- 2.SharedNumberFactoryで番号をsetし、'event:onSetNumber'リスナーを登録しているオブジェクトに波及させる
- 3.ChildControllerには'event:onSetNumber'が登録されているので、その内部が実行され、child_numに数字が登録される

だが、
> 2.SharedNumberFactoryで番号をsetし、'event:onSetNumber'リスナーを登録しているオブジェクトに波及させる
が実行されない。


どうやらリスナーとして、ChildControllerに'event:onSetNumber'が登録されていない模様。

Factoryの`$broadcast`を実行する前に、
どういうわけか、
lisnerとして'event:onSetNumber'が登録されていないのが原因の模様。

たとえば、Factoryやserviceを使わずとも
親controllerに`$broadcast`を実行し、子controllerで$onを登録しているだけのパターンでも
その減少が起こりうる場合があるとのこと。


# OKパターン

> (参考) [AngularJS]コントローラ間のイベント通知では$broadcastが使えない場合がある
> http://d.hatena.ne.jp/Kazzz/20140809/p1 

上記アドレスを参考に下記のようなコードに書き換えた。
書き換えたファイルは
- coffee:shared_number.js.coffee
- coffee:child_controller.js.coffee 
の２つ

```coffeescript:shared_number.js.coffee
App.factory 'SharedNumberFactory', ['$rootScope', ($rootScope) ->
  number = ''

  return{
    number:{
      get: ()->
        return parseInt(number)
      set: (i)->
        number = i
        $rootScope.$on 'event:onControllerLoaded', () -> 
          $rootScope.$broadcast('event:onSetNumber') //★追加
    }
  }
] 
```

```coffee:child_controller.js.coffee                                                                                                                                                                                                                                              
App.controller "ChildController", ($scope, SharedNumberFactory) ->
  $scope.$on('event:onSetNumber', () ->
    $scope.child_num = SharedNumberFactory.number.get()
    console.log 'set child_num'
  $scope.$emit('event:onControllerLoaded', this) //★追加
```

大きな変更は２つ。
ChildControllerが読み出されたタイミングで`$emit()`を利用して、
- `$scope`に登録されているリスナー'event:onControllerLoaded'に自身の存在を告知。
- その中に`$broadcast()`メソッドを登録する

これでFactory/Serviceや親コントローラに自身の存在を登録させる事ができる。


# 参考

> [AngularJS]コントローラ間のイベント通知では$broadcastが使えない場合がある
> http://d.hatena.ne.jp/Kazzz/20140809/p1 


> Angular JS で複数のコントローラ間でモデル（状態や値）を共有する方法 3 種類
> http://qiita.com/sunny4381/items/aeae1e154346b5cf6009