Search code examples
angularjsangularjs-directiveangularjs-scope

How to replace values of an isolated scope when uses the "@" for text attributes on Angular 1.4 directive? (works in Angular 1.3)


I would like to use attribute as strings in my html. So I don't need to use any more scope variables. My issue is actually defining some default values. But I realized, that when I use '@' in Angular, I'm not able to change this value in Angular 1.4, I was able to do using 1.3.

Is there a way to define default values on Angular 1.4 directives when using text attributes (@)?

I've tried replace my values on compile, compile Pre and Pos, link and controller and it's not replacing.

I could use '=' instead and define my attributes as string, but that's actually "Uggly":
Eq. <ribbon title="'my title as string, but forces the single quote use'">

Link for Plunker with Angular 1.3.1 working: http://plnkr.co/edit/onThA71Q5SE5scU7xOez

The snippet is using Angular 1.4

(function(){
    'use strict';

    angular.module('myApp', [])

        .directive('ribbon', function() {
            return {
                restrict: 'E',
                replace: true,
                scope: {
                    title: '@',
                    subtitle: '@'
                },
                template: '<span class="ribbon"><strong>{{title}}</strong> <i>{{subtitle}}</i></span>',
                controller: function($scope) {
                    $scope.title = $scope.title || 'Ribbon';
                    $scope.subtitle = $scope.subtitle || 'Default';
                }
            };
        });
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular.min.js"></script>
<div ng-app="myApp">
    <ul>
        <li>I have a
            <ribbon></ribbon>
        </li>
        <li>I have a
            <ribbon subtitle="customized"></ribbon>
        </li>
        <li>I have a
            <ribbon title="Custom ribbon" subtitle="customized"></ribbon>
        </li>
    </ul>
</div>


Solution

  • I am not sure if this is a breaking change or a bug with 1.4, version of angular. However you could use slightly different ways to tackle this problem.

    1) Deferring the default assignment. Since it looks like even if you set the value on the scope, (controller instantiation happens first) somewhere on the postLink phase it gets overwritten by the value (no value here so undefined) bound. You could use $scope.$evalAsync

      $scope.$evalAsync(function(){
           $scope.title = $scope.title || 'Ribbon';
           $scope.subtitle = $scope.subtitle || 'Default';
      });
    

    2) Use isolated scope with no bindings (scope:{}) (just so you don't pollute its parent scope by adding properties), or child scope scope:true and read the values from the attributes as you are binding them statically anyways.

      $scope.title = attr.title || 'Ribbon';
      $scope.subtitle = attr.subtitle || 'Default';