2013-07-11 1 views
22
.

. Я изо всех сил пытаюсь задуматься о том, как включить ng-include, не использовать дополнительный элемент DOM, поскольку я создаю угловое приложение из простой HTML-демонстрации. Я работаю с довольно тонким HTML с полностью разработанным, тесно связанным с DOM CSS (построен из SASS), и рефакторинг - это то, чего я хочу избежать любой ценой.Избегайте использования дополнительных узлов DOM при использовании nginclude.

Вот фактический код:

<div id="wrapper"> 
    <header 
     ng-controller="HeaderController" 
     data-ng-class="headerType" 
     data-ng-include="'/templates/base/header.html'"> 
    </header> 
    <section 
     ng-controller="SubheaderController" 
     data-ng-class="subheaderClass" 
     ng-repeat="subheader in subheaders" 
     data-ng-include="'/templates/base/subheader.html'"> 
    </section> 
    <div 
     class="main" 
     data-ng-class="mainClass" 
     data-ng-view> 
    </div> 
</div> 

мне нужно < раздел > быть повторяющийся элемент, но имеет свою собственную логику и различное содержание. Оба, содержание и количество повторений зависят от бизнес-логики. Как вы можете видеть, установка ng-контроллера и ng-repeat на < раздел > элемент не будет работать. Что бы было, однако, вставить новый узел DOM, чего я пытаюсь избежать.

Что я упускаю? Это лучшая практика или есть лучший способ?


EDIT: только уточнить, как просили в комментариях, окончательный HTML Я пытаюсь создать бы:

<div id="wrapper"> 
    <header>...</header> 
    <section class="submenuX"> 
     some content from controller A and template B (e.g. <ul>...</ul>) 
    </section> 
    <section class="submenuY"> 
     different content from same controller A and template B (e.g. <div>...</div>) 
    </section> 
    <section class="submenuZ"> 
     ... (number of repetitions is defined in controller A e.g. through some service) 
    </section> 

    <div>...</div> 
</div> 

причина, почему я хочу, чтобы использовать тот же шаблон B (подзаголовок .html), предназначен для чистоты кода. Я заставляю subheader.html иметь какой-то ng-переключатель, чтобы возвращать динамический контент.

Но в основном, подстилающий quiestion: есть ли способ включить содержимое шаблона прозрачно, без использования узла DOM?


EDIT2: Раствор должен быть повторно. =)

+0

Можете ли вы добавить пример вариации, теперь убедитесь, что вы просите? – Chandermani

+0

Извините за это. Отредактировано для уточнения. –

+0

Вы можете использовать ng-include в качестве тега '' и не помечать тег, отличный от содержимого 'url'. – Chandermani

ответ

25

Некоторые другие ответы предполагают replace:true, но имейте в виду, что replace:true в шаблонах marked for deprecation.

Вместо этого в an answer to a similar question, мы находим альтернативу: Это позволяет написать:

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

(cut'n'paste от другого ответа)

+1

Не будет работать с динамическим контентом (ng-repeat, ...). Обновите и используйте этот предпочтительный ответ, который работал для меня: http://stackoverflow.com/a/33508032/704246 –

6

Вы можете создать пользовательскую директиву, ссылки на шаблон с templateUrl собственности и установка replace в true:

app.directive('myDirective', function() { 
    return { 
    templateUrl: 'url/to/template', 
    replace: true, 
    link: function(scope, elem, attrs) { 

    } 
    } 
}); 

Это будет включать в шаблон как есть, без каких-либо обертки элемента, без любой объем оболочки.

+0

Есть ли способ сделать templateUrl динамическим, чтобы я мог повторно использовать директиву? –

+0

На данный момент нет. По крайней мере, не из коробки. Я слышал о некоторых обходных решениях, которые я бы не рекомендовал. @filiptc – finishingmove

+0

Я предполагаю, что вы имеете в виду следующее: https://github.com/angular/angular.js/issues/1039 Кажется возможным в angularjs> = 1.1.4 –

