1

I have a directive defined like this:

myApp.directive('stoplight', function() {
    return {
        restrict:'E',
        transclude: true,
        scope: {
            value: '@'
        }, 
        link: function(scope, element) {
            if (scope.value === true) {
                element.html('<i class="icon icon-true green"></i>');
            } else if (scope.value === false) {
                element.html('<i class="icon icon-false red"></i>');
            } else {
                element.html('<i class="icon icon-unknown yellow"></i>');
            }
        }
    };
});

When I use this directive, I use the following markup:

<stoplight value="boolValue" />

My controller behind stoplight looks like this:

myApp.controller('MyController', function($scope, $http) {
    $scope.boolValue = null;
    $scope.init = function() {
      $scope.boolValue = false;
      $http.jsonp('http://anyorigin.com/get?url=www.google.com&callback=JSON_CALLBACK')
        .success(function() {
            console.log('woohoo!');
            $scope.boolValue = true;
        });
    };

    $scope.init();
}};

I have two issues, and neither make sense to me.

  1. The '@' in my directive doesn't work. If I change the '@' to a '=', the link function works somewhat as expected. However, I want to use one-way binding instead of two-binding for performance reasons.
  2. For some reason, the $scope.boolValue = true; in my success callback doesn't update the UI. The icon stays red. I can set the value to null, expecting yellow, but it stays red. If I look in the console window though, I can see 'woohoo!'. I don't understand why updating boolValue outside of the callback works, yet in the callback, it just doesn't work. I do not see any error in the console window or anything of that nature.

Can someone please help me identify why this isn't working? I'm not sure if this is one issue or two issues. I think they both have to do with the binding. However, I'm not sure how to remedy this.

Thank you.

user687554
  • 10,663
  • 25
  • 77
  • 138
  • after the callback try to use $scope.apply() :) AngularJS sometimes doesn't know the context changes in callbacks. – Chrissx Aug 12 '14 at 11:49
  • I am not 100% sure about this, but are you sure that in one-way binding the boolValue is not passed as text instead of boolean? – pasine Aug 12 '14 at 12:01

3 Answers3

1

Regarding issue #1, I believe it is occurring because '@' always results in a string value. So you probably need scope.value === 'true' and scope.value === 'false'.

Regarding issue #2, as neilhem already answered, you need the double curly braces:

<stoplight value="{{boolValue}}" />
0

Use double curly braces <stoplight value="{{ boolValue }}" />

Rakhat
  • 4,783
  • 4
  • 40
  • 50
0

For #1: using @ doesn't mean 'one-way binding', it means to take evaluated value of the DOM attribute, not the variable, so scope.value will result in a string value of 'boolValue', you could use <stoplight value="{{ boolValue }}" /> in your template or = in your directive. Here is a great explanation how @ and = differs.

For #2: Your UI doesn't update, because you directive is not watching for changes on attribute value. When directive is initialized, it takes first value and does the stuff in your directive, however - that's it. When value changes, nothing should happen in directive. Try this:

myApp.directive('stoplight', function() {
  return {
    restrict:'E',
    transclude: true,
    scope: {
      value: '@'
    },
    link: function(scope, element) {
      scope.$watch(function() { return scope.value; }, function(value) {
        if (value === true) {
          element.html('<i class="icon icon-true green"></i>');
        } else if (value === false) {
          element.html('<i class="icon icon-false red"></i>');
        } else {
          element.html('<i class="icon icon-unknown yellow"></i>');
        }
      });
    }
  };
});
Community
  • 1
  • 1
domakas
  • 1,246
  • 8
  • 9