Odinn
Odinn

Reputation: 1106

Angular watch doesn't work with controllerAs syntax

Have a problem with watching response.

I have a SettingsCtrl as settings and this is my view:

<input  type="text" class="form-control" ng-model="settings.test.one"  />
<input  type="text" class="form-control" ng-model="settings.test.second"  />

And this is my Controller:

app.controller('SettingsCtrl', function ($scope, settingsFactory, Test) {
  
  var vm = this;
  
  
  settingsFactory.test().then(function(response){
  
     vm.test = response;
  })
  
  /////  OR
  
  vm.test = Test; // this is from ui-router resolve
  
  
    $scope.$watch(angular.bind('vm', function () {
    return vm.test;
    }), function (newV, oldV) {
    console.log(newV, oldV); 
    });
  
    $scope.$watch(function watch(scope){
     return vm.test;
    }), function handle(newV, oldV) {
    console.log(newV, oldV);
    });
  
    $scope.$watch('vm', function (newVal, oldVal) {
        console.log('newVal, oldVal', newVal, oldVal);
    });
  
  });

I've been searching and have found different solutions, but non of them works.

**** It's watch only first time, when controller is loaded and I see my console logs, but when I try to make changes watchers do nothing.

What I'm doing wrong?

Upvotes: 1

Views: 3104

Answers (5)

Remus.A
Remus.A

Reputation: 102

What worked for me after referring to a github post (https://github.com/johnpapa/angular-styleguide/issues/428) and (http://jsbin.com/levewagufo/edit?html,js,console,output) was to rename the controller from vm = this to (in your case ) settings = this in the beginning of writing the controller. This makes sure the references match up to the "controller as" declaration from the view. Hope this helps

In View:

ng-controller="AddDetailController as addDetailsCtrl"

In Controller Js file:

 $scope.$watch('addDetailsCtrl.currentPage', function (current, original) {
        console.log(current + ":" + original);    });

Upvotes: 0

Krzysztof Safjanowski
Krzysztof Safjanowski

Reputation: 7438

AngularJS still works as expected:

angular
  .module('app', [])
  .controller('SettingsCtrl', function($scope) {

    var vm = this

    vm.test = ''


    $scope.$watch(function watch(scope) {
        return vm.test;
      },
      function handle(newV, oldV) {
        if (newV && newV.name && newV.name !== oldV.name) {
          vm.test.watchedName = newV.name.toUpperCase()
        }
      }, true);
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app='app'>
  <div ng-controller='SettingsCtrl as settings'>
    <input type='text' ng-model='settings.test.name' />
    <pre><code>
 {{ settings.test.watchedName }}
 </code></pre>
  </div>
</div>

Upvotes: 2

oakgun
oakgun

Reputation: 170

If I'm not wrong, your $watch is hit the first time a controller is loaded, but not when you change something in the object. If that's true, then try this:

$scope.$watch('vm', function (newVal, oldVal) {
    console.log('newVal, oldVal', newVal, oldVal);
}, true);

By default, $watch function watches the reference so if you only change a property of the watched object it will not be fired. By adding true at the end, you start deep watching, and you will get a hit each time you change a property of the object.

Upvotes: 9

Kuldeep Vithlani
Kuldeep Vithlani

Reputation: 613

Try following code for watch.

 $scope.$watch(function(){
    return ctrl.test;
},function(newVal,oldVal){
    console.log(newVal,oldVal);
},true)

Here is the working fiddle

You will need deep watch on object.

This link $watch an object will help you to understand this.

Upvotes: 1

Aravind
Aravind

Reputation: 2320

Please try calling the vm variable as controller.vmVariable in watcher. Controller is your controller name and then your variable assigned in vm.

$scope.$watch('controller.vmVariable', function (newVal, oldVal) {
    console.log('newVal, oldVal', newVal, oldVal);
});

Upvotes: 0

Related Questions