AngularJS 1.5+ 组件不支持 Watchers,有什么解决办法? [英] AngularJS 1.5+ Components do not support Watchers, what is the work around?
问题描述
我一直在将我的自定义指令升级到新的组件架构.我读过组件不支持观察者.这样对吗?如果是这样,您如何检测对象的变化?对于一个基本的例子,我有一个自定义组件 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
指令 - 使用
$onChanges
生命周期钩子 - 使用
$doCheck
生命周期钩子 - 组件间通信与 require
- 使用 RxJS 从服务推送值
使用ng-change
指令
<块引用>在准备 AngularJs2 时,有哪些替代方法可以在不使用 watch 的情况下观察 obj 状态变化?
您可以使用 ng-change
指令对输入更改做出反应.
并且要将事件传播到父组件,需要将事件处理程序添加为子组件的属性.
<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: ... } 形式的对象代码>.使用此钩子触发组件内的更新,例如克隆绑定值以防止意外更改外部值.
$onChanges
钩子用于通过 <
单向绑定对组件的外部更改做出反应.ng-change
指令用于从带有 &
绑定的组件外部的 ng-model
控制器传播更改.
使用 $doCheck
生命周期挂钩
在版本 1.5.8 中,AngularJS 向 $compile
服务添加了 $doCheck
生命周期钩子.
来自文档:
<块引用>控制器可以提供以下方法作为生命周期钩子:
$doCheck()
- 在摘要循环的每一轮调用.提供了检测变化并采取行动的机会.您希望为响应您检测到的更改而采取的任何操作都必须从此挂钩调用;实现这一点对$onChanges
何时被调用没有影响.例如,如果您希望执行深度相等性检查或检查 Date 对象,Angular 的更改检测器不会检测到其更改,因此不会触发$onChanges
,则此钩子可能很有用.这个钩子是不带参数调用的;如果检测到更改,则必须存储先前的值以与当前值进行比较.
<小时>
与require
的组件间通信指令可以要求其他指令的控制器启用彼此之间的通信.这可以通过为 require<提供对象映射在组件中实现/a> 属性.对象键指定所需控制器(对象值)将在其下绑定到所需组件的控制器的属性名称.
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
推送更改.
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 - Use the
$onChanges
Life-cycle Hook - Use the
$doCheck
Life-cycle Hook - Intercomponent Communication with require
- Push Values from a Service with RxJS
Use the ng-change
Directive
what alt methods available to observe obj state changes without using watch in preparation for AngularJs2?
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 controller can provide the following methods that act as life-cycle hooks:
- $onChanges(changesObj) - Called whenever one-way (
<
) or interpolation (@
) bindings are updated. ThechangesObj
is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form{ currentValue: ..., previousValue: ... }
. Use this hook to trigger updates within a component such as cloning the bound value to prevent accidental mutation of the outer value.— AngularJS Comprehensive Directive API Reference -- Life-cycle hooks
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:
The controller can provide the following methods that act as life-cycle hooks:
$doCheck()
- Called on each turn of the digest cycle. Provides an opportunity to detect and act on changes. Any actions that you wish to take in response to the changes that you detect must be invoked from this hook; implementing this has no effect on when$onChanges
is called. For example, this hook could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not be detected by Angular's change detector and thus not trigger$onChanges
. This hook is invoked with no arguments; if detecting changes, you must store the previous value(s) for comparison to the current values.— AngularJS Comprehensive Directive API Reference -- Life-cycle hooks
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
What about in a situation where you have a Service that's holding state for example. How could I push changes to that Service, and other random components on the page be aware of such a change? Been struggling with tackling this problem lately
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,有什么解决办法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!