Angularjs:'控制器作为语法'和$ watch

时间:2014-06-06 09:31:33

标签: javascript angularjs angularjs-scope ng-controller

如何在使用controller as语法时订阅属性更改?

controller('TestCtrl', function ($scope) {
  this.name = 'Max';
  this.changeName = function () {
    this.name = new Date();
  }
  // not working       
  $scope.$watch("name",function(value){
    console.log(value)
  });
});
<div ng-controller="TestCtrl as test">
  <input type="text" ng-model="test.name" />
  <a ng-click="test.changeName()" href="#">Change Name</a>
</div>  

9 个答案:

答案 0 :(得分:158)

只需绑定相关的上下文。

$scope.$watch(angular.bind(this, function () {
  return this.name;
}), function (newVal) {
  console.log('Name changed to ' + newVal);
});

示例:http://jsbin.com/yinadoce/1/edit

<强>更新

Bogdan Gersak的答案实际上是等同的,两个答案都尝试用正确的上下文绑定this。但是,我发现他的答案更清晰。

说到这一点,首先,你必须理解the underlying idea behind it

更新2:

对于那些使用ES6的人,使用arrow function可以获得具有正确上下文OOTB的函数。

$scope.$watch(() => this.name, function (newVal) {
  console.log('Name changed to ' + newVal);
});

Example

答案 1 :(得分:138)

我通常这样做:

controller('TestCtrl', function ($scope) {
    var self = this;

    this.name = 'Max';
    this.changeName = function () {
        this.name = new Date();
   }

   $scope.$watch(function () {
       return self.name;
   },function(value){
        console.log(value)
   });
});

答案 2 :(得分:23)

您可以使用:

   $scope.$watch("test.name",function(value){
        console.log(value)
   });

这与您的示例有效JSFiddle

答案 3 :(得分:13)

类似于使用&#34;测试&#34;来自&#34; TestCtrl作为测试&#34;,如另一个答案所述,你可以指定&#34; self&#34;你的范围:

controller('TestCtrl', function($scope){
    var self = this;
    $scope.self = self;

    self.name = 'max';
    self.changeName = function(){
            self.name = new Date();
        }

    $scope.$watch("self.name",function(value){
            console.log(value)
        });
})

通过这种方式,您不依赖于DOM中指定的名称(&#34; TestCtrl作为测试&#34;),您还可以避免将.bind(this)用于函数。

...用于指定的原始html:

<div ng-controller="TestCtrl as test">
    <input type="text" ng-model="test.name" />
    <a ng-click="test.changeName()" href="#">Change Name</a>
</div>

答案 4 :(得分:11)

AngularJs 1.5支持ControllerAs结构的默认$ ctrl。

$scope.$watch("$ctrl.name", (value) => {
    console.log(value)
});

答案 5 :(得分:1)

你实际上可以传入一个函数作为$ watch()的第一个参数:

 app.controller('TestCtrl', function ($scope) {
 this.name = 'Max';

// hmmm, a function
 $scope.$watch(function () {}, function (value){ console.log(value) });
 });

这意味着我们可以返回this.name参考:

app.controller('TestCtrl', function ($scope) {
    this.name = 'Max';

    // boom
    $scope.$watch(angular.bind(this, function () {
    return this.name; // `this` IS the `this` above!!
    }), function (value) {
      console.log(value);
    });
});

阅读有关controllerAs主题https://toddmotto.com/digging-into-angulars-controller-as-syntax/

的有趣帖子

答案 6 :(得分:0)

在ES6语法中编写$ watch并不像我预期的那样简单。以下是您可以做的事情:

// Assuming
// controllerAs: "ctrl"
// or
// ng-controller="MyCtrl as ctrl"
export class MyCtrl {
  constructor ($scope) {
    'ngInject';
    this.foo = 10;
    // Option 1
    $scope.$watch('ctrl.foo', this.watchChanges());
    // Option 2
    $scope.$watch(() => this.foo, this.watchChanges());
  }

  watchChanges() {
    return (newValue, oldValue) => {
      console.log('new', newValue);
    }
  }
}

答案 7 :(得分:-1)

注意:当View和Controller在路由中耦合或通过指令定义对象时,这不起作用。下面显示的内容仅适用于某些&#34; SomeController为SomeCtrl&#34;在HTML中。就像Mark V.在下面的评论中指出的那样,正如他所说的那样,像波格丹那样做得更好。

我在控制器的开头使用:var vm = this;来获取单词&#34;这个&#34;别挡我的路。然后vm.name = 'Max';并在手表中return vm.name。我使用&#34; vm&#34;就像@Bogdan使用&#34; self&#34;一样。这个var,不管是&#34; vm&#34;或者&#34;自我&#34;因为&#34;这个&#34;在函数内部采用不同的上下文。 (所以返回this.name将无法正常工作)是的,你需要在美丽的控制器中注入$ scope作为&#34;解决方案,以达到$ watch。请参阅John Papa的风格指南:https://github.com/johnpapa/angularjs-styleguide#controllers

function SomeController($scope, $log) {
    var vm = this;
    vm.name = 'Max';

    $scope.$watch('vm.name', function(current, original) {
        $log.info('vm.name was %s', original);
        $log.info('vm.name is now %s', current);
    });
}

答案 8 :(得分:-1)

以下是没有$ scope(以及$ watch!)Top 5 Mistakes - Abusing watch

的方法

如果您使用“控制器为”语法,则避免使用$ scope会更好更清洁。

以下是JSFiddle中的代码。 (我使用服务来保存名称,否则ES5 Object.defineProperty的set和get方法会导致无限次调用。

var app = angular.module('my-module', []);

app.factory('testService', function() {
    var name = 'Max';

    var getName = function() {
        return name;
    }

    var setName = function(val) {
        name = val;
    }

    return {getName:getName, setName:setName};
});

app.controller('TestCtrl', function (testService) {
    var vm = this;

    vm.changeName = function () {
        vm.name = new Date();
    }

    Object.defineProperty(this, "name", {
        enumerable: true,
        configurable: false,
        get: function() {
            return testService.getName();
        },
        set: function (val) {
            testService.setName(val);
            console.log(vm.name);
        }
    }); 
});