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/compilefunction,而使用.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-modelng-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'] })