Ng-include-Knoten durch Vorlage ersetzen?

85

Ein bisschen neu in eckigen. Ist es möglich, den Knoten ng-include durch den Inhalt der enthaltenen Vorlage zu ersetzen ? Zum Beispiel mit:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <div ng-include src="'test.html'"></div>
</div>

Das generierte HTML ist:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <div ng-include src="'test.html'">
        <span class="ng-scope"> </span>
        <p>Test</p>
        <span class="ng-scope"> </span>
    </div>
</div>

Aber was ich will ist:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <p>Test</p>
</div>
SunnySydeUp
quelle
1
Entfernen Sie einfache Anführungszeichen aus 'test.html', um die Vorlage anstelle der URL zu verwenden
charlietfl
1
Beim Lesen der Kommentare des Dokuments für ng-include scheint es, dass die Zeichenfolge mit einfachen Anführungszeichen für die Vorlage und ohne Anführungszeichen für die URL umgeben ist. Auch verwandte Stapelüberlauf Frage
SunnySydeUp
Sie lesen Dokumente und posten, die Sie rückwärts verlinkt haben
charlietfl

Antworten:

134

Ich hatte das gleiche Problem und wollte immer noch, dass die Funktionen von ng-include eine dynamische Vorlage enthalten. Ich habe eine dynamische Bootstrap-Symbolleiste erstellt und brauchte das sauberere Markup, damit die CSS-Stile richtig angewendet werden können.

Hier ist die Lösung, die ich für Interessierte gefunden habe:

HTML:

<div ng-include src="dynamicTemplatePath" include-replace></div>

Benutzerdefinierte Richtlinie:

app.directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A', /* optional */
        link: function (scope, el, attrs) {
            el.replaceWith(el.children());
        }
    };
});

Wenn diese Lösung im obigen Beispiel verwendet würde, würde das Setzen von scope.dynamicTemplatePath auf 'test.html' zum gewünschten Markup führen.

Brady Isom
quelle
Benötigt Winkel v1.2 +
Colllin
Ich habe diese Antwort in einer ähnlichen Frage referenziert
Peter V. Mørch
Dies funktioniert für Winkel 1.2.5+. In 1.2.4 schlägt ein fehlgeschlagenes ng-include fehl, das ein anderes ng-include enthält. Ich vermute wegen # 5247 , bin mir aber nicht sicher. Siehe Changelog für sich. Hier ist ein Plunkr , der dieses Problem mit 1.2.4 demonstriert (Wechsel zu Winkel 1.2.5 und sehen, dass es funktioniert! :-)
Peter V. Mørch
9
Beachten Sie, dass eine solche DOM-Manipulation ziemlich hackig ist. Es gibt ein Problem, wenn das Stammelement der enthaltenen Vorlage so etwas wie ng-repeat verwendet. Es können keine Ergebnisse in DOM eingefügt werden.
Guria
1
Bitte sehen Sie meine Antwort darauf, dies wird fehlschlagen, da die Prelink-Funktion bereits in untergeordneten Elementen ausgeführt wurde.
Sai Dubbaka
28

Dank @ user1737909 habe ich erkannt, dass ng-include nicht der richtige Weg ist. Richtlinien sind der bessere Ansatz und expliziter.

var App = angular.module('app', []);

App.directive('blah', function() {
    return {
        replace: true,
        restrict: 'E',  
        templateUrl: "test.html"
    };
});

In HTML:

<blah></blah>
SunnySydeUp
quelle
2
Vielen Dank! Ich suchte nach einer ng-include-Lösung, aber dies half mir zu erkennen, dass Direktiven besser sind
Matt Kim
Beachten Sie, dass replace:truein Vorlagen als veraltet markiert ist . Ich würde diese Lösung aufgrund des Verfallsstatus vermeiden.
Peter V. Mørch
@ PeterV.Mørch Danke. Für Interessenten ist dies das Commit: github.com/angular/angular.js/commit/… . Es scheint, als wäre es wegen seiner Komplexität (und vielleicht aus anderen Gründen) veraltet.
SunnySydeUp
15

