Angular.js directive templateURL dynamique

169

J'ai une balise personnalisée dans un routeProvidermodèle qui appelle un directivemodèle. L' versionattribut sera rempli par la portée qui appelle ensuite le bon modèle.

<hymn ver="before-{{ week }}-{{ day }}"></hymn>

Il existe plusieurs versions de l'hymne en fonction de la semaine et du jour. J'avais l'intention d'utiliser la directive pour remplir la bonne .htmlpartie. La variable n'est pas lue par le templateUrl.

emanuel.directive('hymn', function() {
    var contentUrl;
    return {
        restrict: 'E',
        link: function(scope, element, attrs) {
            // concatenating the directory to the ver attr to select the correct excerpt for the day
            contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
        },
        // passing in contentUrl variable
        templateUrl: contentUrl
    }
});

Il y a plusieurs fichiers dans le répertoire des extraits qui sont étiquetés before-1-monday.html, before-2-tuesday.html...

Alen Giliana
la source
1
duplication possible de Dynamic templateUrl - AngularJS
Nick Grealy
si vous utilisez AngularJS 1.5+, vérifiez cette solution élégante: stackoverflow.com/a/41743424/1274852
hkong

Réponses:

184

Vous pouvez utiliser la ng-includedirective.

Essayez quelque chose comme ceci:

emanuel.directive('hymn', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           scope.getContentUrl = function() {
                return 'content/excerpts/hymn-' + attrs.ver + '.html';
           }
       },
       template: '<div ng-include="getContentUrl()"></div>'
   }
});

UPD. pour regarder l' verattribut

emanuel.directive('hymn', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           scope.contentUrl = 'content/excerpts/hymn-' + attrs.ver + '.html';
           attrs.$observe("ver",function(v){
               scope.contentUrl = 'content/excerpts/hymn-' + v + '.html';
           });
       },
       template: '<div ng-include="contentUrl"></div>'
   }
});
agrégation
la source
1
Sa excellente solution. Existe-t-il un moyen de l'écrire pour qu'il puisse gérer plusieurs instances? Actuellement, une fois la portée définie, elle ne reconnaît pas les nouveaux attrs.ver.
Alen Giliana
1
Vous voulez dire, vous voulez regarder les verchangements d'attribut et la directive de rendu?
pgregory
1
Merci d'avoir clarifié. Si vous déclarez la directive comme publiée dans upd., Votre cas d'utilisation lorsque vous utilisez multiple <hymn ...>devrait bien fonctionner. Ou peut-être qu'il est temps de construire un prototype chez jsfilddle ?
pgregory
1
Bonjour @AlenGiliana, je porte ve take a look at your site, and changed [JSFiddle](http://jsfiddle.net/JQgG5/6/). All you need is : {} `dans la déclaration de directive - isolation de la portée . Aussi, je vous recommande fortement d'utiliser la dernière version d'angular. <script type="text/ng-template" id="...">- est une alternative locale aux pages html
pgregory
1
Voulez-vous utiliser Angular 1.2.1? Merci pour l'aide au fait, cette courbe d'apprentissage est folle :)
Alen Giliana
313
emanuel.directive('hymn', function() {
   return {
       restrict: 'E',
       link: function(scope, element, attrs) {
           // some ode
       },
       templateUrl: function(elem,attrs) {
           return attrs.templateUrl || 'some/path/default.html'
       }
   }
});

Ainsi, vous pouvez fournir templateUrl via le balisage

<hymn template-url="contentUrl"><hymn>

Maintenant, veillez simplement à ce que la propriété contentUrl soit remplie avec un chemin généré dynamiquement.

Andrej Kaurin
la source
4
Bien, mais ... puis-je accéder aux attributs de portée à partir de la fonction templateUrl? Le templateUrl dépend d'une valeur de portée, mais je ne peux pas y accéder :(
josec89
1
Je suis heureux que vous ayez trouvé une solution. Je ne recommanderais PAS que la directive dépende de son parent sauf si elle est définie par un contrôleur dans une partie requise de la directive.
Andrej Kaurin
11
Finalement! Exactement ce que je cherchais! Je ne savais pas que j'avais accès à elem et attrs à partir d'une fonction templateUrl. MERCI!
coryvb123
7
templateUrl est appelé une fois par directive, il n'est pas appelé à chaque initialisation d'instance de directive, attention !!! Cela peut être un bug angulaire cependant ...
Lu4
2
Je ne l'ai pas encore vérifié, mais d'après mes dernières découvertes, il vaut probablement la peine de le mentionner once per $compile phase. En d'autres termes, si vous utilisez ng-repeatavec votre directive et que vous souhaitez définir un modèle individuel en fonction ng-repeatdu contexte d'élément spécifique , cela ne fonctionnera pas, car la $compilephase parcourt votre directive une fois avant que la réalité ne ng-repeatse produise. Donc, dans ce sens, il est appelé une fois ...
Lu4
6

