Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing variables from the current scope to a compiled directive

I'm trying to pass a variable from the current scope to a directive added via the $compile service.

I can pass a string to the child directive but not the actual object.

Here's a fiddle with the scenario : http://jsfiddle.net/ewx2trvx/2/

HTML:

<section ng-app="myApp" ng-controller="MainCtrl">
    <addbuttonsbutton></addbuttonsbutton>
    <div id="space-for-buttons"></div>
</section>

JS:

var myApp = angular.module('myApp', []);

function MainCtrl($scope) {
    $scope.count = 0;
}

myApp.directive("addbuttonsbutton", function () {
    return {
        restrict: "E",
        template: "<button addbuttons>Click to add buttons</button>"
    }
});

//Directive for adding buttons on click that show an alert on click
myApp.directive("addbuttons", function ($compile) {
    return function (scope, element, attrs) {
        element.bind("click", function () {
            scope.count++;
            angular.element(document.getElementById('space-for-buttons'))
                .append($compile("<alert alert='count'></alert>")(scope));
        });
    };
});

//Directive for showing an alert on click
myApp.directive("alert", function () {
    return {
        template: "<div><button class='btn btn-default'>Show alert # {{count}}</button></div>",
        scope: {
            a: '@alert'
        },
        replace:true,        
        link: function (scope, element, attrs) {
            element.bind("click", function () {
                console.log(scope.a);
                alert("This is alert #" + scope.a);
            });
        }
    };
});

Any thoughts?

Thanks.

like image 822
sirrocco Avatar asked Apr 21 '15 09:04

sirrocco


2 Answers

Fir of all you need to apply scope after you compile and append because you are manipulating with DOM outside of the digest loop:

element.bind("click", function () {
    scope.count++;
    angular.element(document.getElementById('space-for-buttons'))
        .append($compile("<alert alert='count'></alert>")(scope));
    scope.$apply();
});

Then since you are using alert='count' then you need to change scope configuration in alert directive:

scope: {
    a: '=alert'
},

Otherwise, if you use a: '@alert' you need to interpolate it in the attribute like this: alert='{{count}}'

Finally, since the is two-way data binding, you can assign one more intermidiate primitive property to use as the index of the button:

myApp.directive("alert", function () {
    return {
        template: "<div><button class='btn btn-default'>Show alert # {{index}}</button></div>",
        scope: {
            a: '=alert'
        },
        replace:true,        
        link: function (scope, element, attrs) {
            scope.index = scope.a;
            element.bind("click", function () {
                alert("This is alert #" + scope.index);
            });
        }
    };
});

Demo: http://jsfiddle.net/ewx2trvx/3/

like image 170
dfsq Avatar answered Nov 05 '22 00:11

dfsq


You need to interpolate the value to pass it otherwise angular assumes you want to have a string there.

Change your $compile("<alert alert='count'></alert>")(scope) to $compile("<alert alert='{{count}}'></alert>")(scope) and then convert the received string into a number: var count = +scope.a;.

Additionally inside your template change {{count}} to {{a}} because you have an isolated scope here.

Note that in angular 1.2 there is no one-time-binding. If you use 1.3 you can one-time-bind with {{::count}}.

like image 42
Jonathan Avatar answered Nov 05 '22 01:11

Jonathan