简体   繁体   中英

How can I create an embedded ngFor inside of an ngIf statement?

What I'm Trying To Do

I'm trying to create a page where there is a bunch of mat-expansion-panels that each have their own content. The content is hardcoded, but rather than having each page on it's own component, I wanted to try and make one component that gets reused and interacts with a static service in order to be scalable as more content needs to be added, or if I were to connect it to a database in the future.

What I've Tried

What I've Tried (Variation 1)

<article *ngIf="code$ | async as title">
    <h1>{{title.title}}</h1>
    <div *ngFor="section of title.sections | async">
        <mat-expansion-panel>
            <mat-expansion-panel-header>
                <mat-panel-title>
                    {{sTitle}}
                </mat-panel-title>
                <mat-panel-description>
                    {{sDesc}}
                </mat-panel-description>
            </mat-expansion-panel-header>
            <div>
                {{sContent}}
            </div>
        </mat-expansion-panel>
    </div>
</article>

What I've Tried (Variation 2)

<article *ngIf="code$ | async as title">
    <h1>{{title.title}}</h1>
    <div *ngFor="section of title.sections | async as section">
        <mat-expansion-panel>
            <mat-expansion-panel-header>
                <mat-panel-title>
                    {{sTitle}}
                </mat-panel-title>
                <mat-panel-description>
                    {{sDesc}}
                </mat-panel-description>
            </mat-expansion-panel-header>
            <div>
                {{sContent}}
            </div>
        </mat-expansion-panel>
    </div>
</article>

What I've Tried (Variation 3)

<article *ngIf="code$ | async as title">
    <h1>{{title.title}}</h1>
    <div *ngFor="section of title.sections | async">
        <mat-expansion-panel>
            <mat-expansion-panel-header>
                <mat-panel-title>
                    {{this.sTitle}}
                </mat-panel-title>
                <mat-panel-description>
                    {{this.sDesc}}
                </mat-panel-description>
            </mat-expansion-panel-header>
            <div>
                {{this.sContent}}
            </div>
        </mat-expansion-panel>
    </div>
</article>

What I've Tried (Variation 4)

<article *ngIf="code$ | async as title">
    <h1>{{title.title}}</h1>
    <div *ngFor="section of title.sections | async">
        <mat-expansion-panel>
            <mat-expansion-panel-header>
                <mat-panel-title>
                    {{this.section.sTitle}}
                </mat-panel-title>
                <mat-panel-description>
                    {{this.section.sDesc}}
                </mat-panel-description>
            </mat-expansion-panel-header>
            <div>
                {{this.section.sContent}}
            </div>
        </mat-expansion-panel>
    </div>
</article>

Other Code

Snippet of Component.ts (everything is imported fine at the top)

code$: any;
  constructor(
    private pcts: StaticService,
    private route: ActivatedRoute
  ){}
  ngOnInit(){
    this.code$ = this.route.paramMap.pipe(
      map(params => {
        const title = params.get('slug');
        return this.pcts.pctSearch(title);
      })
    )
  }

Service.ts

export interface tSect {
  sTitle: string;
  sDesc: string;
  sContent: string;
}
export interface pct {
  id: string;
  title: string;
  sections: tSect[];
}
...
{
  id: "...",
  title: "...",
  sections: [
     {sTitle: 'Test', sDesc: 'Test', sContent: 'test'},
     {sTitle: 'Tes2t', sDesc: 'Test2', sContent: 'test2'},
  ],
},
...
pctSearch(slug: string) {
    var __FOUND = -1;
    for(var t = 0; t < this.pctarr.length; t++) {
      if(this.pctarr[t].id == slug) {
        __FOUND = t;
        return this.pctarr[__FOUND];
      }
    }
  }

What Happens?

I get an error saying that the property (sContent, sTitle, or sDesc) doesn't exist on the component.

Expected Result

The section should show a list of mat-expansion-panel(s) with the sections from the array in the service.

Put the *ngFor on the mat-expansion-panel and take out the | async | async in the *ngFor, since you have already applied the pipe to the title in the *ngIf.

Edit:

Your pctSearch function should be:

pctSearch(slug: string) {
    return this.pctarr.filter(pct => pct.title === slug);
}

Keep in mind this will return you an array of pct's that match the slug. So if you just want the first element than just grab that first index.

Edit 2:

It was just a small error, you were missing "let" in your *ngFor. You also need to use the actual element in the loop when asking for the properties like sTitle, etc. Also in your component where you declare code$ you should also declare it's type instead of any to Observable (change any to whatever your type is).

So you're template would look like this:

<mat-expansion-panel *ngFor="let section of title.sections">
    <mat-expansion-panel-header>
        <mat-panel-title>
            {{section.sTitle}}
        </mat-panel-title>
        <mat-panel-description>
            {{section.sDesc}}
        </mat-panel-description>
    </mat-expansion-panel-header>
    <div>
        {{section.sContent}}
    </div>
</mat-expansion-panel>

Also in your component you should declare code$ like this:

code$: Observable<any>;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM