Mati
Mati

Reputation: 1148

How to pass a template via bindings to an AngularJS Component

I'd like to pass a custom template, via bindings, into an AngularJS Component and render it using his scope. Something like this (pseudo-code, this is not working):

angular
  .module('myApp', [])
  .controller('mainController', ($scope) => {

    $scope.getTemplate = () => (`
      <div>
        <span>{{$ctrl.name}}</span>
      </div>
    `)
  })
  .component('myComponent', {
    controller: ($scope, $compile) => {
      const $ctrl = $scope.$ctrl;

      $ctrl.$onInit = () => {
        $ctrl.name = 'Hello World!';
      };

      $ctrl.compileTemplate = () => $compile($ctrl.template())($scope);
    },
    bindings: {
      template: '&'
    },
    template: `
      <div>
        My dynamic content: {{$ctrl.compileTemplate()}}
      </div>
  `
  });

Usage:

<div ng-controller="mainController as $ctrl">
  <my-component template="$ctrl.getTemplate()"></my-component>
</div>

Expected Result:

<div>
  My custom content:
  <div>
    <span>Hello World!</span>
  </div>
</div>

Is there any way to do it?

Upvotes: 2

Views: 3099

Answers (2)

Rathma
Rathma

Reputation: 1303

In case you want dynamic template, You can utilize the fact that you can pass a function to component template, in components that function is injectable, I refer you to this question for more info, but here is the main idea:

angular
  .module('myApp', [])
  .factory('tempalteFactory', {
      return getTemplate() {
          retrun '<b> yep </b>';
      }
  })
  .component('myComponent', {
    controller: ($scope, $compile) => {
      const $ctrl = $scope.$ctrl;

      $ctrl.$onInit = () => {
        $ctrl.name = 'Hello World!';
      };   

    },
    template: function($element, $attrs, templateFactory) {
          'ngInject';

          return templateFactory();
    }    
  });

Upvotes: 1

lenilsondc
lenilsondc

Reputation: 9800

You can use the $compile service to create a directive to handle the DOM manipulation involved.

The following working snippet implements an attribute directive compile which compiles the input value of the attribute in the controller scope. It basically take your template and add it to the inner content of the element to which the directive is attached and finally compiles it.

angular.module('app', [])
  .run(($rootScope) => {  
    $rootScope.name = 'world';    
    $rootScope.template = `
      <label>Name</label>
      <input type="text" ng-model="name">
      <h2>Hello {{ name }}!</h2>
    `;
  })
  .directive('compile', ($compile) => {
    return (scope, element, attrs) => {
      scope.$watch(
        scope => scope.$eval(attrs.compile),
        value => {
          element.html(value);
          $compile(element.contents())(scope);
        }
      );
    };
  })
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.js"></script>
<div ng-app="app">
  <div compile="template"></div>
</div>

Upvotes: 0

Related Questions