Angular.js Direktive dynamic templateURL

169

Ich habe ein benutzerdefiniertes Tag in einer routeProviderVorlage, das eine directiveVorlage erfordert. Das versionAttribut wird mit dem Bereich gefüllt, der dann die richtige Vorlage anfordert.

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

Es gibt mehrere Versionen der Hymne, basierend auf der Woche und dem Tag. Ich hatte erwartet, die Direktive zu verwenden, um den richtigen .htmlTeil zu füllen. Die Variable wird von der nicht gelesen 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
    }
});

Es gibt mehrere Dateien in Auszügen Verzeichnis , das gekennzeichnet ist before-1-monday.html, before-2-tuesday.html...

Alen Giliana
quelle
1
mögliches Duplikat von Dynamic templateUrl - AngularJS
Nick Grealy
Wenn Sie AngularJS 1.5+ verwenden, überprüfen Sie diese elegante Lösung: stackoverflow.com/a/41743424/1274852
hkong

Antworten:

184

Sie können die ng-includeDirektive verwenden.

Versuchen Sie so etwas:

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. zum Beobachten 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>'
   }
});
pgregory
quelle
1
Seine großartige Lösung. Gibt es eine Möglichkeit, es so zu schreiben, dass es mehrere Instanzen verarbeiten kann? Derzeit erkennt der festgelegte Bereich keine neuen attrs.ver mehr.
Alen Giliana
1
Sie meinen, Sie möchten verAttributänderungen und die Anweisung zum erneuten Rendern beobachten?
Pgregory
1
Danke für das Aufklären. Wenn Sie die Direktive so deklarieren, wie sie in upd. Veröffentlicht wird, sollte Ihr Anwendungsfall, wenn Sie mehrere <hymn ...>verwenden, gut funktionieren. Oder ist es vielleicht an der Zeit, bei jsfilddle einen Prototyp zu bauen ?
Pgregory
1
Hallo @AlenGiliana, ich ve take a look at your site, and changed [JSFiddle](http://jsfiddle.net/JQgG5/6/). All you need is Umfang: {} `in Direktivendeklaration - Bereichsisolation . Außerdem empfehle ich Ihnen dringend, die letzte Version von Angular zu verwenden. <script type="text/ng-template" id="...">- ist lokale Alternative zu HTML-Seiten
Pgregory
1
Wollen Sie Angular 1.2.1 verwenden? Vielen Dank für die Hilfe übrigens, diese Lernkurve ist verrückt :)
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'
       }
   }
});

So können Sie templateUrl per Markup bereitstellen

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

Jetzt müssen Sie nur noch darauf achten, dass die Eigenschaft contentUrl mit einem dynamisch generierten Pfad gefüllt wird.

Andrej Kaurin
quelle
4
Schön, aber ... kann ich über die Funktion templateUrl auf Bereichsattribute zugreifen? Die templateUrl hängt von einem Gültigkeitsbereich ab, aber ich kann nicht darauf zugreifen :(
josec89
1
Ich bin froh, dass Sie eine Lösung gefunden haben. Ich würde NICHT empfehlen, dass die Direktive von ihrem übergeordneten Element abhängig ist, es sei denn, es handelt sich um einen Controller, für den ein Teil der Direktive erforderlich ist.
Andrej Kaurin
11
Schließlich! Genau das, wonach ich gesucht habe! Ich wusste nicht, dass ich über eine templateUrl-Funktion Zugriff auf elem und attrs hatte. VIELEN DANK!
Coryvb123
7
templateUrl wird einmal pro Direktive aufgerufen, es wird nicht bei jeder Initialisierung der Direktiveninstanz aufgerufen, seien Sie vorsichtig !!! Es kann jedoch ein Fehler im Winkel sein ...
Lu4
2
Ich habe es noch nicht überprüft, aber nach meinen neuesten Erkenntnissen ist es wahrscheinlich erwähnenswert, dass es so ist once per $compile phase. Mit anderen Worten, wenn Sie ng-repeatmit Ihrer Direktive arbeiten und eine individuelle Vorlage basierend auf einem bestimmten ng-repeatElementkontext festlegen möchten, funktioniert dies nicht, da die $compilePhase Ihre Direktive einmal durchläuft, bevor dies tatsächlich ng-repeatgeschieht. In diesem Sinne wird es einmal aufgerufen ...
Lu4
6

Dank @pgregory konnte ich mein Problem mit dieser Direktive für die Inline-Bearbeitung lösen

.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
quelle
5

Sie benötigen hier keine benutzerdefinierte Direktive. Verwenden Sie einfach das Attribut ng-include src. Es ist kompiliert, damit Sie Code einfügen können. Siehe Plunker mit Lösung für Ihr Problem.

<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
quelle
2

Ich hatte das gleiche Problem und löste es auf eine etwas andere Weise als die anderen. Ich benutze Winkel 1.4.4.

In meinem Fall habe ich eine Shell-Vorlage, die ein CSS-Bootstrap-Bedienfeld erstellt:

<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>

Ich möchte je nach Route Panel-Body-Vorlagen einfügen.

    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));
            }
        }
    }]);

Ich habe dann die folgende Vorlage enthalten, wenn die Route ist #/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>

Die Vorlage panel-body.html lautet wie folgt:

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

Beispieldaten für den Fall, dass jemand etwas ausprobieren möchte:

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

Ich habe ein Beispiel dafür.

<!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
quelle