问题描述
我一直在将自定义指令升级到新的组件体系结构.我读过,组件不支持观察者.这样对吗?如果是这样,您如何检测对象的变化?对于一个基本示例,我有一个自定义组件myBox
,该组件具有一个子组件游戏,并带有游戏绑定.如果游戏组件中有找零游戏,如何在myBox中显示警告消息?我知道有rxJS方法是否可以纯粹在角度上做到这一点?我的 JSFiddle
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-->
推荐答案
没有观察者
此答案概述了用于在不使用观察者.
- 使用
ng-change
指令 - 使用
$onChanges
生命周期钩子 - 使用
$doCheck
生命周期钩子 - 与要求 的组件间通信
- 使用 RxJS 从服务中推送值
- 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
您可以使用ng-change
指令来响应输入更改.
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"
});
在父组件中:
myBox.gameChange = function(newValue) {
console.log(newValue);
});
这是以后的首选方法.使用$watch
的AngularJS策略是不可扩展的,因为它是一种轮询策略.当$watch
侦听器的数量达到2000左右时,UI会变慢. Angular 2中的策略是使框架更具响应性,并避免将$watch
放在$scope
上.
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
.
使用版本1.5.3 ,AngularJS在$compile
服务中添加了$onChanges
生命周期挂钩.
With version 1.5.3, AngularJS added the $onChanges
life-cycle hook to the $compile
service.
从文档中:
- $ onChanges(changesObj)-每当单向(
<
)或插值(@
)绑定更新时调用.changesObj
是一个哈希,其键是已更改的绑定属性的名称,而值是格式为{ currentValue: ..., previousValue: ... }
的对象.使用此挂钩可触发组件内的更新,例如克隆绑定值,以防止外部值的意外突变.
- $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.
$onChanges
钩子用于对具有<
单向绑定的组件中的外部更改做出反应. ng-change
指令用于通过&
绑定从组件外部的ng-model
控制器传播更改.
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.
在版本1.5.8 中,AngularJS在$compile
服务中添加了$doCheck
生命周期挂钩.
With version 1.5.8, AngularJS added the $doCheck
life-cycle hook to the $compile
service.
从文档中:
-
$doCheck()
-在摘要循环的每一回合调用.提供机会来检测更改并采取措施.您希望对检测到的更改做出响应的任何操作都必须从此挂钩中调用;实现此功能对$onChanges
的调用时间没有影响.例如,如果您希望执行深度相等性检查或检查Date对象,而Angular的更改检测器无法检测到该更改,因此不会触发$onChanges
,则此钩子可能很有用.该钩子不带任何参数被调用.如果检测到更改,则必须存储以前的值以便与当前值进行比较.
$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.
与require
的组件间通信指令可以要求其他指令的控制器来启用彼此之间的通信.通过在 require 属性.对象键指定属性名称,在这些属性名称下,所需的控制器(对象值)将绑定到所需组件的控制器.
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'
});
有关更多信息,请参见 AngularJS开发人员指南-组件间的通讯
For more information, see AngularJS Developer Guide - Intercomponent Communicatation
使用 RxJS 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);
}
};
});
然后只需订阅更改.
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();
};
});
客户可以使用DataService.subscribe
订阅更改,而生产者可以使用DataService.set
推送更改.
Clients can subscribe to changes with DataService.subscribe
and producers can push changes with DataService.set
.
PLNKR上的演示.
这篇关于AngularJS 1.5+组件不支持Watchers,如何解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!