동일한 요소에서 * ngIf 및 * ngFor 오류 발생


473

나는 각도의를 사용하려고 시도에 문제에 봉착 *ngFor하고*ngIf 같은 요소 .

에서 모음을 반복하려고하면 모음 의 속성에 액세스하려고 할 때 *ngFor모음이 표시되어 null실패합니다.

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

}

나는 쉬운 솔루션은 이동하는 것입니다 알고 *ngIfA의 목록 항목에 걸쳐 반복과 같은 수준까지하지만 시나리오 ul나도 빈으로 끝낼 것, li컬렉션이 비어있는 경우, 또는 내을li 의 중복 컨테이너 요소에 싸여.

이 plnkr의 예 .

콘솔 오류에 유의하십시오.

EXCEPTION: TypeError: Cannot read property 'name' of null in [{{thing.name}} in ShellComponent@5:12]

내가 잘못하고 있거나 버그입니까?


stackoverflow.com/questions/40529537/… ng-container와 함께 갈 것입니다
— 로버트 킹

답변:


680

Angular v2는 동일한 요소에서 둘 이상의 구조적 지시문을 지원하지 않습니다.
해결 방법 <ng-container>으로 각 구조적 지시문에 대해 별도의 요소를 사용할 수 있는 요소를 사용하지만 DOM에 찍히지 않습니다 .

<ng-container *ngIf="show">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</ng-container>

<ng-template>( <template>Angular v4 이전)는 혼란스럽고 더 이상 권장되지 않는 다른 구문으로 동일하게 수행 할 수 있습니다.

<ng-template [ngIf]="show">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</ng-template>

5
고마워 놀랍게도 여전히 문서화되어 있지 않습니다 : github.com/angular/angular.io/issues/2303
— Alex Fuentes

7
* ngFor 안에 * ngIf가 있어야 할 때 코드는 어떻게 생겼습니까? 즉, IF 조건은 루프 요소의 값을 기반으로합니다.
— Yuvraj Patil

22
그냥 넣어 ngFor상기 <ng-container>요소와 ngIf상기 <div>. 또한 두 개의 중첩 <ng-container>랩핑을 가질 수 있습니다 <div>. <ng-container>DOM에 추가되지 않는 도우미 요소 일뿐입니다.
— Günter Zöchbauer 2012 년

3
을 사용하는 것이 좋습니다 <ng-container>. <template>구조적 지시문에 "일반"구문을 사용할 수 는 있지만 동일하게 동작합니다 .
— Günter Zöchbauer

2
문서에 "호스트 요소 당 하나의 구조적 지시어": "이 사용 사례에 대한 쉬운 해결책이 있습니다. * ngFor 요소를 감싸는 컨테이너 요소에 * ngIf를 넣으십시오." -방금 반복
— heringer

71

단일 요소에 여러 템플릿 지시문이 있지만 angular 1.x에서는 작동하지만 Angular 2에서는 허용되지 않습니다. https://github.com/angular/angular/issues/ 7315

2016 각도 2 베타

해결책은 <template>자리 표시 자로 사용하는 것이므로 코드는 다음과 같습니다.

<template *ngFor="let nav_link of defaultLinks"  >
   <li *ngIf="nav_link.visible">
       .....
   </li>
</template>

그러나 어떤 이유로 든 위의 2.0.0-rc.4경우에는 작동하지 않습니다.

<template ngFor let-nav_link [ngForOf]="defaultLinks" >
   <li *ngIf="nav_link.visible">
       .....
   </li> 
</template>

업데이트 된 답변 2018

업데이트로 2018 년 현재 angular v6 <ng-container>대신에 사용 하는 것이 좋습니다<template>

여기에 업데이트 된 답변이 있습니다.

<ng-container *ngFor="let nav_link of defaultLinks" >
   <li *ngIf="nav_link.visible">
       .....
   </li> 
</ng-container>

29

