AngularJs Passing complex data to directive

Angularjs

Angularjs Problem Overview


I have the following directive:

<div teamspeak details="{{data.details}}"></div>

this is the object structure:

data: {
                details: {
                    serverName: { type: 'text', value: 'my server name' },
                    port: { type: 'number', value: 'my port' },
                    nickname: { type: 'text' },
                    password: { type: 'password' },
                    channel: { type: 'text' },
                    channelPassword: { type: 'password' },
                    autoBookmarkAdd: { type: 'checkbox' }
                }
}

and I want it to generate a link based on the data inside the data.details object. Unfortunately it doesn't work since somehow I cann't access any inner values of the details object, but if I am passing it a simple data structure like:

<div teamspeak details="{{data.details.serverName.value}}"></div>

I can access it by using {{details}}.

Here is my Directive Code:

App.directive('teamspeak', function () {
    return {
        restrict: 'A',
        template: "<a href='ts3server://{{details.serverName.value}}:{{details.port.value}}'>Teamspeak Server</a>",
        scope: {
            details: '@details',
        },
        link: function (scope, element, attrs) {
        }
    };
});

Thanks

Angularjs Solutions


Solution 1 - Angularjs

Read on Angularjs official site explanation :

> @ or @attr - bind a local scope property to the value of DOM > attribute. The result is always a string since DOM attributes are > strings. If no attr name is specified then the attribute name is > assumed to be the same as the local name. Given and widget definition of scope: { localName:'@myAttr' }, > then widget scope property localName will reflect the interpolated > value of hello {{name}}. As the name attribute changes so will the > localName property on the widget scope. The name is read from the > parent scope (not component scope).

So you can send only a string, to pass an object, you need to set-up a bi-directionnal binding using =.

   scope: {
        details: '=',
    },

And your HTML will looks like

<div teamspeak details="data.details"></div>

Solution 2 - Angularjs

Someone asked about how to do it without isolating scope, here is a solution:

<div teamspeak details="{{data.details}}"></div>

App.directive('teamspeak', function () {
    return {
        restrict: 'A',
        template: "<a href='ts3server://{{details.serverName.value}}:{{details.port.value}}'>Teamspeak Server</a>",
        link: function (scope, element, attrs) {
            if(attrs.details){
                scope.details = scope.$eval(attrs.details);
            }
        }
    };
});

We can even use $interpolate if any values in attrs.details should be dynamically set with angular {{...}} expressions...

scope.details = scope.$eval($interpolate(attrs.details)(scope));

(don't forget to inject $interpolate service into your directive)

Important Note: I have not tested this method with angular 2.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAviran CohenView Question on Stackoverflow
Solution 1 - AngularjsL105View Answer on Stackoverflow
Solution 2 - Angularjsplong0View Answer on Stackoverflow