AngularJS

AngularJS1.5の scope, bindingsで指定する @=&< の仕様を見直す

More than 1 year has passed since last update.

AngularJS1.5 では、scope, bindings 指定時に @=& に加えて、< を指定できるようになった。< について追加で理解するとともに、=& を正しく理解していない側面があったため、まとめてみることにした。

$compile のドキュメントを参考にしました。

というわけでテスト書いて動作を試してみる。せっかくなので、AngularJS1.5から出たComponentを使う。

const app = angular.module('myApp', []);

class Widget {
  constructor() {
    this.name = 'Soba';
  }

  changeName() {
    if (this.name == 'Soba') {
        this.name = 'Udon';
    } else {
        this.name = 'Soba';
    }
  }
}

app.component('widget', {
    template: '<div>Hello world, {{$ctrl.name}}</div>'+
  '<button ng-click="$ctrl.changeName()">Change Name</button>'+
  '<child-widget name-at="Hi, {{$ctrl.name}}" name-eq="$ctrl.name" name-gt="$ctrl.name"></child-widget>',
    controller: Widget
});

class ChildWidget {
    changeNameAt() {
    this.nameAt = 'Yakisoba';
  }

  changeNameEq() {
    this.nameEq = 'Yakisoba';
  }

  changeNameGt() {
    this.nameGt = 'Yakisoba';
  }
}

app.component('childWidget', {
    controller: ChildWidget,
  template: '<div>@ {{$ctrl.nameAt}}</div>' + 
  '<div>= {{$ctrl.nameEq}}</div>' +
  '<div>&gt; {{$ctrl.nameGt}}</div>' + 
  '<button ng-click="$ctrl.changeNameAt()">Change nameAt</button>' +
  '<button ng-click="$ctrl.changeNameEq()">Change nameEq</button>' +
  '<button ng-click="$ctrl.changeNameGt()">Change nameGt</button>',
  bindings: {
    'nameAt': '@',
    'nameEq': '=',
    'nameGt': '<'
  }
});

以下でテスト可能
https://jsfiddle.net/kawahara/we8k5x3f/4/

@

  • @ は、DOM属性に渡した情報が文字列として渡る
  • 内容については、HTMLと同じく $parse を通して解釈される。 name に Kawahara が入っていた場合 Hi, {{name}} とした時は、Hi, Kawahara が渡る。 name が別のものに変わった場合は別の文字に更新される。
  • $parse の必要のない固定の文字情報だったら、$attrs から情報取得したほうがいいのかな。

=

  • 双方向データバインディング
  • 親スコープからの変更は子スコープに伝搬され、子スコープの変更は親スコープに伝搬させる関係になる。

=?

  • 双方向なので、親スコープが情報なしの状態で、子スコープ側で変更が加わると、通常はエラーが発生するようになっている。? を指定すると、データを親から渡す挙動がオプションとなる。(エラーが抑制される。)

=*

  • 通常ではオブジェクトの変更トラッキングには、$watch を使っているが、 $watchCollection を使うような挙動に変わる。
  • 前述の ? と併用する場合は =?* のような書き方となる。
  • 正直、使いどころがよくわからん。。誰か教えて下さい。 https://teratail.com/questions/30528

<

  • 1.5から新しく追加された 単方向データバインディング (原文ではone-way bindingと記されている) と言われるもの。
  • 親スコープからの変更は子スコープに伝搬させるが、子スコープの変更は親スコープに伝搬させない特性を持っている。

<?

  • =? の単方向データバインディングバージョン。
  • ? 指定なし、親からのデータ渡しなしの状態で、子スコープの値を変更をしても、= のようにエラーはおきたりなどはしない。
  • コード見る限りは、余計な処理が走らなくなるので、親から値を渡さないことがあるのであれば、ぜひ指定しておくべき。

&

  • 子スコープには、&で指定した式を実行するための関数が渡る。
  • 実行可能な式を書けばいいので $ctrl.flag = true のような情報を渡す式を書いてもよい。
  • 親スコープ上で doSomething(data) を指定したときに、子スコープ上で doSomething({data: 'aaa'}) 実行すると、doSomething('aaa') が実行される。