Заменить узел ng-include шаблоном?


85

Вроде новичок в angular. Можно ли заменить узел ng-include содержимым включенного шаблона? Например, с:

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

Сгенерированный html:

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

Но я хочу:

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

1
удалите одинарные кавычки из, 'test.html'чтобы использовать шаблон, а не URL-адрес
charlietfl

1
читая комментарии к документу для ng-include, кажется, что строка заключена в одинарные кавычки для шаблона и без для url. Кроме того, связанный вопрос о stackoverflow
SunnySydeUp

вы читаете документы и
публикуете ссылку

Ответы:


134

У меня была такая же проблема, и я все еще хотел, чтобы функции ng-include включали динамический шаблон. Я создавал динамическую панель инструментов Bootstrap, и мне нужна была более чистая разметка для правильного применения стилей CSS.

Вот решение, которое я придумал для тех, кому интересно:

HTML:

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

Специальная директива:

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

Если бы это решение использовалось в приведенном выше примере, установка для scope.dynamicTemplatePath значения 'test.html' привела бы к желаемой разметке.


Требуется angular v1.2 +
colllin


Это работает для angular 1.2.5+. Для 1.2.4, если у вас есть один ng-include, который ng-include другой, он не работает. Я предполагаю из-за # 5247 , но не уверен. Посмотрите список изменений . Вот Plunkr, демонстрирующий эту проблему с 1.2.4 (перейдите на angular 1.2.5 и посмотрите, как он работает! :-)
Питер В. Мёрч

9
Обратите внимание, что такая манипуляция с DOM довольно хакерская. Проблема возникает, если корневой элемент включенного шаблона использует что-то вроде ng-repeat. Он не сможет вставить результаты в DOM.
Гурия

1
Пожалуйста, посмотрите мой ответ на это, это не удастся, потому что функция предварительной ссылки уже запущена в дочерних элементах.
Сай Дуббака

28

Итак, благодаря @ user1737909 я понял, что ng-include - это не выход. Директивы - лучший и более ясный подход.

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

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

В html:

<blah></blah>

2
Благодарность! искал решение ng-include, но это помогло мне понять, что директивы лучше
Мэтт Ким

Имейте в виду, что replace:trueв шаблонах отмечена отметка о прекращении поддержки . Я бы не стал использовать это решение из-за статуса устаревшего.
Питер В. Мёрч

@ PeterV.Mørch Спасибо. Для заинтересованных это коммит: github.com/angular/angular.js/commit/… . Похоже, он устарел из-за его сложности (и, возможно, по другим причинам).
SunnySydeUp

15

У меня была такая же проблема, моей сторонней таблице стилей css не понравился дополнительный элемент DOM.

Мое решение было супер-простым. Просто переместите ng-include 1 вверх. Так что вместо

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

Я просто сделал:

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

Готов поспорить, это сработает в большинстве ситуаций, даже если технически вопрос не в этом.


10

Другая альтернатива - написать собственную простую директиву replace / include, например

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

Затем это будет использоваться следующим образом:

<div my-replace="test.html"></div>

9

Это правильный способ замены детей

angular.module('common').directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A',
        compile: function (tElement, tAttrs) {
            tElement.replaceWith(tElement.children());
            return {
                post : angular.noop
            };
        }
    };
});

4
Мой включенный частичный html получил несколько повторений ng-repeat, и это единственный ответ, разрешающий их! Большое спасибо.
Саад Бенбузид

Мне пришлось переместить содержимое функции из compileв link, потому что на этапе компиляции мой элемент был пуст.
Итачи

3

Следующая директива расширяет функциональность нативной директивы ng-include.

Он добавляет прослушиватель событий для замены исходного элемента, когда контент готов и загружен.

Используйте его как обычно, просто добавьте атрибут «заменить»:

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

или с обозначением атрибута:

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

Вот директива (не забудьте включить модуль 'include-replace' как зависимость):

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

2

Я бы выбрал более безопасное решение, чем то, которое предлагает @Brady Isom.

Я предпочитаю полагаться на предоставленную onloadопцию, ng-includeчтобы убедиться, что шаблон загружен, прежде чем пытаться его удалить.

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

Нет необходимости во второй директиве, поскольку все обрабатывается внутри первой.


имейте в виду, что с angular 1.5 первым дочерним элементом в директивном элементе является комментарий. Поэтому я удостоверился, что получил элемент ng-include, а затем заменил его его let ngInclude = angular.element( element[ 0 ].querySelector( 'ng-include' ) ); ngInclude.replaceWith( ngInclude.children() );
дочерними элементами
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.