web-dev-qa-db-fra.com

Pouvez-vous changer de templateUrl à la volée?

Est-il possible de modifier templateUrl à la volée en transmettant des valeurs dans le champ d'application de la directive? 

quelque chose qui ressemble peut-être à ça: 

<div> 
   <boom data="{{myData}}" />
</div> 

.directive('boom', function {
        return {
            restrict: 'E',
            transclude: true,
            scope: 'isolate',
            locals: { data: 'bind' },
            templateUrl: "myTemplate({{boom}}})" // <- that of course won't work.
        }
    });
26
iLemming

C'est possible, mais lorsque le modèle à charger dépend de certaines données de portée, vous ne pouvez plus utiliser la propriété templateUrl de la directive et vous serez obligé d'utiliser une API de niveau inférieur, à savoir $http et $compile.

En gros, ce que vous devez faire (uniquement dans la fonction de liaison) est de récupérer le contenu du modèle à l'aide de $http (n'oubliez pas d'impliquer $templateCache!), Puis de compiler le contenu du modèle "manuellement".

Cela peut sembler beaucoup de travail, mais dans la pratique, il est plutôt simple. Je suggérerais de jeter un coup d'oeil à la directive ngIncludesources où ce modèle est utilisé. 

Voici un squelette d'une telle directive:

app.directive('boom', function($http, $templateCache, $compile, $parse) {
        return {
            restrict: 'E',
            link: function(scope , iElement, iAttrs) {                            
              var boom = $parse(iAttrs.data)(scope);
              $http.get('myTemplate'+boom, {cache: $templateCache}).success(function(tplContent){
                iElement.replaceWith($compile(tplContent)(scope));                
              });              
            } 
        }
    });

en supposant qu'il serait utilisé comme <boom data='name'></boom>. Vous travaillez ici: http://plnkr.co/edit/TunwvhPPS6MdiJxpNBg8?p=preview

Veuillez noter que j'ai changé l'évaluation d'attributs de {{name}} à l'analyse d'attributs, car un modèle ne devrait probablement être déterminé qu'une seule fois, au début.

53

Ceci est une nouvelle fonctionnalité de Angular versions 1.1.4+. Je viens de découvrir que si j'utilisais la version unstable actuelle (1.1.5), vous pouvez passer une fonction dans l'URL du modèle d'une directive. Le deuxième paramètre de la fonction est la valeur de la directive d'attribut, comme indiqué ci-dessous.

Voici un lien vers le documents non publiés montrant le changement officiel.

Pour utiliser partials/template1.html comme URL de modèle à partir de 

Html:

<div sub_view="template1"></div>

Directif:

.directive('subView', [()->
  restrict: 'A'
  # this requires at least angular 1.1.4 (currently unstable)
  templateUrl: (notsurewhatthisis, attr)->
    "partials/#{attr.subView}.html"
])
16
EpiphanyMachine

J'ai changé la réponse de pkozlowski.opensource un peu.

De:

var boom = $parse(iAttrs.data)(scope);

À:

var boom = scope.data.myData

Cela a fonctionné pour moi et il est possible d'utiliser

<boom data="{{myData}}" /> 

dans la directive.

2
user1947850

J'ai eu le même problème

 return {
        restrict: 'AE',
        templateUrl: function(Elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
        replace: true,

partnersSite.directive('navMenu', function () {
    return {
        restrict: 'AE',
        templateUrl: function(Elm,attrs){return (attrs.scrolled='scrolled' ?'parts/scrolledNav.php':'parts/nav.php')},
        replace: true,
        link: function (scope, Elm, attrs) {
            scope.hidden = true;
            //other logics
        }
    };
});
<nav-menu scrolled="scrolled"></nav-menu>

2
Karb

Cette question sera corrigée avec ng-include comme suit:

MyApp.directive('boom', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: 'isolate',
      locals: { data: 'bind' },
      templateUrl: '<div ng-include="templateUrl"></div>',
      link: function (scope) {
        function switchTemplate(temp) {
          if (temp == 'x')
          { scope.templateUrl = 'XTemplate.html' }
          else if (temp == 'y')
          { scope.templateUrl = 'YTemplate.html' }
        }
      }
    }
});

Appelez la fonction switchTemplate avec le paramètre temp arbitraire dans la fonction link de la directive.

1
Iman Bahrampour

Ceci est une réponse de suivi qui aborde quelques problèmes avec les réponses précédentes. En particulier, il ne compilera les modèles qu'une seule fois (ce qui est important si vous en avez beaucoup sur votre page. Il surveillera les modifications apportées au modèle une fois qu'il aura été lié. Il copie également la classe et le style de l'élément d'origine vers le template (bien que pas de façon très élégante, angular le fait en interne lorsque vous utilisez "replace: true". Contrairement à la méthode prise en charge par angulaire actuelle consistant à utiliser une fonction pour template ou templateUrl, vous pouvez utiliser les informations de portée pour déterminer le modèle à charger.

.directive('boom', ['$http', '$templateCache', '$compile', function ($http, $templateCache, $compile) {
    //create a cache of compiled templates so we only compile templates a single time.
    var cache= {};
    return {
        restrict: 'E',
        scope: {
            Template: '&template'
        },
        link: function (scope, element, attrs) {
            //since we are replacing the element, and we may need to do it again, we need
            //to keep a reference to the element that is currently in the DOM
            var currentElement = element;
            var attach = function (template) {
                if (cache[template]) {
                    //use a cloneAttachFn so that the link function will clone the compiled elment instead of reusing it
                    cache[template](scope, function (e) {
                        //copy class and style
                        e.attr('class', element.attr('class'));
                        e.attr('style', element.attr('style'));
                        //replace the element currently in the DOM
                        currentElement.replaceWith(e);
                        //set e as the element currently in the dom
                        currentElement = e;
                    });
                }
                else {
                    $http.get('/pathtotemplates/' + template + '.html', {
                        cache: $templateCache
                    }).success(function (content) {
                        cache[template] = $compile(content);
                        attach(template);
                    }).error(function (err) {
                        //this is something specific to my implementation that could be customized
                        if (template != 'default') {
                            attach('default');
                        }
                        //do some generic hard coded template
                    });
                }
            };

            scope.$watch("Template()", function (v, o) {
                if (v != o) {
                    attach(v);
                }
            });
            scope.$on('$destroy', function(){
                currentElement.remove();
            });
        }
    };
} ])
1
Joe Enzminger

Ces réponses sont bonnes, mais pas professionnelles. Il existe une syntaxe consistant à utiliser templateUrl, que nous n'utilisons pas souvent .Il peut s'agir d'une fonction qui renvoie une url. Cette fonction a certains arguments. Si vous voulez plus, voici un article cool

http://www.w3docs.com/snippets/angularjs/dynamically-change-template-url-in-angularjs-directives.html

0
Hazarapet Tunanyan