Ich hatte das gleiche Problem, mein CSS-Stylesheet von Drittanbietern mochte das zusätzliche DOM-Element nicht.

Meine Lösung war super einfach. Bewegen Sie einfach das ng-include 1 nach oben. Also statt

<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')">
  <div ng-include="myService.template"></span>
</md-sidenav>

Ich habe einfach getan:

<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')" ng-include="myService.template">
</md-sidenav>

Ich wette, das wird in den meisten Situationen funktionieren, auch wenn es technisch nicht das ist, was die Frage stellt.

xeor
quelle
10

Eine andere Alternative besteht darin, eine eigene einfache Ersetzungs- / Einschlussrichtlinie zu schreiben, z

    .directive('myReplace', function () {
               return {
                   replace: true,
                   restrict: 'A',
                   templateUrl: function (iElement, iAttrs) {
                       if (!iAttrs.myReplace) throw new Error("my-replace: template url must be provided");
                       return iAttrs.myReplace;
                   }
               };
           });

Dies würde dann wie folgt verwendet:

<div my-replace="test.html"></div>
Daniel Egan
quelle
9

Dies ist der richtige Weg, um die Kinder zu ersetzen

angular.module('common').directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A',
        compile: function (tElement, tAttrs) {
            tElement.replaceWith(tElement.children());
            return {
                post : angular.noop
            };
        }
    };
});
Sai Dubbaka
quelle
4
Mein enthaltenes partielles HTML hat einige ng-Wiederholungen erhalten, und dies ist die einzige Antwort, die sie löst! Vielen Dank.
Saad Benbouzid
Ich musste den Funktionsinhalt von compilenach verschieben link, da mein Element während der Kompilierungsphase leer war.
Itachi
3

Die folgende Direktive erweitert die native Direktivenfunktionalität von ng-include.

Es wird ein Ereignis-Listener hinzugefügt, der das ursprüngliche Element ersetzt, wenn der Inhalt bereit und geladen ist.

Verwenden Sie es auf die ursprüngliche Weise, fügen Sie einfach das Attribut "Ersetzen" hinzu:

<ng-include src="'src.html'" replace></ng-include>

oder mit Attributnotation:

<div ng-include="'src.html'" replace></div>

Hier ist die Direktive (denken Sie daran, das Modul 'include-replace' als Abhängigkeit einzuschließen):

angular.module('include-replace', []).directive('ngInclude', function () {
    return {
        priority: 1000,
        link: function($scope, $element, $attrs){

            if($attrs.replace !== undefined){
                var src = $scope.$eval($attrs.ngInclude || $attrs.src);

                var unbind = $scope.$on('$includeContentLoaded', function($event, loaded_src){
                    if(src === loaded_src){
                        $element.next().replaceWith($element.next().children());
                        unbind();
                    };
                });
            }
        }
    };
});
Edrian
quelle
2

Ich würde eine sicherere Lösung wählen als die von @Brady Isom.

Ich ziehe es vor, mich auf die onloadOption von ng-includezu verlassen, um sicherzustellen, dass die Vorlage geladen ist, bevor ich versuche, sie zu entfernen.

.directive('foo', [function () {
    return {
        restrict: 'E', //Or whatever you need
        scope: true,
        template: '<ng-include src="someTemplate.html" onload="replace()"></ng-include>',
        link: function (scope, elem) {
            scope.replace = function () {
                elem.replaceWith(elem.children());
            };
        }
    };
}])

Keine zweite Richtlinie erforderlich, da alles innerhalb der ersten behandelt wird.

Masadow
quelle
Beachten Sie, dass bei Winkel 1.5 das erste untergeordnete Element im Direktivenelement ein Kommentar ist. Also habe ich dafür gesorgt, dass ich das ng-include-Element bekomme und es dann durch seine Kinder ersetze: let ngInclude = angular.element( element[ 0 ].querySelector( 'ng-include' ) ); ngInclude.replaceWith( ngInclude.children() );
Mattijs