3

I'm doing my first steps in AngularJS directives. Just set up this one as an exercise to output a product name:

.directive('productname', function (Prefs) {
        return {
            restrict: 'E',
            replace: true,
            transclude: true,
            templateUrl: '/partials/productname.html',
            link: function (scope, element, attrs) {
                scope.brand = Prefs.owner;
            }
        }
    })

productname.html

<span class="productname"><span class="brand">{{brand}}</span> <span class="product" ng-transclude>{{productname}}</span></span>

and so the usage is plainly: <productname>{{product.name}}</productname>

Now, could someone tell me how I should go about making this directive configurable by adding a flag to output the productname linked?

The usage would be: <productname linked>{{product.name}}</productname> and the output/template would be:

<span class="productname"><a href="/edit/{{id}}"> <span class="brand">{{brand}}</span> <span class="product" ng-transclude>{{productname}}</span></a></span>

Seems complicated and I cannot quite figure out where the logic should be injected...

1 Answer 1

5

First of all, you should use the scope property of the directive declaration. Also, you do not need transclude in this case. Like so:

.directive('productname', function (Prefs) {
    return {
        restrict: 'E',
        scope: {
            product: "=",
            linked: "="
        },
        replace: true,
        templateUrl: '/partials/productname.html',
        link: function (scope, element, attrs) {
            // scope.product and scope.linked are automatically set
            scope.brand = Prefs.owner;
        }
    }
})

And the template:

<span class="productname" ng-switch="linked">
    <a href="/edit/{{id}}" ng-switch-when="true">
        <span class="brand">{{brand}}</span>
        <span class="product">{{product.name}}</span>
    </a>
    <span ng-switch-default>
        <span class="brand">{{brand}}</span>
        <span class="product">{{product.name}}</span>
    </span>
</span>

Call the template like so:

<productname product="product"></productname>

or:

<productname product="product" linked="'true'"></productname>

Update

If you want to use the linked attribute as a flag, you could do that by using the attrs variable:

.directive('productname', function (Prefs) {
    return {
        restrict: 'E',
        scope: {
            product: "="
        },
        replace: true,
        templateUrl: '/partials/productname.html',
        link: function (scope, element, attrs) {
            // scope.product is automatically set
            scope.linked = typeof attrs.linked != 'undefined';
            scope.brand = Prefs.owner;
        }
    }
})

Call it like so:

<productname product="product" linked></productname>
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks @Alp. The property linked doesn't seem to get ever evaluated to true. I tried with '@' as well to no avail. Anyway, I now see how the conditional is approached, I might have been ineffective in mine because I didn't consider introducing interim <span> to hold the logic.
my bad. try setting a value for linked. for "=" an expression (a variable in the scope linked="linked" or a string linked="'true'"). for "@" a value (linked="true")
Yep, now it works. I will however peruse to find a way convert the attribute into a flag.
Nope :) That's what I've been through. You want a single negation of attrs.linked only. The mere presence of the attribute/property means its value is undefined which, when double-negated, leads to false. But thanks anyway!
scope.linked = typeof attrs.linked != 'undefined'; works better for a flag property
|

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.