Grâce à @pgregory, j'ai pu résoudre mon problème en utilisant cette directive pour l'édition en ligne

.directive("superEdit", function($compile){
    return{
        link: function(scope, element, attrs){
            var colName = attrs["superEdit"];
            alert(colName);

            scope.getContentUrl = function() {
                if (colName == 'Something') {
                    return 'app/correction/templates/lov-edit.html';
                }else {
                    return 'app/correction/templates/simple-edit.html';
                }
            }

            var template = '<div ng-include="getContentUrl()"></div>';

            var linkFn = $compile(template);
            var content = linkFn(scope);
            element.append(content);
        }
    }
})
Shilan
la source
5

Vous n'avez pas besoin de directive personnalisée ici. Utilisez simplement l' attribut ng-include src. Il est compilé pour que vous puissiez y insérer du code. Consultez plunker avec une solution à votre problème.

<div ng-repeat="week in [1,2]">
  <div ng-repeat="day in ['monday', 'tuesday']">
    <ng-include src="'content/before-'+ week + '-' + day + '.html'"></ng-include>
  </div>
</div>
icem
la source
2

J'ai eu le même problème et je l'ai résolu d'une manière légèrement différente des autres. J'utilise angulaire 1.4.4.

Dans mon cas, j'ai un modèle de shell qui crée un panneau CSS Bootstrap:

<div class="class-container panel panel-info">
    <div class="panel-heading">
        <h3 class="panel-title">{{title}} </h3>
    </div>
    <div class="panel-body">
        <sp-panel-body panelbodytpl="{{panelbodytpl}}"></sp-panel-body>
    </div>
</div>

Je souhaite inclure des modèles de corps de panneau en fonction de l'itinéraire.

    angular.module('MyApp')
    .directive('spPanelBody', ['$compile', function($compile){
        return {
            restrict        : 'E',
            scope : true,
            link: function (scope, element, attrs) {
                scope.data = angular.fromJson(scope.data);
                element.append($compile('<ng-include src="\'' + scope.panelbodytpl + '\'"></ng-include>')(scope));
            }
        }
    }]);

J'ai alors le modèle suivant inclus lorsque l'itinéraire est #/students:

<div class="students-wrapper">
    <div ng-controller="StudentsIndexController as studentCtrl" class="row">
        <div ng-repeat="student in studentCtrl.students" class="col-sm-6 col-md-4 col-lg-3">
            <sp-panel 
            title="{{student.firstName}} {{student.middleName}} {{student.lastName}}"
            panelbodytpl="{{'/student/panel-body.html'}}"
            data="{{student}}"
            ></sp-panel>
        </div>
    </div>
</div>

Le modèle panel-body.html comme suit:

Date of Birth: {{data.dob * 1000 | date : 'dd MMM yyyy'}}

Exemples de données dans le cas où quelqu'un voudrait essayer:

var student = {
    'id'            : 1,
    'firstName'     : 'John',
    'middleName'    : '',
    'lastName'      : 'Smith',
    'dob'           : 1130799600,
    'current-class' : 5
}
igasparetto
la source
0

J'ai un exemple à ce sujet.

<!DOCTYPE html>
<html ng-app="app">

  <head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  </head>

  <body>
    <div class="container-fluid body-content" ng-controller="formView">
        <div class="row">
            <div class="col-md-12">
                <h4>Register Form</h4>
                <form class="form-horizontal" ng-submit="" name="f" novalidate>
                    <div ng-repeat="item in elements" class="form-group">
                        <label>{{item.Label}}</label>
                        <element type="{{item.Type}}" model="item"></element>
                    </div>
                    <input ng-show="f.$valid" type="submit" id="submit" value="Submit" class="" />
                </form>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
    <script src="app.js"></script>
  </body>

</html>

angular.module('app', [])
    .controller('formView', function ($scope) {
        $scope.elements = [{
            "Id":1,
            "Type":"textbox",
            "FormId":24,
            "Label":"Name",
            "PlaceHolder":"Place Holder Text",
            "Max":20,
            "Required":false,
            "Options":null,
            "SelectedOption":null
          },
          {
            "Id":2,
            "Type":"textarea",
            "FormId":24,
            "Label":"AD2",
            "PlaceHolder":"Place Holder Text",
            "Max":20,
            "Required":true,
            "Options":null,
            "SelectedOption":null
        }];
    })
    .directive('element', function () {
        return {
            restrict: 'E',
            link: function (scope, element, attrs) {
                scope.contentUrl = attrs.type + '.html';
                attrs.$observe("ver", function (v) {
                    scope.contentUrl = v + '.html';
                });
            },
            template: '<div ng-include="contentUrl"></div>'
        }
    })
Ddagsan
la source