Search code examples
javascriptangularjsangular-directive

Can't return/render html from a custom directive


I'm pretty new with angular's directives and trying to achieve a simple directive that renders dynamic html. Consider the following html

<body ng-app="myApp" ng-controller="myCtrl">
    <my-directive></my-directive>
</body>

What i would like to achieve is a result of

<span>My HTML<span> 

Style:

span {
  color:blue;
}

My directive:

myApp.directive("myDirective", ['$sce', function($sce) {
  return {
    restrict: "E",
    scope: {
      text: "="
    },
    template: '{{test}}',
    replace: true,
    transclude: false,
    link: function(scope, element, attrs) {
        scope.test  = "<span>My HTML<span>";
    }
  }
}]);

All my attempts failed, here's my codepen example, hope you could help me with that because it feels like im missing something. Btw, i believe the reason it's because it is HTML, so i tried to use $sce, but still no success with that.

Edited: I added css style for span tag, so once it will work the color of the text should be blue.


Solution

  • Usually, you would not bind variables to the scope of the directive, but to the scope of your controller. Try to avoid $scope as much as possible, as this is best practice.

    Your index.html would look like:

    <body ng-app="myApp">
        <my-directive></my-directive>
    </body>
    

    Your controller:

    myApp.controller("myCtrl", function() {
      var vm = this;
      vm.test = "Test";
    });
    

    And finally, your directive:

    myApp.directive("myDirective", ['$sce', function($sce) {
      return {
        restrict: "E",
        template: '<span>{{vm.test}}</span>',
        replace: true,
        controller: "myCtrl",
        controllerAs: "vm"
      }
    }]);
    

    Notice, that your variable "test" is bound to the controller directly. The controller is referenced by "controller" and "controllerAs" in your directive.

    Let me know, if that helps you.

    EDIT: If you want to assign the variable value inside the link method you can try:

    myApp.directive("myDirective", ['$sce', function($sce) {
      return {
        restrict: "E",
        scope: {
          text: "@"
        },
        replace: true,
        transclude: true,
        template: '<span ng-bind="text"></span>',
        link: function(scope, element, attrs){
            scope.text = "<span>...</span>";
        }
      }
    }]);
    

    A few things:

    • scope.text: "=" only applies, if you get the text prop from the html element
    • use "@" instead, if you assign it inside the directive
    • variables defined inside scope are referenced by the variable name only, when inside the template
    • directives always need a single root element in the template
    • you can use ng-bind or ng-bind-html (with your $sceProvider) to bind your dynamic html to that root element