156

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>  
4

10 回答 10

161

只需绑定相关上下文。

$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与正确的上下文绑定。但是,我发现他的答案更清晰。

话虽如此,首先,您必须了解其背后的基本思想

更新 2:

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

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

例子

于 2014-06-06T09:48:31.230 回答
139

我通常这样做:

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)
   });
});
于 2014-08-18T07:13:51.437 回答
23

您可以使用:

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

这与您的示例一起使用JSFiddle

于 2014-06-06T09:43:39.723 回答
13

与使用“TestCtrl as test”中的“test”类似,如另一个答案中所述,您可以将“self”分配给您的范围:

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 中指定的名称(“TestCtrl as test”),并且还避免了将 .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>
于 2014-11-25T13:49:59.143 回答
12

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

$scope.$watch("$ctrl.name", (value) => {
    console.log(value)
});
于 2016-04-20T12:43:01.483 回答
2

你实际上可以传入一个函数作为 $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/

于 2016-07-01T21:08:07.330 回答
1

您可以使用$onChanges角度组件生命周期。

在此处查看文档: https ://docs.angularjs.org/guide/component 在基于组件的应用程序部分

于 2017-11-29T11:43:41.683 回答
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);
    }
  }
}
于 2016-02-05T10:41:45.057 回答
-1

注意:当 View 和 Controller 在路由中或通过指令定义对象耦合时,这不起作用。下面显示的内容仅在 HTML 中有“SomeController as SomeCtrl”时有效。就像 Mark V. 在下面的评论中指出的那样,正如他所说的那样,最好像 Bogdan 那样做。

var vm = this;在控制器的开头使用: 来消除“this”这个词。然后vm.name = 'Max';在手表上我return vm.name。我使用“vm”,就像@Bogdan 使用“self”一样。需要这个 var,无论是“vm”还是“self”,因为“this”这个词在函数内部具有不同的上下文。(所以返回 this.name 是行不通的)是的,你需要在你漂亮的“controller as”解决方案中注入 $scope 以达到 $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);
    });
}
于 2015-01-15T14:31:17.213 回答
-1

以下是在没有 $scope(和 $watch!)的情况下如何做到这一点的5 大错误 - 滥用 watch

如果您使用“controller as”语法,最好避免使用 $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);
        }
    }); 
});
于 2015-10-25T06:26:12.703 回答