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

}

मुझे पता है कि आसान समाधान *ngIfएक स्तर को ऊपर ले जाने के लिए है, लेकिन एक सूची में आइटमों पर लूपिंग जैसे परिदृश्यों के लिए ul, मैं liसंग्रह खाली होने पर या तो खाली के साथ समाप्त होता हूं , या मेरा liनिरर्थक कंटेनर तत्वों में लिपटा हुआ है।

इस plnkr पर उदाहरण ।

कंसोल त्रुटि पर ध्यान दें:

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

क्या मैं कुछ गलत कर रहा हूँ या यह एक बग है?


stackoverflow.com/questions/40529537/… मैं एनजी-कंटेनर के साथ जाना होगा
रॉबर्ट राजा

जवाबों:


680

कोणीय 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>पहले कोणीय 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
एलेक्स फुएंटेस

7
जब हमारे पास * ngIf * ngFor होगा तो कोड कैसा दिखेगा? Ie IF स्थिति लूप एलिमेंट के मान पर आधारित होगी।
युवराज पाटिल

22
बस डाल ngForपर <ng-container>तत्व और ngIfपर <div>। आप दो नेस्टेड <ng-container>रैपिंग भी कर सकते हैं <div><ng-container>केवल एक सहायक तत्व है जिसे DOM में नहीं जोड़ा जाएगा।
गुंटर ज़ोचबॉयर

3
मैं उपयोग करने का सुझाव दूंगा <ng-container>। यह वैसा ही व्यवहार करता है <template>लेकिन संरचनात्मक निर्देशों के लिए "सामान्य" वाक्यविन्यास का उपयोग करने की अनुमति देता है।
गुंटर ज़ोचबॉयर

2
दस्तावेज़ीकरण कहता है : "प्रति होस्ट तत्व एक संरचनात्मक निर्देश": "इस उपयोग के मामले का एक आसान समाधान है: * ngIf को एक कंटेनर तत्व पर रखें जो * ngFor तत्व को लपेटता है।" - सिर्फ दोहराते हुए
20

71

जैसा कि सभी ने बताया है कि एक ही तत्व में कई टेम्प्लेट डायरेक्शंस होने के बावजूद कोणीय 1.x में यह कोणीय 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 में कोणीय 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>ओं):

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

यह समाधान भी किसी भी अतिरिक्त / निरर्थक कंटेनर तत्वों का परिचय नहीं देता है।


1
मुझे यकीन नहीं है कि यह स्वीकृत उत्तर क्यों नहीं है। <template>एक मूल तत्व जोड़ने का तरीका है जो आउटपुट में दिखाई नहीं देगा।
इवान प्लाइस


5

आपके पास ngForऔर ngIfसमान तत्व नहीं हो सकते । ngForजब तक आप अपने उदाहरण में टॉगल पर क्लिक नहीं कर लेते, तब तक आप जिस सरणी का उपयोग कर रहे हैं , उस पर क्लिक करके आप क्या कर सकते हैं ।

यहां एक मूल (महान नहीं) तरीका है जो आप कर सकते हैं: http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P


वह दोनों क्यों नहीं कर सकते? कृपया विस्तृत करें
maurycy

1
वहाँ चारों ओर एक चर्चा है कि यहाँ github.com/angular/angular/issues/4792
Zyzle

1
मुझे पता है कि ऐसा क्यों हो रहा है, यह सिर्फ उत्तर की गुणवत्ता में सुधार करना है, स्पष्ट रूप से कहना you can'tवास्तव में एक अच्छा जवाब नहीं है, क्या आप सहमत नहीं हैं?
मोरिसी

निश्चित रूप से, उन्हें केवल इसलिए एक साथ उपयोग नहीं किया जाना चाहिए क्योंकि उन्हें कुछ निश्चित क्रम में डालने के लिए यह गारंटी नहीं है कि उन्हें उसी क्रम में निष्पादित किया जाएगा। लेकिन यह स्पष्ट नहीं करता है कि वास्तव में क्या होता है जब 'संपत्ति को पढ़ा नहीं जा सकता है' नाम 'के नाम'।
एस्टुस फ्लास्क

दोनों * ngFor और * ngIf (तारांकन के साथ) संरचनात्मक निर्देश हैं और वे <टेम्पलेट> टैग उत्पन्न करते हैं। एनजीआईएफ जैसे संरचनात्मक निर्देश HTML 5 टेम्पलेट टैग का उपयोग करके अपना जादू करते हैं।
परदीप जैन

5

आप एक Structural Directiveही तत्व पर कोणीय में एक से अधिक का उपयोग नहीं कर सकते हैं , यह एक बुरा भ्रम और संरचना बनाता है, इसलिए आपको उन्हें 2 अलग-अलग नेस्टेड तत्वों (या आप उपयोग कर सकते हैं ng-container) में लागू करने की आवश्यकता है , इस कथन को अंगुलर टीम से पढ़ें:

