Search code examples
angularundefinedtypeerrorangular-pipe

Custom Pipe Angular, TypeError: Cannot read property 'reduce' of undefined


I am fetching the courses from the Firebase database as so:

              this.fetchItems()
              .subscribe((res) => {
                   this.coursesFiltered = res.filter((filtered: any) => {
                    return filtered.courseStatus === 2 || filtered.courseStatus === 3
                   });


               });

The function fetchItems()

  fetchItems() {
    return this.afDB.list('courses', (ref) => ref.orderByChild('courseSemCode'))
       .snapshotChanges()
       .map((arr) => {
          return arr.map((snap: any) => {
            return snap.status = snap.payload.val();
          });
        });
      }

Then I want to group them by courseSemCode so that it displays properly in the cards

<ion-card *ngFor="let item of coursesFiltered | groupBy:'courseSemCode'">
    <ion-card-header>
      <h6>{{item.courseSemester + " " + item.courseYear}}</h6>
    </ion-card-header>

    <ion-card-content>

        <ion-list>
            <button ion-button class="text" class="btnCourse">
              {{item.courseName}}
            </button>
        </ion-list>
    </ion-card-content>
  </ion-card>

The groupBy pipe is a custom pipe that I got from this thread: How to group data in Angular 2?

Which is this:

    @Pipe({name: 'groupBy'})
export class GroupByPipe implements PipeTransform {
  transform(value: Array<any>, field: string): Array<any> 
{
  if(!value || !value.length) { 
    return value; 
  }else{
    const groupedObj = value.reduce((prev, cur)=> {
      if(!prev[cur[field]]) {
        prev[cur[field]] = [cur];
      } else {
        prev[cur[field]].push(cur);
      }
      return prev;
    }, {});
    return Object.keys(groupedObj).map(key => ({ key, value: groupedObj[key] }));
  }
  }  
}

But unfortunately in the end I'm faced with the problem TypeError: Cannot read property 'reduce' of undefined

I believe this has to do with the .subscribe which I've written in the constuctor, which only means that the coursesFiltered still has no data.

How can I make sure it does and solve this issue?

Thank you


Solution

  • In your pipe, you can simply test for it :

    transform(value: any, args?: any) {
      if(!value || !value.length) { return value; }
      return value.reduce(...);
    }
    

    EDIT In your loop you do this

    *ngFor="let item of coursesFiltered | groupBy:'courseSemCode'"
    

    But your structure for the grouped array is this

    [{key: 'your key', value: [...]}]
    

    This means that you have to make two loops :

    <ion-card *ngFor="let group of coursesFiltered | groupBy:'courseSemCode'">
      <ng-container *ngFor="let item of group.value">
        <ion-card-header>
          <h6>{{item.courseSemester + " " + item.courseYear}}</h6>
        </ion-card-header>
    
        <ion-card-content>
    
            <ion-list>
                <button ion-button class="text" class="btnCourse">
                  {{item.courseName}}
                </button>
            </ion-list>
        </ion-card-content>
      </ng-container>
    </ion-card>