5

I have a controller in my Angular app:

(function (angular) {
    function MyController() {
        this.name = 'Dave';

        // I want to have code like this:
        /*
          $scope.$watch('name', function (newValue, oldValue) {
              console.log(oldValue, "changed to", newValue);
          });
        */
    }

    window.myApp = angular.module('myApp', [])
        .controller('MyController', [MyController]);
})(angular);

Is there a way to use the features of $scope.$watch when attaching values to the MyController prototype?

I did notice that in my code, if I add something like ng-controller="MyController as myCtrl", and change my $scope.$watch statement to $scope.$watch('myCtrl.name', ...), it'll work after I add the $scope dependency, but that feels like tying my controller to my views, which feels wrong.

Edit

To attempt to clarify on what I'm asking. My HTML is something like this:

<div ng-app="myApp">
  <div ng-controller="MyController as myCtrl">
    <input type="text" ng-model="myCtrl.name" />
    <p>{{myCtrl.helloMessage}}</p>
  </div>
</div>

My controller is something like this:

angular.module('myApp', [])
  .controller('MyController', ['$scope', function ($scope) {
    this.name = 'World';
    this.helloMessage = "Hello, " + this.name;

    var self = this;
    $scope.$watch('myCtrl.name', function () {
      self.helloMessage = "Hello, " + self.name;
    });
  }]);

That currently works, but as you can see, in the $watch call, I have to reference my controller by the controllerAs name from my view, which is less than ideal.

I've setup an example on Plunkr

1
  • What is the benefit of storing values on controller instances instead of scope? Commented Aug 2, 2014 at 6:30

3 Answers 3

4

$watch

Expression that is evaluated on each $digest cycle. A change in the return value triggers a call to the listener. Watch expression can be a sting or function.

  • string: Evaluated as expression
  • function(scope): called with current scope as a parameter.

example

angular.module('app', []).controller('MainCtrl', function($scope) {
  this.name = 'World'
  this.helloMsg = ''
  
  $scope.$watch(function() {
    return this.name
  }.bind(this), function(newName) {
    this.helloMsg = "Hello, " + newName
  }.bind(this))
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app='app'>
  <div ng-controller='MainCtrl as ctrl'>
    <input type='text' ng-model='ctrl.name' />
    {{ ctrl.helloMsg }}
  </div>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. For some reason, I thought that when using $scope, you can't use this scoped variables.
3

You can avoid being bound to the view by using angular.bind in your watch, i.e.

$scope.$watch(angular.bind(this, function () {
    self.helloMessage = "Hello, " + self.name;
}));

https://docs.angularjs.org/api/ng/function/angular.bind

Comments

0

I might be wrong but I believe the $scope is automatically injected by angular.

Here's an example of a controller being declared:

var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {
      $scope.greeting = 'Hola!';
}]);

Notice how $scope dependency is declared '$scope' and injected function($scope)

In other words, should yours look something like this ?

function MyController($scope) {}

window.myApp = angular.module('myApp', [])
        .controller('MyController', ['$scope', MyController($scope)]);

EDIT:

I understand now. I've never had a need to use "controller as" but why not do it like this ?

<div ng-app="myApp">
  <div ng-controller="MyController">
    <input type="text" ng-model="name" />
    <p>{{helloMessage}}</p>
  </div>
</div>

angular.module('myApp', [])
  .controller('MyController', ['$scope', function ($scope) {
    this.name = 'World';
    this.helloMessage = "Hello, " + this.name;

    var self = this;
    $scope.$watch('name', function () {
      self.helloMessage = "Hello, " + self.name;
    });
  }])

3 Comments

Yes, I'm aware that I can use the $scope dependency to hold my values, but I was hoping for a way to still be able to use the controllerAs style approach in my views, which it seems you can't do when using $scope
Well I'm really not sure about your "way" but bottom line, $scope has to be declared and injected.
I've added further explanation and an example above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.