Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Isolate scope attributes defined with @ are undefined/disappear in directive's link function

The directive has isolate scope, and the scope attributes are being passed with "@".

This is how the directive is called:

<div ng-init="classForIcon = 'vladClass'"></div>
<div ng-init="textForIcon = 'Icon\'s text'"></div>
<div ng-init="routeForIcon = 'www.google.com'"></div>
<div ng-init="tooltipForIcon = 'my tooltip'"></div>
<div ng-init="imageForIcon = 'images/HOME_ICON1.png'"></div>

<rl-icon-widget icon-class="{{classForIcon}}" icon-text = "{{textForIcon}}" icon-tooltip="{{tooltipForIcon}}" icon-route="{{routeForIcon}}" icon-image="{{imageForIcon}}"></rl-icon-widget>

This is how the directive is defined:

'use strict';

fcPortalApp.directive('rlIconWidget', ['localizationAssistant', function(localizationAssistant) {
    var obj = {
        restrict: 'E',
        templateUrl: 'scripts/directives/rliconwidget/rliconwidget.html',

        //require: 'ngModel',
        scope: {
            //ngModel: '@',
            iconClass: "@",
            iconRoute: "@",
            iconText: "@",
            iconTooltip: "@",
            iconImage: "@"         
        },

        link: function(scope, element, attrs) {

            console.log(scope);
            console.log(scope.iconImage);
            console.log(scope.iconTooltip);
            console.log(scope.iconRoute);

        }
    };

    console.log(obj);
    return obj;

}]);

When I inspect the scope object (click on the output of console.log(scope_ in firebug), it looks like it has iconImage, iconTooltip and iconRoute properties set correctly.

Yet console.log(scope.iconImage), console.log(scope.iconTooltip) and console.log(scope.iconRoute) print "undefined"

like image 964
user2140869 Avatar asked Mar 06 '13 17:03

user2140869


1 Answers

Use $observe to observe the value changes of attributes that contain interpolation (e.g. src="{{bar}}"). Not only is this very efficient but it's also the only way to easily get the actual value because during the linking phase the interpolation hasn't been evaluated yet and so the value is at this time set to undefined. -- directive doc

By the time you manually inspect the scope, the values get defined.

The reason we need to use $observe (actually $watch will also work for isolate scope properties defined with '@') is because a directive will likely need to do something whenever the interpolated value changes. E.g., if the value of textForIcon changes, you may want to modify something in the DOM that is managed by your directive.

If you need the values defined when the linking function runs, you have two options:

  1. Use '=' instead of '@'. This will require that you remove the {{}}s from the HTML.
  2. If the values won't change, pass strings:
    <rl-icon-widget icon-class="vladClass" ...>
    Then in your directive, simply use attrs.iconClass -- no need for '@'.
like image 181
Mark Rajcok Avatar answered Sep 18 '22 23:09

Mark Rajcok