angularjs - ng-include not working
Evite usar nodos DOM adicionales cuando use nginclude (5)
Algunas de las otras respuestas sugieren replace:true
, pero tenga en cuenta que replace:true
en las plantillas está marcado como obsoleto .
En cambio, en una respuesta a una pregunta similar , encontramos una alternativa: le permite escribir:
<div ng-include src="dynamicTemplatePath" include-replace></div>
Directiva personalizada:
app.directive(''includeReplace'', function () {
return {
require: ''ngInclude'',
restrict: ''A'', /* optional */
link: function (scope, el, attrs) {
el.replaceWith(el.children());
}
};
});
(cortar y pegar de la otra respuesta)
Estoy luchando para ver cómo hacer que un ng-include no use un elemento DOM adicional ya que estoy creando una aplicación angular a partir de una demostración en formato HTML simple. Estoy trabajando con un HTML bastante delgado con un CSS (desarrollado a partir de SASS) completamente desarrollado y estrechamente acoplado a DOM, y la refactorización es algo que quiero evitar a toda costa.
Aquí está el código real:
<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>
Necesito que <sección> sea un elemento repetitivo, pero que tenga su propia lógica y contenido diferente. Tanto el contenido como la cantidad de repeticiones dependen de la lógica empresarial. Como puede ver, poner el controlador ng y la repetición ng en el elemento <section> no funcionará. Lo que, sin embargo, sería insertar un nuevo nodo DOM, que es lo que estoy tratando de evitar.
¿Qué me estoy perdiendo? ¿Es esta la mejor práctica o hay una mejor manera?
EDITAR : solo para aclarar según lo solicitado en los comentarios, el HTML final que estoy tratando de generar sería:
<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>
La razón por la que quiero usar la misma plantilla B (subheader.html) es por la limpieza del código. Concibo subheader.html para tener algún tipo de interruptor ng para devolver contenido dinámico.
Pero básicamente, la cuestión subyacente es: ¿hay una manera de incluir el contenido de una plantilla de forma transparente, sin utilizar un nodo DOM?
EDIT2 : La solución debe ser reutilizable. =)
Con la configuración correcta, puede definir su propia directiva ngInclude
que puede ejecutarse en lugar de la proporcionada por Angular.js y evitar que la directiva incorporada se ejecute siempre.
Para evitar que la directiva incorporada en Angular se ejecute, es crucial establecer la prioridad de su directiva más alta que la de la directiva incorporada (400 para ngInclude
y establecer la propiedad del terminal
en true
.
Después de eso, debe proporcionar una función de enlace posterior que recupere la plantilla y reemplace el nodo DOM del elemento con el HTML compilado de la plantilla.
Una advertencia : esto es bastante draconiano, usted redefine el comportamiento de ngInclude
para toda su aplicación. Por lo tanto, establezco la directiva a continuación, no en myApp
sino dentro de una de mis propias directivas para limitar su alcance. Si desea usarlo en toda la aplicación, es posible que desee que su comportamiento sea configurable, por ejemplo, solo reemplace el elemento si se establece un atributo de replace
en el HTML y por defecto recurra a la configuración de innerHtml.
Además: esto podría no funcionar bien con animaciones. El código para el ngInclude
original es mucho más largo, por lo tanto, si usa animaciones en su aplicación, c & p el código original y calce el `$element.replaceWith()
en eso.
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);
Para cualquiera que visite esta pregunta:
A partir de la versión 1.1.4+, puede utilizar una función en la plantillaURL para hacerla dinámica.
Echa un vistazo a esta otra respuesta here
Puede crear una directiva personalizada, vincular a la plantilla con la propiedad templateUrl
y establecer replace
en true
:
app.directive(''myDirective'', function() {
return {
templateUrl: ''url/to/template'',
replace: true,
link: function(scope, elem, attrs) {
}
}
});
Eso incluiría la plantilla como está, sin ningún elemento de envoltura, sin ningún alcance de envoltura.
Edit: Después de algunas investigaciones y por el bien de la integridad, he añadido algo de información. Desde la 1.1.4, los siguientes trabajos:
app.directive(''include'',
function () {
return {
replace: true,
restrict: ''A'',
templateUrl: function (element, attr) {
return attr.pfInclude;
}
};
}
);
Uso:
<div include="''path/to/my/template.html''"></div>
Sin embargo, hay una pregunta: la plantilla no puede ser dinámica (como en, pasar una variable a través del ámbito porque no se puede acceder a $ scope, o cualquier DI , en templateUrl - ver este problema ), solo se puede pasar una cadena (Al igual que el fragmento de código HTML anterior). Para evitar ese problema en particular, este trozo de código debería hacer el truco (felicitaciones a este 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));
}
);
}
};
});
Uso:
<div include="myTplVariable"></div>