3

I want to create a directive, where it observe the 'playerSearchSpinnerOn' property in the parent scope. where the value changes, than execute code in my directive link function. At the moment, my observe function isn't been triggered when value changes.

html

  <div id="addUsers" class="center" spinner spinnerOn="{{playerSearchSpinnerOn}}">

directive

 monopolyMenuModule.directive('spinner', function () {
    return {

        restrict: "A",
        link: function (scope, elem, attr) {
            attr.observe('spinnerOn', function (newValue, oldValue) {
                var spinner = new spinner();
                if (newValue) {
                    // load spinner
                    spinner.spin(elem);
                }
                else if (newValue == false) {
                    // close spinner
                    spinner(false);
                }
            });


        }
    }

parent controller

 monopolyMenuModule.controller('AddUsersCtrl', ['$scope', 'addUserServices', 'GameGroupDetails', function ($scope, service, GameGroupDetails) {

     // add code to call notifyUsers object.. watch pluralsight "connecting our server to client" and "how signalr works"
     $scope.playerSearchSpinnerOn = false;

     $scope.FindUsers = function () {
         if (GameGroupDetails != null) {
             service.FindUsers(GameGroupDetails).done(function () {
                 // add spinner once group has been show in invite screen
                 $scope.playerSearchSpinnerOn = true;
             });
         }
     };

 }])

when playerSearchSpinnerOn property changes in the AddUserCtrl parent controller, i want my 'spinner' directive to react to this change.

where am i going wrong?

1
  • it should be attr.$observe then all code will started working Commented Mar 30, 2015 at 20:52

3 Answers 3

5

Instead of watching an attribute, you should instead use an isolated scope

monopolyMenuModule.directive('spinner', function () {
    return {
        restrict: "A",
        scope:{
          spinnerOn: "@"
        }
        link: function (scope, elem, attr) {
            $scope.$watch('spinnerOn', function (newValue, oldValue) {
                var spinner = new spinner();
                if (newValue) {
                    // load spinner
                    spinner.spin(elem);
                }
                else if (newValue == false) {
                    // close spinner
                    spinner(false);
                }
            });
        }
    }

This way you don't have to rely on any weird parent-based logic, you just pass in the value you want to watch. That being said, I have no idea what this spinner thing is, and I suspect you have some issues there.

Also, read this blog for a great guide on isolated scopes.

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

1 Comment

Also see Sitepoint's article on AngularJS directives. observe is overbloated for this simple case.
2

Solved. I had to wrap the playerSearchSpinnerOn property with the $apply service. This was needed because, changing this property was happening outside of angular' knowledge. calling apply() looks for any new changes in the model, and if one or more is found, then it update's the DOM.

     $scope.FindUsers = function () {
         if (GameGroupDetails != null) {
             service.FindUsers(GameGroupDetails).done(function () {
                 // add spinner once group has been show in invite screen

                 // apply is needed and apply is only called in angularjs directives
                 $scope.$apply(function(){ 
                        $scope.playerSearchSpinnerOn = true;
                 });


             });
         }
     };

2 Comments

why $apply() needed here?
In my case, $apply() was needed because nothing had happened that would trigger the watchers (admittedly, my case is significantly different from OP, but the same solution applied).
1

You made some sort of typo, it should be attr.$observe instead of attr.observe, $observe will work as like watch inside a directive, it will call a attr.$observe function whenever the interpolation ({{}}) directive of attribute gets evaluated. Also on UI use attribute as hyphen (-) separated & in directive it would be used as camelCase instead of

HTML

<div id="addUsers" class="center" spinner spinner-on="{{playerSearchSpinnerOn}}">

Directive

monopolyMenuModule.directive('spinner', function () {
  return {

    restrict: "A",
    link: function (scope, elem, attr) {
        attr.$observe('spinnerOn', function (newValue, oldValue) {
            var spinner = new spinner();
            if (newValue) {
                // load spinner
                spinner.spin(elem);
            }
            else if (newValue == false) {
                // close spinner
                spinner(false);
            }
        });


    }
 }

3 Comments

I made the change, but $observe callback function still not being triggered
Still no luck. I'm using angular.module.config, which loads the html view template(referencing the spinner direcitve , using the AddUsersCtrl controller) after the compilation of the spinner directive js script.... Is this a problem?
could you please share you config code? Also did you change spinnerOn to sinner-on in you directive element?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.