本文介绍了AngularJS 1.5+ 组件不支持 Watchers,有什么解决办法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在将我的自定义指令升级到新的组件架构.我读过组件不支持观察者.这样对吗?如果是这样,您如何检测对象的变化?对于一个基本的例子,我有一个自定义组件 myBox ,它有一个子组件 game ,在 game 上有一个绑定.如果游戏组件中有更改游戏,我如何在 myBox 中显示警报消息?我知道有 rxJS 方法是否可以纯粹以角度来做到这一点?我的 JSFiddle

JavaScript

var app = angular.module('myApp', []);app.controller('mainCtrl', function($scope) {$scope.name = "托尼·丹扎";});app.component("myBox", {绑定:{},控制器:函数($element){var myBox = this;myBox.game = '魔兽世界';//如果 myBox.game 发生变化,则显示警告消息 'NAME CHANGE'},controllerAs: 'myBox',templateUrl: "/template",转置:真实})app.component("游戏", {绑定:{游戏:'='},控制器:函数($element){var 游戏 = 这个;},controllerAs: '游戏',templateUrl: "/template2"})

HTML

<script type="text/ng-template" id="/template"><div style='width:40%;border:2px solid black;background-color:yellow'>您最喜欢的游戏是:{{myBox.game}}<game game='myBox.game'></game>

<script type="text/ng-template" id="/template2"><div></br>改变游戏<textarea ng-model='game.game'></textarea>

嗨{{name}}<我的盒子></my-box></div><!--end app-->

解决方案

Writing Components without 观察者

这个答案概述了在不使用 观察者.

使用ng-change指令

在准备 AngularJs2 时,有哪些替代方法可以在不使用 watch 的情况下观察 obj 状态变化?

您可以使用 ng-change 指令对输入更改做出反应.

</textarea>

并且要将事件传播到父组件,需要将事件处理程序添加为子组件的属性.

<game game='myBox.game' game-change='myBox.gameChange($value)'></game>

JS

app.component("游戏", {绑定:{游戏:'=',gameChange: '&'},控制器:函数(){var 游戏 = 这个;game.textChange = 函数(值){game.gameChange({$value: value});});},controllerAs: '游戏',templateUrl: "/template2"});

在父组件中:

myBox.gameChange = function(newValue) {控制台日志(新值);});

这是未来的首选方法.使用 $watch 的 AngularJS 策略是不可扩展的,因为它是一种轮询策略.当 $watch 侦听器的数量达到 2000 左右时,UI 变得迟钝.Angular 2 中的策略是让框架更具反应性,避免将 $watch 放在 $scope 上.

使用 $onChanges 生命周期挂钩

版本 1.5.3 中,AngularJS 向 $compile 服务添加了 $onChanges 生命周期钩子.

来自文档:

控制器可以提供以下方法作为生命周期钩子:

  • $onChanges(changesObj) - 每当更新单向 (<) 或插值 (@) 绑定时调用.changesObj 是一个散列,其键是已更改的绑定属性的名称,值是形式为 { currentValue: ..., previousValue: ... } 的对象.使用此钩子触发组件内的更新,例如克隆绑定值以防止意外更改外部值.

——AngularJS综合指令API参考——生命周期钩子

$onChanges 钩子用于通过 < 单向绑定对组件的外部更改做出反应.ng-change 指令用于从带有 & 绑定的组件外部的 ng-model 控制器传播更改.

使用 $doCheck 生命周期挂钩

版本 1.5.8 中,AngularJS 向 $compile 服务添加了 $doCheck 生命周期钩子.

来自文档:

控制器可以提供以下方法作为生命周期钩子:

  • $doCheck() - 在摘要循环的每一轮调用.提供了检测变化并采取行动的机会.您希望为响应您检测到的更改而采取的任何操作都必须从此挂钩调用;实现这一点对 $onChanges 何时被调用没有影响.例如,如果您希望执行深度相等检查或检查 Date 对象,Angular 的更改检测器不会检测到其更改,因此不会触发 $onChanges,则此钩子可能很有用.这个钩子是不带参数调用的;如果检测到更改,则必须存储先前的值以与当前值进行比较.

——AngularJS综合指令API参考——生命周期钩子

require

的组件间通信

指令可以要求其他指令的控制器启用彼此之间的通信.这可以通过为 require 属性.对象键指定所需控制器(对象值)将在其下绑定到所需组件的控制器的属性名称.

app.component('myPane', {转置:真实,要求: {tabsCtrl: '^myTabs'},绑定:{标题: '@'},控制器:函数(){this.$onInit = function() {this.tabsCtrl.addPane(this);控制台日志(这个);};},templateUrl: 'my-pane.html'});

有关更多信息,请参阅AngularJS 开发人员指南 - 组件间通信

使用 RxJS

从服务推送值

例如,在您拥有一个保持状态的服务的情况下呢?我如何将更改推送到该服务,以及页面上的其他随机组件是否知道此类更改?最近一直在努力解决这个问题

使用 RxJS Extensions for Angular 构建服务.

<script src="//unpkg.com/angular/angular.js"></script><script src="//unpkg.com/rx/dist/rx.all.js"></script><script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);app.factory("DataService", function(rx) {var 主题 = 新 rx.Subject();var data = "初始";返回 {集:函数集(d){数据 = d;主题.onNext(d);},获取:函数获取(){返回数据;},订阅:功能(o){返回主题.订阅(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 = 函数(){订阅.处置();};});

客户端可以使用 DataService.subscribe 订阅更改,生产者可以使用 DataService.set 推送更改.

PLNKR 上的演示.

I've been upgrading my custom directives to the new component architecture. I've read that components do not support watchers. Is this correct? If so how do you detect changes on an object? For a basic example I have custom component myBox which has a child component game with a binding on the game . If there is a change game within the game component how do I show an alert message within the myBox? I understand there is rxJS method is it possible to do this purely in angular? My JSFiddle

JavaScript

var app = angular.module('myApp', []);
app.controller('mainCtrl', function($scope) {

   $scope.name = "Tony Danza";

});

app.component("myBox",  {
      bindings: {},
      controller: function($element) {
        var myBox = this;
        myBox.game = 'World Of warcraft';
        //IF myBox.game changes, show alert message 'NAME CHANGE'
      },
      controllerAs: 'myBox',
      templateUrl: "/template",
      transclude: true
})
app.component("game",  {
      bindings: {game:'='},
      controller: function($element) {
        var game = this;


      },
      controllerAs: 'game',
      templateUrl: "/template2"
})

HTML

<div ng-app="myApp" ng-controller="mainCtrl">
  <script type="text/ng-template" id="/template">
    <div style='width:40%;border:2px solid black;background-color:yellow'>
      Your Favourite game is: {{myBox.game}}
      <game game='myBox.game'></game>
    </div>
  </script>

 <script type="text/ng-template" id="/template2">
    <div>
    </br>
        Change Game
      <textarea ng-model='game.game'></textarea>
    </div>
  </script>

  Hi {{name}}
  <my-box>

  </my-box>

</div><!--end app-->
解决方案

Writing Components without Watchers

This answer outlines five techniques to use to write AngularJS 1.5 components without using watchers.


Use the ng-change Directive

You can use the ng-change directive to react to input changes.

<textarea ng-model='game.game'
          ng-change="game.textChange(game.game)">
</textarea>

And to propagate the event to a parent component, the event handler needs to be added as an attribute of the child component.

<game game='myBox.game' game-change='myBox.gameChange($value)'></game>

JS

app.component("game",  {
      bindings: {game:'=',
                 gameChange: '&'},
      controller: function() {
        var game = this;
        game.textChange = function (value) {
            game.gameChange({$value: value});
        });

      },
      controllerAs: 'game',
      templateUrl: "/template2"
});

And in the parent component:

myBox.gameChange = function(newValue) {
    console.log(newValue);
});

This is the preferred method going forward. The AngularJS strategy of using $watch is not scalable because it is a polling strategy. When the number of $watch listeners reaches around 2000, the UI gets sluggish. The strategy in Angular 2 is to make the framework more reactive and avoid placing $watch on $scope.


Use the $onChanges Life-cycle Hook

With version 1.5.3, AngularJS added the $onChanges life-cycle hook to the $compile service.

From the Docs:

The $onChanges hook is used to react to external changes into the component with < one-way bindings. The ng-change directive is used to propogate changes from the ng-model controller outside the component with & bindings.


Use the $doCheck Life-cycle Hook

With version 1.5.8, AngularJS added the $doCheck life-cycle hook to the $compile service.

From the Docs:


Intercomponent Communication with require

Directives can require the controllers of other directives to enable communication between each other. This can be achieved in a component by providing an object mapping for the require property. The object keys specify the property names under which the required controllers (object values) will be bound to the requiring component's controller.

app.component('myPane', {
  transclude: true,
  require: {
    tabsCtrl: '^myTabs'
  },
  bindings: {
    title: '@'
  },
  controller: function() {
    this.$onInit = function() {
      this.tabsCtrl.addPane(this);
      console.log(this);
    };
  },
  templateUrl: 'my-pane.html'
});

For more information, see AngularJS Developer Guide - Intercomponent Communicatation


Push Values from a Service with RxJS

Build a service with RxJS Extensions for Angular.

<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);

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

Clients can subscribe to changes with DataService.subscribe and producers can push changes with DataService.set.

The DEMO on PLNKR.

这篇关于AngularJS 1.5+ 组件不支持 Watchers,有什么解决办法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 05:02
查看更多