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 に答える
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 に答える
1

$onChanges Angular コンポーネントのライフサイクルを使用できます。

ここのドキュメントを参照してください: 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

$scope (および $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 に答える
-1

: ビューとコントローラーがルートまたはディレクティブ定義オブジェクトを介して結合されている場合、これは機能しません。以下に示すものは、HTML に「SomeController as SomeCtrl」がある場合にのみ機能します。以下のコメントで Mark V. が指摘しているように、また彼が言うように、Bogdan のように行う方が良いと言っています。

私は次を使用します:var vm = this;コントローラーの冒頭で、"this" という単語を邪魔にならないようにします。そしてvm.name = 'Max';時計の中で私はreturn vm.name. @Bogdanが「self」を使用するのと同じように、「vm」を使用します。この var は、「vm」であれ「self」であれ、「this」という単語が関数内で異なるコンテキストを取るため、必要です。(したがって、this.name を返すことはできません) そして、$watch に到達するには、美しい "controller as" ソリューションに $scope を挿入する必要があります。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 に答える