angular-ui / bootstrap

PLEASE READ THE PROJECT STATUS BELOW. Native AngularJS (Angular) directives for Bootstrap. Smaller footprint (20kB gzipped), no 3rd party JS dependencies (jQuery, bootstrap JS) required. Please read the README.md file before submitting an issue!
http://angular-ui.github.io/bootstrap/
MIT License
14.28k stars 6.73k forks source link

Cannot $provide alternate templateUrl for typeaheadMatchDirective #4266

Closed 807811b0-1373-11e5-b60b-1697f925ec7b closed 8 years ago

807811b0-1373-11e5-b60b-1697f925ec7b commented 9 years ago

Hi, I am using $provide to change the templateUrl for the typeaheadPopupDirective like this:

$provide.decorator('typeaheadPopupDirective', function ($delegate) {
    $delegate[0].templateUrl = 'bower_components/angular-ui-bootstrap/template/typeahead/typeahead-popup.html';
    return $delegate;
});

It does not work for typeaheadMatchDirective because the code is built differently:

  link:function (scope, element, attrs) {
    var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html';
    $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){
       element.replaceWith($compile(tplContent.trim())(scope));
    });
  }

Is it possible to allow a place to global override, i.e. $provide in my app config?

wesleycho commented 9 years ago

Yuck, this sounds like it was built wrong - might be worth doing a breaking change here. What are your thoughts @Foxandxss?

Foxandxss commented 9 years ago

Will take a peek tomorrow, but it seems that that code is really old, there are better ways to do that concrete thing and we could "normalize" it to what we are doing now (templateUrl function) but that will remove features (no dynamic template).

wesleycho commented 9 years ago

It was never truly dynamic to begin with - one workaround would be to change it to template-url="{{templateUrl}} or whatever. It should accomplish the same thing.

yemista commented 9 years ago

I am having an issue with this as well. I dont think the above suggestion works, at least it did not work for me. My suggestion is to modify the line in the link function of the typeaheadMatch directive to be

var tplUrl = attrs.templateUrl || 'template/typeahead/typeahead-match.html';

My reasoning for this is that since template-url sounds like it should be a URL, it should always be a string, so there is no need to do anything fancy such as evaluating a function that is returned from another function based on what templateUrl is. This is a simple approach and it has worked for me. Any one have any objecting thoughts?

icfantv commented 9 years ago

I'm a bit torn here. There's not really a reason templateUrl has to be a string that I can think of. That said, EVERY implementation of if that I can think of is a string. So maybe there's the answer?

A third solution would be to allow the user to override the parsing behavior w/ an override-parse (or similar) attribute, but I'm not loving that idea.

yemista commented 9 years ago

I agree it does not have to be a string, but ultimately it always resolves to a string. I cannot think of an example where it would not, just as you said. Im all for flexibility in code, but if no one will ever use the added flexibility, does it really need to be there?

lancecaraccioli commented 9 years ago

I second OP. I'd like to DRY up my templates by changing the typeahead-match template URL globally via $provide.

wesleycho commented 9 years ago

I have spent a bit of time thinking about this, and I am not quite sure if there is anything we can do here without a significant refactor maybe, along with breaking changes. May need to think about this some more, but because of the intermediaries involved, I am not sure there is anything we can do.

wesleycho commented 9 years ago

Noting investigation, attempted to strip out the manual compile logic today and replace it with just replace: true and a pluggable custom directive with logic straight from the attribute, ran into a problem with the directive attribute not containing the proper value because the child directive is compiled before interpolation occurs.

We need to investigate how to fix this cascading value not being preserved at the ideal step.

807811b0-1373-11e5-b60b-1697f925ec7b commented 8 years ago

I'm better at AngularJS now so I figured out the solution:

.run(['$templateCache', function (
    $templateCache
) {
    $templateCache.put('template/typeahead/typeahead-match.html', typeaheadMatchHtml);
}]);