LoginSignup
24
24

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-11-18

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

要件

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

NGだったパターン

ファイルは4つ。

  • haml:template.html.haml
  • coffeescript:shared_number.js.coffee
  • coffee:parent_controller.js.coffee
  • coffee:child_controller.js.coffee
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}}


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

  return{
    number:{
      get: ()->
        return parseInt(number)
      set: (i)->
        number = i
        $rootScope.$broadcast('event:onSetNumber')
    }
  }
] 
parent_controller.js.coffee
App.controller "ParentController", ($scope, SharedNumberFactory) ->
  $scope.set_child_num = (num) ->
    SharedNumberFactory.number.set(num)
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
の2つ

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') //★追加
    }
  }
] 
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) //★追加

大きな変更は2つ。
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

24
24
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
24