template style example container cli angular ngfor angular-ng-if

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>