Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Should the directives support variable templateUrls? #1611

Closed
joshkurz opened this issue Jan 18, 2014 · 22 comments
Closed

Should the directives support variable templateUrls? #1611

joshkurz opened this issue Jan 18, 2014 · 22 comments

Comments

@joshkurz
Copy link
Contributor

I know that it would be a simple change to allow for the directives in this repo to offer variable templates based off of the markup. As of now, the directives are hardcoded with specific urls, making it a little difficult to plug and play with Bower.

update: it also makes it impossible to use the same directive with different templates.

Here is an issue angular/angular.js#5867 brought up, which would allow for overwriting urls in $templateProvider. I believe that the templateUrls should be optionally overwritten by some attribute on the directive itself.

Is this something that you guys are looking at doing or is the templateUrl hardcoded in the directives for a reason i'm not aware of?

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

@joshkurz There is a "hackish" way to configure templateUrl dynamically as mentioned #743 (comment).

@joshkurz
Copy link
Contributor Author

ahh yes that is hackish.

Since this has been a topic of debate for a while now, I dont want to beat a dead horse, but I really feel that with >1.1.x the ability to use variable template urls is as easy as:

templateUrl: function(tElem,tAttrs){
  if(tAttrs.templateUrl){
    return templateUrl;
  } else {
   return defaultPath;
  }
},

This could save people a lot of time when using these directives without having to take hackish steps or messing with the build.

@pkozlowski-opensource
Copy link
Member

I can't stop thinking that this whole problem is artificial, since templates should be preloaded in the $temaplateCache anyways. Maybe we should change those paths to something abstract, like '$templates/alert.html' so people understand that those paths shouldn't be used to download real files...

I'm kind of tired with this topic as I fail to see what is the real problem and don't know how to make people aware of the fact that those paths are not real paths....

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

@pkozlowski-opensource Agree, but a valid use case IMO is if I have 2 templates for one directive, both in the $temaplateCache and I want to choose one based on user's preference, ie dark theme or white theme :-)

@pkozlowski-opensource
Copy link
Member

@bekos right, but what you are talking about is different topic, that is, using a different template per directive usage / instance, which I agree is an important topic, but I feel like this should be coming from AngularJS itself.

@joshkurz was mentioning "playing with Bower", which lead me to think that this is about overriding default templates. @joshkurz what is your real concern?

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

@pkozlowski-opensource Nope. I mean for example the same datepicker template for every datepicker in my application, but becuase I can have only one build file for all the user's of my application, I want it to hold both templates, and each user will use the appropriate one based on some config. Do I make sense?

@joshkurz
Copy link
Contributor Author

i am saying that the user should be able to use whatever templateUrl they please from the markup itself, rather than hacking js to do so. "Angular Zen" I mentioned playing with Bower just as one use case, but i feel the use case @bekos brought up is similar. Both are solved by using a function of this sort to return the templateUrl.

@pkozlowski-opensource
Copy link
Member

@bekos @joshkurz sorry guys, I'm slow today... Let me list the use-cases I'm aware off:

  • I want to use standard BS templates => nothing to do, I'm including built file with default templates
  • I want to override default templates
    ** all of them => I get the built file without any templates and put my templates in $templateChache
    ** some of them => I get the built file with default templates and put my templates in $templateChache
  • I want to use a different template per directive usage => this is a real use-case we don't support today

@bekos I'm not sure what you mean by "user" - do you mean that different users interacting with an application should see different set of templates (that is - different widgets?). Is it a real use case?

@joshkurz I'm still not clear what is the exact thing you are after... Is it one of the use-cases I've listed above or something else? If this is something else, could you please be more specific / provide more details?

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

@pkozlowski-opensource I will try to explain with simple, step-by-step example to help you :-P

Let's say I have the accordion directive, but because some of my users like dark colors, I also have created another template with different classes, that make my panel headers black with white text :-)

So in my build file I have something like this:

angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {

 // White
  $templateCache.put("template/accordion/accordion.html",
    "<div class=\"panel-group\" ng-transclude></div>");

// Black
 $templateCache.put("template/accordion/accordion-black.html",
    "<div class=\"panel-group-black\" ng-transclude></div>");
}]);

Now when user John Doe uses my application to show the black template, but when Jane Roe uses it to show the white one :-)