मेजबान तत्व प्रति एक संरचनात्मक निर्देश

किसी दिन आप HTML का एक खंड दोहराना चाहते हैं, लेकिन केवल तब जब कोई विशेष स्थिति सत्य हो। आप दोनों एक डाल करने के लिए कोशिश करता हूँ * ngFor और एक * ngIf ही मेजबान तत्व पर। कोणीय आपको नहीं होने देगा। आप एक तत्व के लिए केवल एक संरचनात्मक निर्देश लागू कर सकते हैं।

इसका कारण सादगी है। संरचनात्मक निर्देश मेजबान तत्व और उसके वंश के साथ जटिल चीजें कर सकते हैं। जब दो निर्देश एक ही मेजबान तत्व का दावा करते हैं, तो कौन सा पूर्वता लेता है? जो पहले जाना चाहिए, NgIf या NgFor? क्या NgIf NgFor के प्रभाव को रद्द कर सकता है? यदि ऐसा है (और ऐसा लगता है कि ऐसा होना चाहिए), तो कोणीय को अन्य संरचनात्मक निर्देशों के लिए रद्द करने की क्षमता को कैसे सामान्य करना चाहिए?

इन सवालों के कोई आसान जवाब नहीं हैं। कई संरचनात्मक निर्देशों को रोकना उन्हें लूट बनाता है। इस उपयोग के मामले के लिए एक आसान उपाय है: डाल * ngIf एक कंटेनर तत्व यह है कि लपेटता पर * ngFor तत्व। एक या दोनों तत्व एनजी-कंटेनर हो सकते हैं, इसलिए आपको HTML के अतिरिक्त स्तरों को लागू करने की आवश्यकता नहीं है।

तो आप ng-container(Angular4) को रैपर के रूप में उपयोग कर सकते हैं (डोम से हटा दिया जाएगा) या एक div या स्पान यदि आपके पास नीचे के रूप में वर्ग या कुछ अन्य विशेषताएं हैं:

<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> <विकल्प> संयोजन के लिए एक बहुत आसान हैक है, जिसे मैं पूरी सूची के बजाय फ़िल्टर्ड आइटम दिखाना चाहता हूं
davyzhang

आपका बहुत बहुत धन्यवाद!
अभिषेक शर्मा

3

केवल "शुरुआती" मान सेट करने वाली वस्तुओं को नीचे दी गई तालिका में सूचीबद्ध किया गया है। Html में अवांछित पंक्तियों को रोकने *ngForके *ngIfलिए दोनों की आवश्यकता होती है।

मूल रूप से *ngIfऔर *ngForएक ही <tr>टैग पर था , लेकिन काम नहीं करता है। लूप के <div>लिए जोड़ा गया *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 में काम करता है जो विशेष रूप से तत्वों के बारे में picky है<table>
Günter Zöchbauer

3

कोणीय 2 बीटा 8 को अपडेट किया गया

अब जैसा कि कोणीय 2 बीटा 8 से हम उपयोग कर सकते हैं *ngIfऔर *ngForउसी घटक पर यहाँ देखें

वैकल्पिक:

कभी कभी हम HTML टैग एक और अंदर में की तरह उपयोग नहीं कर सकते tr, th( table) या में li( ul)। हम दूसरे HTML टैग का उपयोग नहीं कर सकते हैं, लेकिन हमें उसी स्थिति में कुछ कार्रवाई करनी होगी इसलिए हम <template>इस तरह से HTML5 फीचर टैग कर सकते हैं ।

टेम्प्लेट का उपयोग करते हुए एनफोर:

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

टेम्प्लेट का उपयोग करके ngIf:

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

कोणीय 2 में संरचनात्मक निर्देशों के बारे में अधिक जानकारी के लिए यहां देखें



1

आप एक ही HTML तत्व पर * ngFor और ngIfng-template दोनों को लागू करने के लिए (टेम्पलेट के बजाय टेम्पलेट टैग का उपयोग करने के लिए नोट देखें) का भी उपयोग कर सकते हैं । यहाँ एक उदाहरण है जहाँ आप का उपयोग कर सकते है दोनों * ngIf और * ngFor उसी के लिए कोणीय तालिका में tr तत्व के ।

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


ली वस्तुओं को केवल तभी प्रदर्शित किया जाता है जब उसका कोई नाम हो।
राजीव

3
यह उत्तर यहाँ मूल्य कैसे जोड़ता है? यह कुछ भी प्रदान नहीं करता है जो पहले से ही अन्य उत्तरों द्वारा प्रदान नहीं किया गया है या मुझे कुछ याद नहीं है?
गुंटर ज़ोचबॉयर 11

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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.