LoginSignup
1
0

More than 5 years have passed since last update.

Angular1 One-way binding と Two-way binding

Posted at

Angular1の.component()を使う時にbindingsでカスタムプロパティを定義することができます。その際に指定の仕方によってTwo-way bindingにするかOne-way bindingにするかを選ぶことができます。
指定の仕方の違いはbindingsオブジェクトに渡すプロパティ値を'='にするか'<'にするかの違いで、'='ならTwo-way binding、'<'ならOne-way bindingになります。

index.html
<!DOCTYPE html>
<html ng-app="App">

<head>
  <meta charset="UTF-8">
  <title>Bindings sample</title>
</head>

<body>

  <app></app>

  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
  <script src="script.js"></script>
</body>

</html>
app.html
<h1>app</h1>
Original data is : {{$ctrl.data}}
<app-child data="$ctrl.data"></app-child>
app-child.html
<h2>data is : {{$ctrl.data}}</h2>
<button ng-click="$ctrl.onClickButton()">Change data to current time</button>
script.js
angular.module('App', [])
  // <app> の定義
  .component('app', {
    templateUrl: 'app.html',
    controller: class {
      $onInit() {
        // <app> 内で data = 123 に初期化する
        this.data = 123;
      }
    }
  })
  // <app-child> の定義
  .component('appChild', {
    templateUrl: 'app-child.html',
    bindings: {
      data: '=' // Two-way binding
    },
    controller: class {
      // ボタンをクリックした時の動作。
      // <app-child> 内の data を現在時刻で上書きする。
      onClickButton() {
        this.data = Date.now();
      }
    }
  });

このシンプルなサンプルアプリでは<app>,<app-child>という二つのコンポーネントを作成し、dataという名前でデータを受け渡しています。<app-child>内のボタンクリック時に親から受け渡されて設定されているdataプロパティを変更します。
Two-way bindingを使用している場合、子コンポーネントでデータを変更すると、変更は親コンポーネントにも伝わります。

今度は試しにOne-way bindingにしてみましょう。変更するコードは一文字だけです。bindingsで渡す値を'='から'<'にします。

script.js
angular.module('App', [])
  // <app> の定義
  .component('app', {
    templateUrl: 'app.html',
    controller: class {
      $onInit() {
        // <app> 内で data = 123 に初期化する
        this.data = 123;
      }
    }
  })
  // <app-child> の定義
  .component('appChild', {
    templateUrl: 'app-child.html',
    bindings: {
      data: '<' // One-way binding
    },
    controller: class {
      // ボタンをクリックした時の動作。
      // <app-child> 内の data を現在時刻で上書きする。
      onClickButton() {
        this.data = Date.now();
      }
    }
  });

今度は子コンポーネントでdataを変更しても、親には変更が伝わらなくなりました。

注意しなければいけないのは、One-way binding と Two-way binding で動作に違いが現れるのは、バインドしているプロパティそのものに代入する時だということです。
もしバインドしているものがオブジェクトであり、子コンポーネントでそのオブジェクトのプロパティを変更するという場合には、One-way binding でも Two-way binding でも同じように動作します。

script.js
angular.module('App', [])
  .component('app', {
    templateUrl: 'app.html',
    controller: class {
      $onInit() {
        this.data = {
          count: 0
        };
      }
    }
  })
  .component('appChild', {
    templateUrl: 'app-child.html',
    bindings: {
      data: '=' // '<' にしても結果は同じ
    },
    controller: class {
      onClickButton() {
        this.data.count++;
      }
    }
  });

バインドしているのがオブジェクトである場合でも、子コンポーネントでバインドしたプロパティ自体を上書きする場合は最初の例と同じように One-way binding と Two-way binding で動作が変わります。

script.js
angular.module('App', [])
  .component('app', {
    templateUrl: 'app.html',
    controller: class {
      $onInit() {
        this.data = {
          count: 0
        };
      }
    }
  })
  .component('appChild', {
    templateUrl: 'app-child.html',
    bindings: {
      data: '=' // '<' にすると、親は変更されない
    },
    controller: class {
      onClickButton() {
        this.data = { count: this.data.count + 1 };
      }
    }
  });

なぜこのような動作になるのかわからなかった方は、JavaScriptの値渡しについて調べてみましょう。

参考: http://qiita.com/migi/items/3417c2de685c368faab1

One-way binding と Two-way binding はそれぞれ必要な場面が異なります。今書いている自分のコードではどちらを使うべきかをきちんと判断して適切に使い分けるようにしましょう。

1
0
0

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
1
0