AngularJS 1.5+组件不支持Watchers,解决方法是什么?

Ka *_*ech 76 angularjs angularjs-directive angularjs-scope angularjs-components angularjs-1.5

我一直在将自定义指令升级到新的组件架构.我读过组件不支持观察者.它是否正确?如果是这样,您如何检测对象的更改?对于一个基本的例子,我有自定义组件myBox,它有一个带有游戏绑定的子组件游戏.如果游戏组件中有更改游戏,我如何在myBox中显示警告消息?我明白有rxJS方法是否有可能纯粹在棱角分明?我的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"
})
Run Code Online (Sandbox Code Playgroud)

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-->
Run Code Online (Sandbox Code Playgroud)

geo*_*awg 152

没有观察者编写组件

这个答案概述了在不使用观察者的情况下编写AngularJS 1.5组件的五种技术.


使用ng-change指令

什么alt方法可用于观察obj状态变化而不使用watch来准备AngularJs2?

您可以使用该ng-change指令来响应输入更改.

<textarea ng-model='game.game' 
          ng-change="game.textChange(game.game)">
</textarea>
Run Code Online (Sandbox Code Playgroud)

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

<game game='myBox.game' game-change='myBox.gameChange($value)'></game>
Run Code Online (Sandbox Code Playgroud)

JS

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

      },
      controllerAs: 'game',
      templateUrl: "/template2"
});
Run Code Online (Sandbox Code Playgroud)

在父组件中:

myBox.gameChange = function(newValue) {
    console.log(newValue);
});
Run Code Online (Sandbox Code Playgroud)

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


使用$onChanges生命周期钩

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

来自Docs:

控制器可以提供以下充当生命周期钩子的方法:

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

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

$onChanges钩用于与外部变化引入组分反应<单向绑定.该ng-change指令用于ng-model通过&绑定来传播来自组件外部的控制器的更改.


使用$doCheck生命周期钩

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

来自Docs:

控制器可以提供以下充当生命周期钩子的方法:

  • $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'
});
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅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>
Run Code Online (Sandbox Code Playgroud)
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);
      }
  };
});
Run Code Online (Sandbox Code Playgroud)

然后只需订阅更改.

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();
  };
});
Run Code Online (Sandbox Code Playgroud)

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

PLNKR上DEMO.


Pan*_*kar 8

$watch对象在$scope对象内部可用,因此您需要$scope在控制器工厂函数内添加,然后将观察者放在变量上.

$scope.$watch(function(){
    return myBox.game;
}, function(newVal){
   alert('Value changed to '+ newVal)
});
Run Code Online (Sandbox Code Playgroud)

在这里演示

注意:我知道你已经转换directivecomponent,删除依赖关系,$scope以便你更接近Angular2.但似乎没有因为这种情况而被删除.

更新

基本上角度1.5确实增加了.component方法jus区分两个不同的功能.像component.stands来执行特定的行为添加selector,其中directive表示向DOM添加特定行为.指令只是.directiveDDO(指令定义对象)的包装方法.只有你能看到的是,他们link/compile在使用.component你有能力获得角度编译DOM的方法时删除了函数.

使用Angular组件生命周期钩子的$onChanges/ $doChecklifecycle钩子,这些钩子将在Angular 1.5.3+版本之后可用.

$ onChanges(changesObj) - 每当更新绑定时调用.changesObj是一个哈希,其键是绑定属性的名称.

$ doCheck() - 绑定更改时,在摘要周期的每个回合调用.提供检测和处理更改的机会.

通过在组件内部使用相同的功能将确保您的代码兼容移动到Angular 2.