@Zyzle이 언급했듯이 @ Günter는 주석에서 언급했습니다 ( https://github.com/angular/angular/issues/7315 ) 이것은 지원되지 않습니다.

와

<ul *ngIf="show">
  <li *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </li>
</ul>

<li>목록이 비어 있으면 빈 요소 가 없습니다 . 심지어 <ul>(예상대로) 요소가 존재하지 않습니다.

목록이 채워지면 중복 컨테이너 요소가 없습니다.

GitHub의 토론 (4792) @Zyzle 그의 주석에서 언급 한 또한 사용하여 다른 솔루션을 제공합니다 <template>- (사용 나는 원래 마크 업을 사용하고 이하 <div>: S)

<template [ngIf]="show">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</template>

이 솔루션에는 여분 / 중복 컨테이너 요소도 도입되지 않습니다.


1
왜 이것이 대답이 아닌지 잘 모르겠습니다. <template>출력에 표시되지 않는 부모 요소를 추가하는 방법입니다.
— Evan Plaice

8

html로 :

<div [ngClass]="{'disabled-field': !show}" *ngFor="let thing of stuff">
    {{thing.name}}
</div>

CSS에서 :

.disabled-field {
    pointer-events: none;
    display: none;
}

5

당신은 할 수 없습니다 ngFor와 ngIf같은 요소. 할 수있는 일은 ngFor예제의 토글을 클릭 할 때까지 사용중인 배열을 채우는 것 입니다.

기본적인 방법은 다음과 같습니다. http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P


왜 둘 다 가질 수 없습니까? 정교한 제발
— maurycy

1
그 주위에 토론이 여기에있다 github.com/angular/angular/issues/4792
— Zyzle

1
왜 그런 일이 일어나는지 알고 있습니다. 답변의 품질을 향상시키는 you can't것입니다. 일반적으로 좋은 대답은 아니라고 동의합니까?
— maurycy

물론, 템플릿에 특정 순서로 배치한다고해서 동일한 순서로 실행될 것이라는 보장은 없기 때문에 함께 사용해서는 안됩니다. 그러나 이것은 'null의'name '속성을 읽을 수 없습니다'가 발생했을 때 정확히 무슨 일이 일어나는지 설명하지 않습니다.
— Estus Flask

* ngFor 및 * ngIf (별표 포함)는 구조적 지시문이며 <template> 태그를 생성합니다. ngIf와 같은 구조적 지시문은 HTML 5 템플릿 태그를 사용하여 마법을 수행합니다.
— Pardeep Jain

5

Structural Directive같은 요소에 Angular에서 둘 이상을 사용할 수 없으므로 혼동과 구조가 잘못되므로 두 개의 별도 중첩 요소에 적용해야합니다 (또는 사용할 수 있음 ng-container). Angular 팀 에서이 문장을 읽으십시오.

호스트 요소 당 하나의 구조적 지시어

언젠가는 특정 조건이 참일 때만 HTML 블록을 반복하고 싶을 것입니다. 당신은 둘 다 넣어하려고합니다 * ngFor 와 * ngIf을 동일한 호스트 요소. 각도는 당신을 못하게합니다. 하나의 구조 지시문 만 요소에 적용 할 수 있습니다.

그 이유는 단순성입니다. 구조적 지시어는 호스트 요소와 그 하위 요소로 복잡한 작업을 수행 할 수 있습니다. 두 개의 지시문이 동일한 호스트 요소에 대한 소유권을 주장 할 때 어느 지시어가 우선합니까? NgIf 또는 NgFor 중 어느 것을 먼저해야합니까? NgIf가 NgFor의 효과를 취소 할 수 있습니까? 그렇다면 Angular는 다른 구조적 지시문에 대한 취소 기능을 어떻게 일반화해야합니까?

이 질문들에 대한 쉬운 대답은 없습니다. 여러 구조적 지시문을 금지하면 문제가 발생합니다. 이 사용 사례에 대한 쉬운 해결책이있다 : 풋 * ngIf을 감쌈 컨테이너 요소에 * ngFor 요소를. 요소 중 하나 또는 둘 다 ng- 컨테이너 일 수 있으므로 추가 수준의 HTML을 도입 할 필요가 없습니다.

따라서 ng-container(Angular4)를 래퍼 (dom에서 삭제됨) 또는 div 또는 span으로 사용할 수 있습니다 (아래와 같이 클래스 또는 다른 속성이있는 경우).

<div class="right" *ngIf="show">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</div>

4

이것은 작동하지만 요소는 여전히 DOM에 있습니다.

.hidden {
    display: none;
}

<div [class.hidden]="!show" *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
</div>

이것은 <select> <option> 조합에 대한 매우 쉬운 해킹입니다. 간단히 전체 목록 대신 필터링 된 항목을 표시하려고합니다.
— davyzhang

대단히 감사합니다!
— Abhishek Sharma

3

아래 표에는 "초보자"값이 설정된 항목 만 나열되어 있습니다. 모두 필요 *ngFor와는 *ngIfHTML에서 불필요한 행을 방지 할 수 있습니다.

원래했다 *ngIf과 *ngFor같은에서 <tr>태그,하지만 작동하지 않습니다. <div>for *ngFor루프를 추가 *ngIf하고 <tr>태그에 배치 하면 예상대로 작동합니다.

<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>

1
나는 <div>테이블 내부가 거위 아이디어 라고 생각하지 않습니다 . 특히 더 나은 대안이있을 때. IE의 요소가 특히 까다로운 IE에서 작동하는지 확인 했습니까?<table>
— Günter Zöchbauer

3

angular2 베타 8로 업데이트

이제 angular2 베타 우리가 사용할 수있는 8에서로 *ngIf와 *ngFor같은 구성 요소에는 여기를 참조하십시오 .

번갈아 하는:

때때로 우리가 같은 다른 내부 HTML 태그를 사용할 수 없습니다 tr, th( table) 또는 li( ul). 다른 HTML 태그를 사용할 수 없지만 같은 상황에서 몇 가지 작업을 수행해야 HTML5 기능 태그를 사용할 수 있습니다<template> 이러한 방식으로 를 .

ng 템플릿을 사용하는 경우 :

<template ngFor #abc [ngForOf]="someArray">
    code here....
</template>

ng 템플릿을 사용하는 경우 :

<template [ngIf]="show">
    code here....
</template>    

angular2의 구조적 지시문에 대한 자세한 내용 은 여기를 참조하십시오 .


1
<div *ngFor="let thing of show ? stuff : []">
  {{log(thing)}}
  <span>{{thing.name}}</span>
</div>

1

동일한 HTML 요소에 * ngFor 및 ngIf 를 ng-template모두 적용하기 위해 템플릿 대신 사용할 수 있습니다 (템플릿 태그 사용에 대한 참고 사항 참조) . 다음은 각도 테이블에서 동일한 tr 요소에 * ngIf 및 * ngFor 를 모두 사용할 수있는 예 입니다.

<tr *ngFor = "let fruit of fruiArray">
    <ng-template [ngIf] = "fruit=='apple'>
        <td> I love apples!</td>
    </ng-template>
</tr>

어디서 fruiArray = ['apple', 'banana', 'mango', 'pineapple']?

노트 :

template태그 대신 태그 만 사용하는 경우주의해야 ng-template할 점 은 태그가 StaticInjectionError특정 위치에 발생 한다는 것 입니다.


0

<!-- 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>


li 항목은 이름이있는 경우에만 표시됩니다.
— Rajiv

3
이 답변이 여기에 어떻게 가치를 더합니까? 이미 다른 답변에서 제공하지 않은 것을 제공하지 않거나 무언가를 놓쳤습니까?
— Günter Zöchbauer

0

동일한 요소에 여러 구조적 지시문을 사용할 수 없습니다. 요소를 감싸고 ng-template하나의 구조적 지시문을 사용 하십시오.


0

배열 길이를 확인하여 다른 방법 으로이 작업을 수행 할 수 있습니다

<div *ngIf="stuff.length>0">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</div>

-1

app.component.ts

import {NgModule, Component} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

@Component({
  selector: 'ngif-example',
  template: `
<h4>NgIf</h4>
<ul *ngFor="let person of people">
  <li *ngIf="person.age < 30"> (1)
  {{ person.name }} ({{ person.age }})
  </li>
</ul>
`
})
class NgIfExampleComponent {

  people: any[] = [
    {
      "name": "yogesh ",
      "age": 35
    },
    {
      "name": "gamesh",
      "age": 32
    },
    {
      "name": " Meyers",
      "age": 21
    },
    {
      "name": " Ellis",
      "age": 34
    },
    {
      "name": " Tyson",
      "age": 32
    }
  ];
}

app.component.html

<ul *ngFor="let person of people" *ngIf="person.age < 30">
  <li>{{ person.name }}</li>
</ul>

산출

Meyers(21)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.