4

次の例 ( plunker ) では、ui-router 状態は、データオブジェクトと、指定された値を使用してこのオブジェクトを新しいオブジェクトに置き換える replaceメソッドを持つアプリコンポーネントにルーティングされます。そのテンプレートには、次のものがあります。

  • コールバック バインディング ('&') を介して置換メソッドをトリガーするエディターコンポーネント
  • 一方向バインディング ('<') を介してデータオブジェクトを受け取り、$onChanges ライフサイクル フックがトリガーされたときにローカル コピーを作成し、オブジェクトの内容を表示する表示コンポーネント

すべてが正常に動作し、期待どおりです:-)

angular
.module('app', ['ui.router'])

.config(($urlRouterProvider, $stateProvider) => {
    $urlRouterProvider.otherwise('/');

    $stateProvider
    .state('root', {
      url: '/',
      component: 'app'
  });
})

.component('app', {
  controller: function () {
    this.data = { name: 'initial' };
    this.replace = (value) => { this.data = { name: value }; };
  },
  template: `
    <editor on-replace="$ctrl.replace(value)"></editor>
    <display data="$ctrl.data"></display>
  `
})

.component('editor', {
  bindings: {
    onReplace: '&'
  },
  controller: function () {
    this.replace = (value) => this.onReplace({value});
  },
  template: `
    <input type="text" ng-model="value">
    <button ng-click="$ctrl.replace(value)"> replace object </button>
  `
})

.component('display', {
  bindings: {
    data: '<'
  },
  controller: function () {
    this.$onChanges = (changes) => {
      if (changes.data) {
        this.data = Object.assign({}, this.data);
      }
    };
  },
  template: `
    <p> value : {{ $ctrl.data.name }} </p>
  `
});

次の 2 番目の例 ( plunker ) に問題があります。appコンポーネントがデータ自体を管理しなくなったことを除いて、まったく同じ設定ですが、ui-router 状態の解決として定義された一方向バインディング ('<') を介してデータオブジェクトを受け取ります (コメントに見られるように、グローバル オブジェクトとメソッドの使用と、サービスを介した対話の両方をテストしました)。この解決されたオブジェクトが再割り当てされると、アプリコンポーネントの $onChanges フックがトリガーされることを期待していました (アプリ コンポーネントのデータ オブジェクトが再割り当てされるときの表示コンポーネント場合と同様)。しかし、そうではありません。誰か説明がありますか?

let data = { name: 'initial' };
const replace = (value) => { data = { name: value }; };

angular
.module('app', ['ui.router'])

/*.factory('DataService', function () {
  let data = { name: 'initial' };
  return {
    getData: () => data,
    replace: (value) => { data = { name: value }; }
  };
})*/

.config(($urlRouterProvider, $stateProvider) => {
    $urlRouterProvider.otherwise('/');

    $stateProvider
    .state('root', {
      url: '/',
      component: 'app',
      resolve: {
        data: () => data /*(DataService) => DataService.getData()*/
      }
  });
})

.component('app', {
  bindings: {
    data: '<'
  },
  controller: function (/*DataService*/) {
    this.$onChanges = (changes) => {
      if (changes.data) {
        this.data = Object.assign({}, this.data);
      }
    };
    this.replace = (value) => { replace(value); }; /*(value) => { DataService.replace(value); };*/
  },
  template: `
    <editor on-replace="$ctrl.replace(value)"></editor>
    <display data="$ctrl.data"></consumer>
  `
})

.component('editor', {
  bindings: {
    onReplace: '&'
  },
  controller: function () {
    this.replace = (value) => this.onReplace({value});
  },
  template: `
    <input type="text" ng-model="value">
    <button ng-click="$ctrl.replace(value)"> replace object </button>
  `
})

.component('display', {
  bindings: {
    data: '<'
  },
  controller: function () {
    this.$onChanges = (changes) => {
      if (changes.data) {
        this.data = Object.assign({}, this.data);
      }
    };
  },
  template: `
    <p> value : {{ $ctrl.data.name }} </p>
  `
});
4

1 に答える 1

2

内部的には、親スコープにUI-ROUTER1 回限りのバインディングを持つ HTML を作成します。$resolve.data

<app data="::$resolve.data" class="ng-scope ng-isolate-scope">
  <editor on-replace="$ctrl.replace(value)" class="ng-isolate-scope">
    <input type="text" ng-model="value" class="ng-pristine ng-untouched ng-valid ng-empty">
    <button ng-click="$ctrl.replace(value)"> replace object </button>
  </editor>
  <display data="$ctrl.data" class="ng-isolate-scope">
    <p class="ng-binding"> value : initial </p>
  </display>
</app>

コンポーネントで$onChangesフックを呼び出すウォッチャーは、親スコープのプロパティを監視します。分離スコープのプロパティの変更には反応しません。また、これは 1 回限りのバインドであるため、フックは変数が初期化されたときにのみ呼び出され、その後の変更では呼び出されません。app$resolve.data$ctrl.data$onChanges


RxJZ でサービスを使用する

$onChange設計されていないことをやろうとする代わりに、 RxJS Extensions for Angularを使用してサービスを構築してください。

app.factory("DataService", function(rx) {
  var subject = new rx.Subject(); 
  var data = "Initial";

  return {
      set: function set(d){
        data = d;
        subject.onNext(d);
      },
      get: function get() {
        return data;
      },
      subscribe: function (o) {
         return subject.subscribe(o);
      }
  };
});

次に、変更を購読するだけです。

app.controller('displayCtrl', function(DataService) {
  var $ctrl = this;

  $ctrl.data = DataService.get();
  var subscription = DataService.subscribe(function onNext(d) {
      $ctrl.data = d;
  });

  this.$onDestroy = function() {
      subscription.dispose();
  };
});

PLNKRのデモ。

于 2016-07-28T20:35:01.733 に答える