angular - style - * ngIf y*ngFor en el mismo elemento que causa error
ngfor angular 6 (14)
Actualizado a angular2 beta 8
Ahora a partir de angular2 beta 8 podemos usar
*ngIf
y
*ngFor
en el mismo componente,
ver aquí
.
Alterno:
A veces no podemos usar etiquetas HTML dentro de otra como en
tr
,
th
(
table
) o en
li
(
ul
).
No podemos usar otra etiqueta HTML, pero tenemos que realizar alguna acción en la misma situación para que podamos etiquetar la etiqueta HTML5
<template>
de esta manera.
ng Para usar la plantilla:
<template ngFor #abc [ngForOf]="someArray">
code here....
</template>
ng Si usa la plantilla:
<template [ngIf]="show">
code here....
</template>
Para obtener más información sobre las directivas estructurales en angular2, consulte aquí .
Tengo un problema al tratar de usar
*ngFor
y
*ngIf
de
*ngIf
en el mismo elemento.
Al intentar recorrer la colección en
*ngFor
, la colección se ve como
null
y, en consecuencia, falla al intentar acceder a sus propiedades en la plantilla.
@Component({
selector: ''shell'',
template: `
<h3>Shell</h3><button (click)="toggle()">Toggle!</button>
<div *ngIf="show" *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
`
})
export class ShellComponent implements OnInit {
public stuff:any[] = [];
public show:boolean = false;
constructor() {}
ngOnInit() {
this.stuff = [
{ name: ''abc'', id: 1 },
{ name: ''huo'', id: 2 },
{ name: ''bar'', id: 3 },
{ name: ''foo'', id: 4 },
{ name: ''thing'', id: 5 },
{ name: ''other'', id: 6 },
]
}
toggle() {
this.show = !this.show;
}
log(thing) {
console.log(thing);
}
}
Sé que la solución fácil es mover el
*ngIf
sube un nivel, pero para escenarios como recorrer los elementos de la lista en un
ul
, terminaría con una
li
vacía si la colección está vacía, o mi
li
está envuelta en un contenedor redundante elementos.
Ejemplo en este plnkr .
Tenga en cuenta el error de la consola:
EXCEPTION: TypeError: Cannot read property ''name'' of null in [{{thing.name}} in ShellComponent@5:12]
¿Estoy haciendo algo mal o es un error?
Angular v2 no admite más de una directiva estructural sobre el mismo elemento.
Como solución alternativa, use el elemento
<ng-container>
que le permite usar elementos separados para cada directiva estructural, pero no está
estampado en el DOM
.
<ng-container *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</ng-container>
<ng-template>
(
<template>
before Angular v4) permite hacer lo mismo pero con una sintaxis diferente que es confusa y ya no se recomienda
<ng-template [ngIf]="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</ng-template>
Como @Zyzle mencionó y @ Günter mencionó en un comentario ( https://github.com/angular/angular/issues/7315 ), esto no es compatible.
Con
<ul *ngIf="show">
<li *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</li>
</ul>
no hay elementos
<li>
vacíos cuando la lista está vacía.
Incluso el elemento
<ul>
no existe (como se esperaba).
Cuando se llena la lista, no hay elementos contenedores redundantes.
La
discusión de github (4792)
que @Zyzle mencionó en su comentario también presenta otra solución usando
<template>
(a continuación estoy usando su marcado original - usando
<div>
s):
<template [ngIf]="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</template>
Esta solución tampoco introduce ningún elemento contenedor adicional / redundante.
Como todos señalaron, aunque tener múltiples directivas de plantilla en un solo elemento funciona en angular 1.x no está permitido en Angular 2. Puede encontrar más información aquí: https://github.com/angular/angular/issues/7315
2016 angular 2 beta
la solución es usar
<template>
como marcador de posición, por lo que el código es así
<template *ngFor="let nav_link of defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</template>
pero por alguna razón anterior no funciona en
2.0.0-rc.4
en ese caso puede usar esto
<template ngFor let-nav_link [ngForOf]="defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</template>
Respuesta actualizada 2018
Con las actualizaciones, ahora en 2018 angular v6 se recomienda usar
<ng-container>
lugar de
<template>
Así que aquí está la respuesta actualizada.
<ng-container *ngFor="let nav_link of defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</ng-container>
Esto funcionará pero el elemento seguirá en el DOM.
.hidden{
display: none;
}
<div [class.hidden]="!show" *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
La siguiente tabla solo enumera los elementos que tienen un conjunto de valores "principiante".
Requiere tanto
*ngFor
como
*ngIf
para evitar filas no deseadas en html.
Originalmente tenía
*ngIf
y
*ngFor
en la misma etiqueta
<tr>
, pero no funciona.
Se agregó un
<div>
para el bucle
*ngFor
y se colocó
*ngIf
en la etiqueta
<tr>
, funciona como se esperaba.
<div [ngClass]="{''disabled-field'': !show}" *ngFor="let thing of stuff">
{{thing.name}}
</div>
No puede tener
ngFor
y
ngIf
en el mismo elemento.
Lo que podría hacer es
ngFor
para
ngFor
la matriz que está usando en
ngFor
hasta que se
ngFor
en el interruptor de su ejemplo.
Aquí hay una forma básica (no excelente) de hacerlo: http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P
No puede usar directivas estructurales múltiples en el mismo elemento.
Envuelva su elemento en
ng-template
y use una directiva estructural allí
No puede usar más de una
Structural Directive
en angular en el mismo elemento, crea una mala confusión y estructura, por lo que debe aplicarlas en 2 elementos anidados separados (o puede usar
ng-container
), lea esta declaración de Angular equipo:
Una directiva estructural por elemento host
Algún día querrás repetir un bloque de HTML, pero solo cuando una condición particular sea verdadera. Intentará poner un * ngFor y un * ngIf en el mismo elemento host. Angular no te dejará. Puede aplicar solo una directiva estructural a un elemento.
La razón es la simplicidad. Las directivas estructurales pueden hacer cosas complejas con el elemento host y sus descendientes. Cuando dos directivas reclaman el mismo elemento host, ¿cuál tiene prioridad? ¿Cuál debería ir primero, el NgIf o el NgFor? ¿Puede el NgIf cancelar el efecto del NgFor? Si es así (y parece que debería ser así), ¿cómo debería Angular generalizar la capacidad de cancelar para otras directivas estructurales?
No hay respuestas fáciles para esas preguntas. Prohibir múltiples directivas estructurales los hace discutibles. Hay una solución fácil para este caso de uso: coloque * ngIf en un elemento contenedor que envuelva el elemento * ngFor . Uno o ambos elementos pueden ser un contenedor ng para que no tenga que introducir niveles adicionales de HTML.
Por lo tanto, puede usar
ng-container
(Angular4) como el contenedor (se eliminará del dom) o un div o span si tiene la clase o algunos otros atributos como a continuación:
.disabled-field {
pointer-events: none;
display: none;
}
También puede usar
ng-template
(en lugar de template. Consulte la nota para la advertencia de usar la etiqueta de plantilla) para aplicar tanto
* ngFor
como
ngIf
en el mismo elemento HTML.
Aquí hay un ejemplo donde puede usar
tanto * ngIf como * ngFor
para el mismo elemento
tr
en la tabla angular.
<tr *ngFor = "let fruit of fruiArray">
<ng-template [ngIf] = "fruit==''apple''>
<td> I love apples!</td>
</ng-template>
</tr>
donde
fruiArray = [''apple'', ''banana'', ''mango'', ''pineapple'']
.
Nota:
La advertencia de usar solo la etiqueta de
template
lugar de la etiqueta
ng-template
es que arroja
StaticInjectionError
en algunos lugares.
Tengo una solución mas.
Utilice
[hidden]
lugar de
*ngIf
<div [hidden]="!show" *ngFor="let thing of stuff">
La diferencia es que
*ngIf
eliminará el elemento del DOM, mientras que
[hidden]
realidad juega con el estilo
CSS
configurando display: none
en html:
<table class="table lessons-list card card-strong ">
<tbody>
<div *ngFor="let lesson of lessons" >
<tr *ngIf="lesson.isBeginner">
<!-- next line doesn''t work -->
<!-- <tr *ngFor="let lesson of lessons" *ngIf="lesson.isBeginner"> -->
<td class="lesson-title">{{lesson.description}}</td>
<td class="duration">
<i class="fa fa-clock-o"></i>
<span>{{lesson.duration}}</span>
</td>
</tr>
</div>
</tbody>
</table>
en css:
<div class="right" *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</div>
<!-- Since angular2 stable release multiple directives are not supported on a single element(from the docs) still you can use it like below -->
<ul class="list-group">
<template ngFor let-item [ngForOf]="stuff" [ngForTrackBy]="trackBy_stuff">
<li *ngIf="item.name" class="list-group-item">{{item.name}}</li>
</template>
</ul>
<div *ngFor="let thing of show ? stuff : []">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>