Angular.js directive dynamic templateURL

AngularjsAngularjs Directive

Angularjs Problem Overview


I have a custom tag in a routeProvider template that that calls for a directive template. The version attribute will be populated by the scope which then calls for the right template.

<hymn ver="before-{{ week }}-{{ day }}"></hymn>

There are multiple versions of the hymn based on what week and day it is. I was anticipating to use the directive to populate the correct .html portion. The variable is not being read by the templateUrl.

emanuel.directive('hymn', function() {
    var contentUrl;
    return {
        restrict: 'E',
        link: function(scope, element, attrs) {
            // concatenating the directory to the ver attr to select the correct excerpt for the day
            contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
        },
        // passing in contentUrl variable
        templateUrl: contentUrl
    }
});

There are multiple files in excerpts directory that are labeled before-1-monday.html, before-2-tuesday.html, …

Angularjs Solutions


Solution 1 - Angularjs

emanuel.directive('hymn', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           // some ode
       },
       templateUrl: function(elem,attrs) {
           return attrs.templateUrl || 'some/path/default.html'
       }
   }
});

So you can provide templateUrl via markup

<hymn template-url="contentUrl"><hymn>

Now you just take a care that property contentUrl populates with dynamically generated path.

Solution 2 - Angularjs

You can use ng-include directive.

Try something like this:

emanuel.directive('hymn', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           scope.getContentUrl = function() {
                return 'content/excerpts/hymn-' + attrs.ver + '.html';
           }
       },
       template: '<div ng-include="getContentUrl()"></div>'
   }
});

UPD. for watching ver attribute

emanuel.directive('hymn', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           scope.contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
           attrs.$observe("ver",function(v){
               scope.contentUrl = 'content/excerpts/hymn-' + v + '.html';
           });
       },
       template: '<div ng-include="contentUrl"></div>'
   }
});

Solution 3 - Angularjs

Thanks to @pgregory, I could resolve my problem using this directive for inline editing

.directive("superEdit", function($compile){
    return{
        link: function(scope, element, attrs){
        	var colName = attrs["superEdit"];
        	alert(colName);
 
            scope.getContentUrl = function() {
                if (colName == 'Something') {
                    return 'app/correction/templates/lov-edit.html';
                }else {
                    return 'app/correction/templates/simple-edit.html';
                }
            }
	        
	        var template = '<div ng-include="getContentUrl()"></div>';
            
            var linkFn = $compile(template);
            var content = linkFn(scope);
            element.append(content);
        }
    }
})

Solution 4 - Angularjs

You don't need custom directive here. Just use ng-include src attribute. It's compiled so you can put code inside. See plunker with solution for your issue.

<div ng-repeat="week in [1,2]">
  <div ng-repeat="day in ['monday', 'tuesday']">
    <ng-include src="'content/before-'+ week + '-' + day + '.html'"></ng-include>
  </div>
</div>

Solution 5 - Angularjs

I had the same problem and I solved in a slightly different way from the others. I am using angular 1.4.4.

In my case, I have a shell template that creates a CSS Bootstrap panel:

<div class="class-container panel panel-info">
	<div class="panel-heading">
		<h3 class="panel-title">{{title}} </h3>
	</div>
	<div class="panel-body">
		<sp-panel-body panelbodytpl="{{panelbodytpl}}"></sp-panel-body>
	</div>
</div>

I want to include panel body templates depending on the route.

	angular.module('MyApp')
	.directive('spPanelBody', ['$compile', function($compile){
		return {
			restrict		: 'E',
			scope : true,
			link: function (scope, element, attrs) {
				scope.data = angular.fromJson(scope.data);
				element.append($compile('<ng-include src="\'' + scope.panelbodytpl + '\'"></ng-include>')(scope));
			}
		}
	}]);

I then have the following template included when the route is #/students:

<div class="students-wrapper">
	<div ng-controller="StudentsIndexController as studentCtrl" class="row">
		<div ng-repeat="student in studentCtrl.students" class="col-sm-6 col-md-4 col-lg-3">
			<sp-panel 
			title="{{student.firstName}} {{student.middleName}} {{student.lastName}}"
			panelbodytpl="{{'/student/panel-body.html'}}"
			data="{{student}}"
			></sp-panel>
		</div>
	</div>
</div>

The panel-body.html template as follows:

Date of Birth: {{data.dob * 1000 | date : 'dd MMM yyyy'}}

Sample data in the case someone wants to have a go:

var student = {
	'id' 			: 1,
	'firstName' 	: 'John',
	'middleName' 	: '',
	'lastName' 		: 'Smith',
	'dob' 			: 1130799600,
	'current-class' : 5
}

Solution 6 - Angularjs

I have an example about this.

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  </head>

  <body>
    <div class="container-fluid body-content" ng-controller="formView">
        <div class="row">
            <div class="col-md-12">
                <h4>Register Form</h4>
                <form class="form-horizontal" ng-submit="" name="f" novalidate>
                    <div ng-repeat="item in elements" class="form-group">
                        <label>{{item.Label}}</label>
                        <element type="{{item.Type}}" model="item"></element>
                    </div>
                    <input ng-show="f.$valid" type="submit" id="submit" value="Submit" class="" />
                </form>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
    <script src="app.js"></script>
  </body>

</html>

angular.module('app', [])
    .controller('formView', function ($scope) {
        $scope.elements = [{
          	"Id":1,
          	"Type":"textbox",
          	"FormId":24,
          	"Label":"Name",
          	"PlaceHolder":"Place Holder Text",
          	"Max":20,
          	"Required":false,
          	"Options":null,
          	"SelectedOption":null
          },
          {
          	"Id":2,
          	"Type":"textarea",
          	"FormId":24,
          	"Label":"AD2",
          	"PlaceHolder":"Place Holder Text",
          	"Max":20,
          	"Required":true,
          	"Options":null,
          	"SelectedOption":null
        }];
    })
    .directive('element', function () {
        return {
            restrict: 'E',
            link: function (scope, element, attrs) {
                scope.contentUrl = attrs.type + '.html';
                attrs.$observe("ver", function (v) {
                    scope.contentUrl = v + '.html';
                });
            },
            template: '<div ng-include="contentUrl"></div>'
        }
    })

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
QuestionAlen GilianaView Question on Stackoverflow
Solution 1 - AngularjsAndrej KaurinView Answer on Stackoverflow
Solution 2 - AngularjspgregoryView Answer on Stackoverflow
Solution 3 - AngularjsShilanView Answer on Stackoverflow
Solution 4 - AngularjsicemView Answer on Stackoverflow
Solution 5 - AngularjsigasparettoView Answer on Stackoverflow
Solution 6 - AngularjsddagsanView Answer on Stackoverflow