So when my application initializes I want to do something naive like:

app.run(
  if (user === 'John Doe') {
     accordion.template = 'template/accordion/accordion-black';
  } else if (user === 'Jane Roe') {
     accordion.template = 'template/accordion/accordion';
  }
);

So as long as John uses my application he sees everything black, but Jane sees everything white.
I hope this make sense now!!! :-D

@pkozlowski-opensource
Copy link
Member

@bekos it totally makes sense now, thnx for bearing with me. This sounds like yet another use-case to have different "profiles" for different users. Not sure how common it is and if this couldn't be handled by CSS, but it doesn't sound like the issue that @joshkurz was raising.

@bekos is it a real thing that you are struggling with in one of your projects or just anticipating a use-case? Somehow I would expect that your use-case would be handled with a different bootstrap CSS and wouldn't require a different set of templates, but I might be wrong.

@joshkurz
Copy link
Contributor Author

2 and 3 are correct. I think saying something about bower made you think i was just talking about that one case. (i should have been more descriptive). This is broader than that in my opinion, since the proposed solution solves multiple use cases.

  • 2 is solved today I understand that. I believe doing it this proposed way makes it simpler and opens up more options. (everything that is available today would still be an option, plus many more)
  • 3 would be solved by this for all cases where a static string is used in the markup to define the templateUrl, but to solve @bekos use case and turn it into a general solution, some config object would need to be accessible to the templateUrl function as well. (im not suggesting the templateURl be an interpolated value)

so maybe it would look like this

templateUrl: function(tElem,tAttrs){
 return tAttrs.template || config.template || defaultPath;
},

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

@pkozlowski-opensource I haven't deal with this in a project but except theming case (dark/white etc) that can be solved by just changing the CSS, that will solve issues for alternative templates. For example in timepicker the arrows to be on the left/rigth of the input instead of up/down - I know this sounds silly but I couldn't think of something better :-)

@chrisirhc
Copy link
Contributor

@bekos, for the use case you mentioned, using the $decorator to modify the directive actually seems like quite a decent approach. I don't think it's very hackish in a way that makes it a bad practice. It's quite maintainable too because the directive name and templateUrl properties are unlikely to change.

Referring to @joshkurz 's use case 3, to me, this seems to be quite rare and unusual of a use case. I think that unless a directive explicitly deals with generating html for display (perhaps popovers is an example), it's unlikely that a user will want to specify a template url on each use of the directive. If we do go with that approach that @joshkurz mentions with the templateUrl function, I think the attribute should be prefixed with the directive name.

I feel like this should be allowed through users defining their own directives (with their templateUrls).

My vision on such customization is to allow users to instantiate the directives we have in this repo and customize them without copy-pasting the whole directive code. Something similar to the $tooltip service.

Like:

.directive( 'popover', [ '$tooltip', function ( $tooltip ) {
  var directiveDef = $tooltip( 'popover', 'popover', 'click' );
  directiveDef.templateUrl = "myTemplate";
  return directiveDef;
}]);

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

@chrisirhc I called it hackish in a sense that is not known by many people.

@chrisirhc
Copy link
Contributor

@bekos ah okay. Indeed and it's quite new. I like the idea though. Perhaps it should be in the FAQ, or StackOverflow as a wiki. And we should know about it if someone asks, heh.

@bekos
Copy link
Contributor

bekos commented Jan 18, 2014

+1 for adding in the FAQ.

@joshkurz
Copy link
Contributor Author

thats not a bad idea at all @chrisirhc. I kinda like it. Never thought about overwriting directive definition objects based off of the return values of some directive service. (could be overkill though for simple use cases)
I also agree 3 is rare (in a since of this repo specifically)...

I do feel that the solution for 2 is a little hacky as it makes the controller the source of truth for the directive's template.

i believe there is no benefit to hardcoding the templateUrls, because making them dynamic solves these use cases for little cost.

So is there a benefit?

@chrisirhc
Copy link
Contributor

I think the current way of doing things is just to keep things short and simple. My concern is weighing the need for this functionality over more code to maintain.

We can even use a service / value provider for the templateUrl:

templateUrl: $bsTemplates('popover')

This way the behavior can be overridden. I'm just quite on the fence on this. I think the real issue is perhaps knowing what majority of users want or need.

