角度1.5组件,ui路由器解析,$ onChanges生命周期挂钩 [英] angular 1.5 component, ui-router resolve, $onChanges lifecycle hook

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

问题描述

在以下示例中( plunker ),UI路由器状态路由至一个 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:

  • 一个编辑器组件,该组件通过回调绑定('&')
  • 触发 replace 方法 通过1向绑定('<')接收 data 对象的
  • display 组件,在触发$ 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路方式接收 data 对象绑定('<'),它定义为ui-router状态的解析(从注释中可以看出,我使用全局对象和方法进行了测试,并通过服务进行了交互).重新分配此解析的对象后,我期望触发 app 组件的$ onChanges钩子(因为 display 组件的数据对象是 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来完成并非为之设计的事情,而是使用 RxJS Angular扩展.

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

然后只需订阅更改.

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上的 DEMO .

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

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