AngularJs 1.5 – 组件不支持Watchers,这是什么工作?
我一直在升级我的自定义指令到新的组件方法。我读过这个组件不支持观察者。 它是否正确? 如果是这样,你如何检测对象的变化。 对于一个基本的例子,我有自定义组件myBox,它有一个绑定在游戏上的子组件游戏。 如果游戏组件中有更改游戏,那么我怎样在myBox中显示警报消息? 我明白有rxJS方法是可以做到这一点纯粹angular度? 我的JS FIDDLE JS FIDDLE
JS
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-->
没有看守人写组件
这个答案概括了五种用来编写AngularJS 1.5组件而不使用观察者的技术。
- 使用
ng-change
指令 - 使用
$onChanges
生命周期钩子 - 使用
$doCheck
生命周期钩子 - 组件间通信与要求
- 使用RxJS从服务中推送值
使用ng-change
指令
什么alt方法可用来观察obj状态的变化而不使用手表来准备AngularJs2?
您可以使用ng-change
指令对input更改作出反应。
<textarea ng-model='game.game' ng-change="game.textChange(game.game)"> </textarea>
为了将事件传播给父组件,需要将事件处理程序添加为子组件的属性。
<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中的策略是使框架更具react native,避免将$watch
放在$scope
。
使用$onChanges
生命周期钩子
在版本1.5.3中 ,AngularJS将$onChanges
生命周期钩子添加到$compile
服务中。
从文档:
控制器可以提供以下作为生命周期钩子的方法:
- $ onChanges(changesObj) – 每当更新单向(
<
)或插值(@
)绑定时调用。changesObj
是一个散列,其键是已经改变的绑定属性的名称,值是{ currentValue: ..., previousValue: ... }
forms的对象。 使用此钩子触发组件内的更新,例如克隆绑定值以防止外部值的意外突变。– AngularJS综合指令API参考 – 生命周期钩子
$onChanges
钩子用于对具有<
单向绑定的组件进行外部更改。 ng-change
指令用于通过&
bindings传播来自ng-model
控制器外部的更改。
使用$doCheck
生命周期钩子
在1.5.8版本中 ,AngularJS将$doCheck
生命周期钩子添加到$compile
服务中。
从文档:
控制器可以提供以下作为生命周期钩子的方法:
$doCheck()
– 在摘要循环的每一回合中调用。 提供检测和应对变化的机会。 您希望采取的任何行动,以响应您检测到的变化,必须从这个钩子调用; 在调用$onChanges
时候实现这个没有任何影响。 例如,如果您希望执行深入的相等性检查,或者检查Date对象,那么对于Angular的变化检测器不会检测到的变化,因此不会触发$onChanges
,该钩子可能非常有用。 这个钩子被调用时没有参数。 如果检测到更改,则必须存储先前的值以与当前值进行比较。– AngularJS综合指令API参考 – 生命周期钩子
组件间通信与require
指令可以要求其他指令的控制器启用对方之间的通信。 这可以通过为require属性提供对象映射在组件中实现。 对象键指定所需控制器(对象值)将被绑定到需求组件的控制器的属性名称。
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开发人员指南 – 组件间通信
使用RxJS从服务中推送值
如果你有一个服务,例如持有状态的情况下。 我怎样才能将更改推送到该服务,并在页面上的其他随机组件意识到这样的变化? 近来一直在努力解决这个问题
使用RxJS Extensions for Angular构build服务。
<script src="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
推送更改。
PLNKR上的演示 。
$watch
对象在$scope
对象内是可用的,所以你需要在你的controller工厂函数中添加$scope
,然后把watcher放在variables上。
$scope.$watch(function(){ return myBox.game; }, function(newVal){ alert('Value changed to '+ newVal) });
在这里演示
注意:我知道你已经将
directive
转换为component
,去除了$scope
依赖关系,这样你就可以更接近Angular2了。 但似乎这个案件并没有被删除。
更新
基本上angular度1.5添加.component
方法绝对区分两个不同的function。 像component
一样可以执行特定的行为添加selector
,其中as directive
向DOM添加特定的行为。 指令只是.directive
DDO(指令定义对象)的包装方法。 只有你能看到的是,他们已经删除了link/compile
function,而使用.component
方法,你有能力得到angular度编译的DOM。
请使用Angular组件生命周期钩子的$onChanges
/ $doCheck
生命周期钩子,这些将在Angular 1.5.3+版本之后提供。
$ onChanges(changesObj) – 每当绑定更新时调用。 changesObj是一个散列,其键是绑定属性的名称。
$ doCheck() – 在绑定更改时,在摘要循环的每一轮中调用。 提供检测和应对变化的机会。
通过在组件中使用相同的function将确保您的代码兼容移动到Angular 2。
对于任何对我的解决scheme感兴趣的人,我最终会诉诸于RXJS Observables,当你到达Angular 2时,你将不得不使用它。这是组件之间通信的一个小工具,它让我更好地控制什么观看。
JS FIDDLE RXJS Observables
class BoxCtrl { constructor(msgService) { this.msgService = msgService this.msg = '' this.subscription = msgService.subscribe((obj) => { console.log('Subscribed') this.msg = obj }) } unsubscribe() { console.log('Unsubscribed') msgService.usubscribe(this.subscription) } } var app = angular .module('app', ['ngMaterial']) .controller('MainCtrl', ($scope, msgService) => { $scope.name = "Observer App Example"; $scope.msg = 'Message'; $scope.broadcast = function() { msgService.broadcast($scope.msg); } }) .component("box", { bindings: {}, controller: 'BoxCtrl', template: `Listener: </br> <strong>{{$ctrl.msg}}</strong></br> <md-button ng-click='$ctrl.unsubscribe()' class='md-warn'>Unsubscribe A</md-button>` }) .factory('msgService', ['$http', function($http) { var subject$ = new Rx.ReplaySubject(); return { subscribe: function(subscription) { return subject$.subscribe(subscription); }, usubscribe: function(subscription) { subscription.dispose(); }, broadcast: function(msg) { console.log('success'); subject$.onNext(msg); } } }])
根据公认的答案推荐使用ng-change
,并附带一个angular度为1.5的组件。
如果你需要看一个ng-model
和ng-change
不起作用的组件,你可以传递参数为:
使用哪个组件标记:
<my-component on-change="$ctrl.doSth()" field-value="$ctrl.valueToWatch"> </my-component>
组件js:
angular .module('myComponent') .component('myComponent', { bindings: { onChange: '&', fieldValue: '=' } });
组件标记:
<select ng-model="$ctrl.fieldValue" ng-change="$ctrl.onChange()"> </select>
可用于IE11,MutationObserver https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver 。 你需要将$元素服务注入到控制器中,这会半分离DOM /控制器分离,但是我觉得这是angularjs中的一个基本exception(即缺陷)。 由于隐藏/显示是asynchronous的,我们需要显示callback,angularjs&angular-bootstrap-tab不提供。 它还要求你知道你想观察哪个特定的DOM元素。 我使用下面的代码为angularjs控制器来触发Highcharts图表回stream显示。
const myObserver = new MutationObserver(function (mutations) { const isVisible = $element.is(':visible') // Requires jquery if (!_.isEqual(isVisible, $element._prevIsVisible)) { // Lodash if (isVisible) { $scope.$broadcast('onReflowChart') } $element._prevIsVisible = isVisible } }) myObserver.observe($element[0], { attributes: true, attributeFilter: ['class'] })