@joshkurz
Copy link
Contributor Author

I think the real issue is perhaps knowing what majority of users want or need.

Agree 100%

From what i've seen in other threads people do want this, but its not until now that its possible to offer it with a simple implementation.

This can be accomplished in simple manageable ways now with AngularJS>1.2.x as shown by examples on this thread. I dont feel it makes things complex by any means. The ability for users to define templates (templateCached or not) in their semantic markup or some js config is very powerful. IMO

jdewit added a commit to jdewit/bootstrap that referenced this issue Jan 30, 2014
I need the ability to have different markup for some tabs on a page
by page basis. Injecting templates with the script tag on each page
is getting ugly.

This topic was recently brought up again in angular-ui#1611.

@sudhakar mentions a similar need for this in angular-ui#105.

_Usage_

```html
    <tabset>
      <tab ng-repeat="tab in tabs">
        <tabset template-url="custom_tab_template">
          <tab ng-repeat="innerTab in tab.tabs">
            <span class="inner-tab-content">{{ innerTab.content }}</span>
          </tab>
        </tabset>
      </tab>
    </tabset>
```
jdewit added a commit to jdewit/bootstrap that referenced this issue Jan 30, 2014
I need the ability to have different markup for some tabs on a page
by page basis. Injecting templates with the script tag on each page
is getting ugly.

This topic was recently brought up again in angular-ui#1611.

@sudhakar mentions a similar need for this in angular-ui#105.

Usage

<tabset>
  <tab ng-repeat="tab in tabs">
    <tabset template-url="custom_tab_template">
      <tab ng-repeat="innerTab in tab.tabs">
        <span class="inner-tab-content">{{ innerTab.content }}</span>
      </tab>
    </tabset>
  </tab>
</tabset>
jdewit added a commit to jdewit/bootstrap that referenced this issue Jan 30, 2014
I need the ability to have different markup for some tabs on a page
by page basis. Injecting templates with the script tag on each page
is getting ugly.

This topic was recently brought up again in angular-ui#1611.

@sudhakar mentions a similar need for this in angular-ui#105.

Usage

    <tabset>
      <tab ng-repeat="tab in tabs">
        <tabset template-url="custom_tab_template">
          <tab ng-repeat="innerTab in tab.tabs">
            <span class="inner-tab-content">{{ innerTab.content }}</span>
          </tab>
        </tabset>
      </tab>
    </tabset>
jdewit added a commit to jdewit/bootstrap that referenced this issue Jan 30, 2014
I need the ability to have different markup for some tabs on a page
by page basis. Injecting templates with the script tag on each page
is getting ugly.

This topic was recently brought up again in angular-ui#1611.

@sudhakar mentions a similar need for this in angular-ui#105.

Usage

    <tabset template-url="custom_tab_template">
      <tab heading="Stuff">
        Some stuff here
      </tab>
    </tabset>
@rvanbaalen rvanbaalen added this to the Purgatory milestone Mar 31, 2015
@ackzell
Copy link

ackzell commented Aug 11, 2015

Hi everyone,

I don't mean to stir up the water again, but I think I am facing the actual case where

I want to use a different template per directive usage

The thing is, we are using the accordion directive for 2 different purposes in the same app. One is to display a set of data and the other one is because the client wanted the behavior on a FAQ kind of page.

So, for the set of data, we needed to display one button that would actually toggle the accordion-group but the rest of the heading won't trigger any change (this is where we had to alter the template and use one of our own).

Now for the other accordion, we want the standard behavior, where clicking anywhere on the heading will toggle the contents.

Right now, we have an issue where after modifying the heading for one of the accordions, the other got changed as a side effect.

I guess we could roll our own solution leveraging the collapse directive in either of the cases, but I was wondering if there could be a way to "switch" between templates.

I looked into the related links posted above but wasn't able to figure out what I am trying to accomplish.

@RobJacobs
Copy link
Contributor

@ackzell There have been several recent commits to add 'templateUrl' support, the one for the accordion can be viewed here. Closing this issue as complete.

@ackzell
Copy link

ackzell commented Aug 12, 2015

Thanks a lot @RobJacobs, I didn't go back to the docs after implementing the accordions a couple weeks ago. Awesome timing!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants