angular 1.5 组件,ui-router 解析,$onChanges 生命周期钩子 [英] angular 1.5 component, ui-router resolve, $onChanges lifecycle hook

查看:20
本文介绍了angular 1.5 组件,ui-router 解析,$onChanges 生命周期钩子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下示例(plunker)中,ui-router 状态路由到一个 app 组件,它具有一个 data 对象和一个 replace 方法,该方法使用给定的值将该对象替换为一个新对象.在它的模板中,它有:

In the following example (plunker), a ui-router state routes to an app component that has a data object and a replace method that replaces this object with a new one using the given value. In its template, it has:

  • 一个 editor 组件,它通过回调绑定 ('&') 触发 replace 方法
  • display 组件通过单向绑定 ('<') 接收 data 对象,在 $onChanges 生命周期钩子被触发时制作本地副本, 并显示对象的内容
  • an editor component which triggers the replace method through a callback binding ('&')
  • a display component which receives the data object through a 1-way binding ('<'), makes a local copy when the $onChanges lifecycle hook is triggered, and displays the contents of the object

一切正常,符合预期:-)

Everything works fine and as expected :-)

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>
  `
});

我对以下第二个示例(plunker)有疑问.这是完全相同的设置,除了 app 组件不再管理 data 本身,而是通过 1-way 接收一个 data 对象绑定 ('<') 定义为 ui-router 状态的解析(从评论中可以看出,我使用全局对象和方法进行了测试,并通过服务进行交互).当这个解析的对象被重新分配时,我期待 app 组件的 $onChanges 钩子被触发(就像 display 组件的数据对象em>app 组件被重新分配),但事实并非如此.有没有人解释一下?

I have a problem with the following second example (plunker). It is the exact same setting, except that the app component no longer manages the data itself, but receives a data object through a 1-way binding ('<') that is defined as a resolve of the ui-router state (as can be seen in the comments, I tested both using a global object and method, and interacting through a service). When this resolved object is reassigned, I was expecting the $onChanges hook of the app component to be triggered (as it is for the display component when the data object of the app component is reassigned), but this is not the case. Does anyone has an explanation?

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>
  `
});

推荐答案

在幕后,UI-ROUTER 创建 HTML 并一次性绑定到 $resolve.data 在父作用域上.

Under the hood, UI-ROUTER creates HTML with a one-time binding to $resolve.data on the parent scope.

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

调用 app 组件中的 $onChanges 钩子的观察者监视父作用域的 $resolve.data 属性.它不会对隔离作用域的 $ctrl.data 属性的更改做出反应.而且由于它是一次性绑定,$onChanges 钩子仅在变量被初始化时才会被调用,而不会在后续更改时被调用.

The watcher that invokes the $onChanges hook in the app component watches the $resolve.data property of the parent scope. It does not react to changes to the $ctrl.data propery of the isolate scope. And since it is a one-time binding, the $onChanges hook gets invoked only when the variable gets initialized and not on subsequent changes.

与其试图改变 $onChange 去做一些它没有设计的事情,不如用 Angular 的 RxJS 扩展.

Instead of trying to bend $onChange to do something for which it was not designed, build a service with 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);
      }
  };
});

然后只需订阅更改即可.

Then simply subscribe to the changes.

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 上的演示.

这篇关于angular 1.5 组件,ui-router 解析,$onChanges 生命周期钩子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