web-dev-qa-db-fra.com

Angular Directive Template différent

J'ai une directive myDirective avec un type de variable. Si je lance <my-directive type="X"> Je veux que la directive utilise templateUrl: x-template.html. Si je fais <my-directive type="Y"> Je veux que la directive utilise templateUrl: y-template.html.

Ceci est ma directive actuelle.

app.directive('myDirective', function() {
    var myDirective = {
        templateUrl: 'X-template.html',
        restrict: 'E',
        scope: {
            type: '=' 
        },
    };
    return myDirective;
});

J'ai lu via stackoverflow et angular mais je n'ai rien trouvé dont j'ai besoin.

J'essaie maintenant de faire quelque chose dans le sens de:

if ($scope.type === 'X') {
    templateUrl: 'X-template.html',
}
else if ($scope.type === 'Y') {
    templateUrl: 'Y-template.html',
}

Mais je ne sais pas où le faire.

Savez-vous si cela est possible et comment?

30
Massive Boisson

Vous pouvez contourner ce problème en utilisant ng-include inside compile:

app.directive('myDirective', function() {
    return {
        restrict: 'E',
        compile: function(element, attrs) {
            element.append('<div ng-include="\'' + attrs.type + '-template.html\'"></div>');
        }
    }
});

violon

25
Mark Rajcok

Angular acceptera une fonction comme option de modèle, vous pouvez donc faire quelque chose comme ceci:

.directive('myDirective', function () {
    return {
        templateUrl: function (tElement, tAttrs) {
            if (tAttrs) {
                if (tAttrs.type === 'X') {
                    return 'X-template.html';
                }
                if (tAttrs.type === 'Y') {
                    return 'Y-template.html';
                }
            }
        }
    }
});

Pour plus d'informations, consultez la documentation du service $ compile .

102
Rob J

Si vous êtes prêt à vivre sur le bord saignant avec une construction sur le chemin du code 1.1.x (notez l'avertissement attaché à chaque entrée de notes de construction 1.1.x donc je ne dilue pas cette réponse en la répétant à nouveau ici), vous nous avons de la chance - cette fonctionnalité vient d'être ajoutée dans la version 1.1.4 le 3 avril. Vous pouvez trouver les notes de publication pour 1.1.4 ici et la fonctionnalité journal des tâches inclut un test Jasmine qui montre comment utiliser la nouvelle fonctionnalité.

Si vous êtes plus conservateur et utilisez une version 1.0.x, vous ne pourrez pas accomplir cela aussi facilement, mais cela peut être fait. La solution de Mark Rajcok semble correspondre à vos besoins, comme indiqué, mais j'ajouterais simplement quelques notes supplémentaires:

  • Mis à part sa version 1.1.4, les directives de compilation ne prennent pas en charge la modification au moment de l'exécution.
  • Vous voudrez peut-être considérer replaceWith() au lieu de append() puisque <my-directive> N'est pas un type d'élément HTML défini par défaut.
  • Si vos modèles X et Y contiennent des directives supplémentaires, je ne pense pas que vous serez en mesure de transmettre si facilement des attributs sur <my-template> À l'élément racine de votre modèle.
    • Une directive avec replace: true transfèrera les attributs de l'élément source à sa racine de remplacement, mais je ne pense pas que ngInclude fera de même de l'hôte à la racine du modèle inclus.
    • Il me semble également que ngInclude n'exige pas que son modèle ait exactement un élément racine.
    • Vous pouvez peut-être conserver les attributs d'un parent de remplacement en utilisant replaceWith() au lieu de append() et en enveloppant la balise <div ng-include=""> Dans un <div></div>. Le <div> Externe pourrait contenir des attributs et serait toujours accessible après que l'élément <div ngInclude> Se soit remplacé par du contenu chargé.
  • Sachez que ngInclude crée une nouvelle étendue. Cela vous soumet à un avertissement de klaxons jaune clignotant sur les dangers des modèles de portée primitifs. Pour plus d'informations, voir cette belle page du dépôt GitHub d'Angular .

Je peux proposer une autre alternative pour ceux sur 1.0.x, mais cela implique une bonne quantité de code. C'est une opération plus lourde, mais elle a l'avantage non seulement de pouvoir basculer entre les modèles, mais aussi de directives à part entière. De plus, son comportement est plus facilement dynamique.

app.directive('myDirective', function() {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'partials/directive/my-directive.html',
        link: function(scope, element, attrs, ctrl) {
            // You can do this with isolated scope as well of course.
            scope.type = attrs.type;
        }
    }
);

my-directive.js

<div ng-switch on="{{type}}">
    <div ng-switch-where="X" ng-include="X-template.html"></div>
    <div ng-switch-where="Y" ng-include="Y-template.html"></div>
</div>

my-directive.html

7
John Heinnickel

Ceci est ma version pour éventuellement remplacer un modèle par défaut

templateUrl: function (elem, attrs) {
  if (attrs.customTemplate) {
    return '/path/to/components/tmpl/' + attrs.customTemplate + '.html';
  } else {
    return '/path/to/components/tmpl/directive.html';
  }
}

par exemple sur une directive

<div my-directive custom-template="custom"></div>
5
Joel Davey

Je résous ce problème donc:

app.directive("post", function ($templateCache, $compile) {
function getTemplate(mode) {
    switch (mode) {
        case "create":
            return "createPost.html";
        case "view":
            return "viewPost.html";
        case "delete":
            return "deletePost.html";
    }
}

var defaultMode = "view";

return {
    scope: {},
    restrict: "AE",
    compile: function (elem, attrs, transclude) {
        return function ($scope, $element, $attr) {
            function updateTemplate() {
                $element.html("");
                $compile($templateCache.get(getTemplate($scope.mode)).trim())($scope, function (clonedElement, scope) {
                    clonedElement.appendTo($element);

                });
            }

            $scope.mode = $attr.mode || defaultMode;

            $scope.$watch("mode", updateTemplate);
        }
    }
}
});

Ce n'est probablement pas la meilleure façon de le faire, mais je n'ai pas de portée supplémentaire.

4
Anton Rodin