2

I am trying to load conditional template urls via attributes, my directives is as follows.

The directive is in a ng-repeate and when box.key == 'experiences' the expression is returning education-form.php and not experiences-form.php.

<div multiple-form
   directive-data='directiveData'
   template-url="box.key == 'experiences'? 'experiences-form.php':'education-form.php'"
   item="item"
   forms="forms"
   form-name="{{box.key}}{{item._id}}"
   onsave="updateMultipleUser(box.key, item._id, $data)"
   onreset="formAction($formName, 'reset')"
   cancel="formAction($formName, 'cancel')"
   >
</div>

Directive DDO

 {
     restrict: 'A',
     replace: true,
     scope: {
         directiveData: '=',
         onsave: '&',
         onreset: '&',
         cancel: '&',
         formName: '@',
         forms: '=',
         item: '='
     },
     controller: controller,
     templateUrl: function(tElement, tAttrs) {
         return $rootScope.$eval(tAttrs.templateUrl);
     }
 }

attempting using link function

<div multiple-form
   directive-data='directiveData'
   template-map="{
   experiences:'experiences-form.php',
   courses:'education-form.php'
   }"
   box="box" 
   item="item"
   forms="forms"
   form-name="{{box.key}}{{item._id}}"
   onsave="updateMultipleUser(box.key, item._id, $data)"
   onreset="formAction($formName, 'reset')"
   cancel="formAction($formName, 'cancel')"
   >
</div>

 controller: controller,
     link: function(scope, element, attrs) {
         // shows correct template url ... now what?
         console.log(scope.templateMap[scope.box.key]);
     },
     templateUrl: function(tElement, tAttrs) {
         return 'experiences-form.php';
     }
9
  • When you use scope.eval property has to be on the scope or inherited from its parent. rootScope has no idea what is box.key Commented Jun 5, 2015 at 17:50
  • how to pass scope to templateUrl? sorry angular newbie here ;) Commented Jun 5, 2015 at 17:52
  • The thing is you cant.. :( it is too early in the directive compilation phase to have access to the scope. But you could try one thing, if this is the only one on the page. angular.element(document.querySelector("[multiple-form]")).scope().$eval(tAttrs.templateUrl) i have never tried it. Commented Jun 5, 2015 at 17:53
  • You can have static string in the attributes which you can directly access Commented Jun 5, 2015 at 17:57
  • 1
    @pankajparkar Yeah but that is an obvious way though.. :) append the element and re-compile Commented Jun 5, 2015 at 17:59

1 Answer 1

1

Markup

<div multiple-form
   directive-data='directiveData'
   ng-attr-template-url="{{box.key == 'experiences'? 'experiences-form.php':'education-form.php'}}"
   item="item"
   forms="forms"
   form-name="{{box.key}}{{item._id}}"
   onsave="updateMultipleUser(box.key, item._id, $data)"
   onreset="formAction($formName, 'reset')"
   cancel="formAction($formName, 'cancel')"
   >
</div>

Then your templateUrl function would be

 templateUrl: function(tElement, tAttrs) {
     $timeout(function(){ //wait until the ng-attr evaluates a value.
         return tAttrs.templateUrl;
     })
 }

Not sure it will work or not.

Update

Another obivious way would be loading template from the link function and append it from there it self rather than having call template through templateUrl

HTML

<div multiple-form
   directive-data='directiveData'
   template-path="{{box.key == 'experiences'? 'experiences-form.php':'education-form.php'}}"
   item="item"
   forms="forms"
   form-name="{{box.key}}{{item._id}}"
   onsave="updateMultipleUser(box.key, item._id, $data)"
   onreset="formAction($formName, 'reset')"
   cancel="formAction($formName, 'cancel')">
</div>

Directive

 {
     restrict: 'A',
     replace: true,
     scope: {
         directiveData: '=',
         onsave: '&',
         onreset: '&',
         cancel: '&',
         formName: '@',
         forms: '=',
         item: '=',
         templatePath: '@'
     },
     controller: controller,
     link: function(scope, element, attrs){
         //here you will have template path in your scope.templatePath variable
         //you can load template using it.
         var template = getTemplate(); //this can be done by below mentioned way
         element.append($compile(template)(scope));//addding compiled element
     }
 }

Inside your link function you could append directive template by loading template on demand, there are several way to load template from directive

Using $templateCache

While using $templateCache you need to put that template in angular $templateCache at the run phase,

app.run(function($templateCache){
   $templateCache.put('myTemplate.html', '<div>myTemplate</div>')
})

After doing this you could eaisily access that template in directive just by adding $templateCache.get('myTemplate.html')

Another way of adding template in $templateCache would be using script tag with type="text/ng-template"

<script type="text/ng-template" id="myTemplate.html">
  <div>myTemplate</div>
</script>

Using $http.get

You could do get the template by using $http.get('myTemplate.html') in success of it you will get data that is nothing but html content that file. You could compile and append that html to your directive element.

Using ng-include

You could use ng-include directive here. You need to do create a dummy div that will have an ng-include directive with desired template-path like <div ng-include="templatePath"></div>,it will load a template in that div. If you don't want to use div then you could use <ng-include src="templatePath"></ng-include>. But this is not much preferable way of doing code. because it does create child scope like ng-repeat does.

Sign up to request clarification or add additional context in comments.

7 Comments

@PSL I just thought about it..sorry for my bad idea..what will it consider for templateUrl or will it throw an error?
i guess it might throw error as you dont return a template. It does not even take a promise, which would have been awesome if it was able to
@pankajparkar thanks but how can the template be loaded at this stage?
Thanks!! Finally it worked in my case var template = $templateCache.get(scope.templateMap[scope.box.key]); element.append($compile(template)(scope)); since I have all the templates in script tags at startup
@ericsicons see all those possibility I covered in my answer..Glad to help you...Thanks :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.