20

Редактировать: После некоторых исследований и для полноты, я добавил некоторую информацию. Так как 1.1.4, следующие работы:

app.directive('include', 
    function() { 
     return { 
      replace: true, 
      restrict: 'A', 
      templateUrl: function (element, attr) { 
       return attr.pfInclude; 
      } 
     }; 
    } 
); 

Использование:

<div include="'path/to/my/template.html'"></div> 

Существует, однако, один Гоча: шаблон не может быть динамическим (как, проходя через переменную сферу, поскольку $ scope или любой DI, в этом случае недоступен в templateUrl - см. this issue), только строка может быть передана (как и html-фрагмент выше).Чтобы обойти эту конкретную проблему, этот кусок кода следует сделать трюк (престижность this plunker):

app.directive("include", function ($http, $templateCache, $compile) { 
    return { 
     restrict: 'A', 
     link: function (scope, element, attributes) { 
      var templateUrl = scope.$eval(attributes.include); 
      $http.get(templateUrl, {cache: $templateCache}).success(
       function (tplContent) { 
        element.replaceWith($compile(tplContent.data)(scope)); 
       } 
      ); 
     } 
    }; 
}); 

Использование:

<div include="myTplVariable"></div> 
+0

Мне пришлось бы утверждать, что мое решение все еще лучше для того, что было актуальным вопросом. Если это сработает для вас, то хорошо. – finishingmove

+0

Ваш ответ абсолютно в порядке и поставил меня в правильном направлении (правда!). Мне просто нужно, чтобы эта функция была повторно использована вдоль всей моей структуры шаблонов. Я не могу позволить объявить одну новую директиву для каждого из них. –

+0

... это совсем другое дело (и не упоминалось - или я не читал хорошо?) :) Поскольку вы в основном повторно изобрели «ng-include» с этим, проверьте его источник, если вы столкнулись с проблемами по пути. Cheers :) – finishingmove

1

Для тех, кто случается посетить этот вопрос:

С угловым 1.1.4+ вы можете использовать функцию в шаблонеURL, чтобы сделать ее динамичной.

Проверьте этот другой ответ here

0

С правой настройкой, вы можете определить свою собственную ngInclude директивы, которая может работать вместо одной представленного Angular.js и предотвратить встроенную директиву для выполнения когда-либо.

Для предотвращения директивы угловой встроенный от исполнения имеет решающее значение, чтобы установить приоритет вашей директивы выше, чем у встроенного в директиве (400 для ngInclude и установите terminal свойство true.

После что вам необходимо для обеспечения функции пост-ссылку, которая извлекает шаблон и заменяет узел DOM элемента с скомпилированного шаблона HTML

слово предупреждения:. это довольно безжалостный, вы переопределить поведение ngInclude для все ваше приложение. Поэтому я устанавливаю директиву b elow не на myApp, но внутри одной из моих собственных директив, чтобы ограничить его объем. Если вы хотите использовать его в масштабе всего приложения, вы можете настроить его поведение, например. только замените элемент, если атрибут replace установлен в HTML и по умолчанию возвращается к настройке innerHtml.

Также: это может плохо отразиться на анимации. Код для исходного ngInclude -directive намного длиннее, поэтому, если вы используете анимацию в своем приложении, c & p исходный код и shoehorn `$element.replaceWith().

var includeDirective = ['$http', '$templateCache', '$sce', '$compile', 
         function($http, $templateCache, $sce, $compile) { 
    return { 
     restrict: 'ECA', 
     priority: 600, 
     terminal: true, 
     link: function(scope, $element, $attr) { 
      scope.$watch($sce.parseAsResourceUrl($attr.src), function ngIncludeWatchAction(src) {  
       if (src) { 
        $http.get(src, {cache: $templateCache}).success(function(response) { 
         var e =$compile(response)(scope); 
         $element.replaceWith(e); 
        });  
       } 
      }); 
     } 
    }; 
}]; 

myApp.directive('ngInclude', includeDirective);