8

Please help me on, How can we make AngularJS compile the code generated by directive ?

You can even find the same code here, http://jsbin.com/obuqip/4/edit

HTML

<div ng-controller="myController">
    {{names[0]}} {{names[1]}}
    <br/> <hello-world my-username="names[0]"></hello-world>
    <br/> <hello-world my-username="names[1]"></hello-world>
    <br/><button ng-click="clicked()">Click Me</button>
</div>

Javascript

var components= angular.module('components', []);
components.controller("myController",
    function ($scope) {
        var counter = 1;
        $scope.names = ["Number0","lorem","Epsum"];
        $scope.clicked = function() {
            $scope.names[0] = "Number" + counter++;
        };
    }
);

// **Here is the directive code**
components.directive('helloWorld', function() {
    var directiveObj =  {
        link:function(scope, element, attrs) {
            var strTemplate, strUserT = attrs.myUsername || "";
            console.log(strUserT);
            if(strUserT) {
                strTemplate = "<DIV> Hello" + "{{" + strUserT +"}} </DIV>" ;
            } else {
                strTemplate = "<DIV>Sorry, No user to greet!</DIV>" ;
            }
            element.replaceWith(strTemplate);
        },
        restrict: 'E'
    };
    return directiveObj;
});
SunnyShah
  • 28,934
  • 30
  • 90
  • 137

3 Answers3

14

Here's a version that doesn't use a compile function nor a link function:

myApp.directive('helloWorld', function () {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      myUsername: '@'
    },
    template: '<span><div ng-show="myUsername">Hello {{myUsername}}</div>'
    + '<div ng-hide="myUsername">Sorry, No user to greet!</div></span>',
  };
});

Note that the template is wrapped in a <span> because a template needs to have one root element. (Without the <span>, it would have two <div> root elements.)

The HTML needs to be modified slightly, to interpolate:

<hello-world my-username="{{names[0]}}"></hello-world>

Fiddle.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 7
    @Liviu, since the directive doesn't change the myUsername value, one-way databinding ('@') seems more appropriate than two-way databinding ('='). Although using '=' is easier (no need to use {{}} in the HTML), using '@' makes it clear that the directive does not need to modify the value. – Mark Rajcok Jan 16 '13 at 19:24
  • @MarkRajcok, Excellent information in last comment, We would love to see some more like this be shared via blog or video tutorial. ;) – SunnyShah Jan 17 '13 at 10:31
10

Code: http://jsbin.com/obuqip/9/edit

components.directive('helloWorld', function() {
    var directiveObj =  {
        compile:function(element, attrs) {
            var strTemplate, strUserT = attrs.myUsername || "";
            console.log(strUserT);
            if(strUserT) {
                strTemplate = "<DIV> Hello " + "{{" + strUserT +"}} </DIV>" ;
            } else {
                strTemplate = "<DIV>Sorry, No user to greet!</DIV>" ;
            }
            element.replaceWith(strTemplate);
        },
        restrict: 'E'
    };
    return directiveObj;
});

Explanation: The same code should be used in compile function rather than linking function. AngularJS does compile the generated content of compile function.

SunnyShah
  • 28,934
  • 30
  • 90
  • 137
9

You need to create an angular element from the template and use the $compile service

jsBin

components.directive('helloWorld', ['$compile', function(compile) {
    var directiveObj =  {
        link: function(scope, element, attrs) {
            var strTemplate, strUserT = attrs.myUsername || "";
            console.log(strUserT);
            if (strUserT) {
                strTemplate = "<DIV> Hello" + "{{" + strUserT +"}} </DIV>" ;
            } else {
                strTemplate = "<DIV>Sorry, No user to greet!</DIV>" ;
            }

            var e = angular.element(strTemplate);
            compile(e.contents())(scope);
            element.replaceWith(e);
        },
        template: function() {
            console.log(args);
            return "Hello";
        },
        restrict: 'E'
    };
    return directiveObj;
}]);
Wei Hao
  • 2,756
  • 9
  • 27
  • 40
Liviu T.
  • 23,584
  • 10
  • 62
  • 58
  • http://stackoverflow.com/questions/12164138/what-is-the-difference-between-compile-and-link-function-in-angularjs. Normally it's not an issue with 1:1 directive:html. ng-repeat and similar directives use the compile function to optimize. – Liviu T. Jan 16 '13 at 12:50
  • 1
    This answer includes explanation from Misko http://stackoverflow.com/a/14359666/148869 – SunnyShah Jan 16 '13 at 13:46
  • @Liviu, what is the purpose of `template:` in the directive? Were you trying to see if you could generate the two versions of the output there (and found it didn't work and forgot to remove the code, maybe)? I'm curious to know if `template:` can take a function. – Mark Rajcok Jan 16 '13 at 16:57
  • @MarkRajcok actually I just modified the OP's solution to include the compile service, frankly I didn't see the other parameters :) – Liviu T. Jan 16 '13 at 17:06