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


85

Своєрідно нове для кутового. Чи можна замінити вузол 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

Ви читаєте документи та публікацію, до якої посилаєтесь назад
charlietfl

Відповіді:


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


Це працює для кутових 1.2.5+. Для 1.2.4, якщо у вас є одне ng-include, що ng-включає інше, це не вдається. Я здогадуюсь через # 5247 , але я не впевнений. Дивіться журнал змін самостійно. Ось Plunkr, який демонструє цю проблему з 1.2.4 (змініть на angular 1.2.5 і переконайтеся, що це працює! :-)
Peter V. Mørch

9
Зверніть увагу, що подібні маніпуляції з DOM досить хакі. Є проблема, якщо кореневий елемент включеного шаблону використовує щось на зразок ng-repeat. Він не зможе вставити результати в DOM.
Guria

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в шаблонах позначено застарілість . Я б уникнув використання цього рішення через статус застарілості.
Peter V. Mørch

@ 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

Інша альтернатива - написати власну просту директиву заміна / включення, наприклад

    .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-повтор, і це єдина відповідь, яка їх вирішує! Дуже дякую.
Саад Бенбузид,

Мені довелося перенести вміст функції з compileна link, оскільки мій елемент був порожнім на етапі компіляції.
itachi

3

Наступна директива розширює функцію ng-include.

Він додає прослуховувач подій для заміни вихідного елемента, коли вміст готовий і завантажений.

Використовуйте його оригінальним способом, просто додайте атрибут "replace":

<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() );
Mattijs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.