Why in my Angular code I am obtaining this error? Error: InvalidPipeArgument

Why in my Angular code I am obtaining this error? Error: InvalidPipeArgument

我正在做一个 Angular 项目,我遇到了以下问题。

基本上我有这个 HomeComponent 查看代码:

<div class="courses-panel">

    <h3>All Courses</h3>

    <mat-tab-group>

        <mat-tab label="Beginners">
          <courses-card-list [courses]="beginnerCourses$ | async"></courses-card-list>
        </mat-tab>

        <mat-tab label="Advanced">
          <courses-card-list [courses]="advancedCourses$ | async"></courses-card-list>
        </mat-tab>

    </mat-tab-group>

</div>

下面是相关的TypeScript代码:

import {Component, OnInit} from '@angular/core';
import {Course, sortCoursesBySeqNo} from '../model/course';
import {interval, noop, Observable, of, throwError, timer} from 'rxjs';
import {catchError, delay, delayWhen, filter, finalize, map, retryWhen, shareReplay, tap} from 'rxjs/operators';
import {HttpClient} from '@angular/common/http';
import {MatDialog, MatDialogConfig} from '@angular/material/dialog';
import {CourseDialogComponent} from '../course-dialog/course-dialog.component';
import { CoursesService } from '../services/courses.service';


@Component({
  selector: 'home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  beginnerCourses$: Observable<Course[]>;

  advancedCourses$: Observable<Course[]>;


  constructor(private coursesService: CoursesService) {

  }

  ngOnInit() {

    const courses$ = this.coursesService.loadedAllCourses()
                     .pipe(
                       map(courses => courses.sort(sortCoursesBySeqNo))
                     )

    this.beginnerCourses$ = courses$
                            .pipe(
                              map(courses => courses.filter(course => course.category == "BEGINNER"))
                            );

    this.advancedCourses$ = courses$
                            .pipe(
                              map(courses => courses.filter(course => course.category == "ADVANCED"))
                            );


  }

}

正如您在前面代码中看到的那样,首先进入组件初始化,我使用服务 class 的 loadedAllCourses() 方法检索一个 Observable(它只是执行一个指向 API) 的 HTTP 请求,然后从这个 Observable 我创建了另外两个 Observable,它们是 beginnerCourses$advancedCourses$ 包含两个在检索到的课程 Observable 上过滤不同类型的课程。

在我的 HomeCompoent 视图中,我声明了 courses-card-list 组件,它只会显示课程信息,比如这个:

<courses-card-list [courses]="beginnerCourses$ | async"></courses-card-list>

和:

<courses-card-list [courses]="advancedCourses$ | async"></courses-card-list>

这是courses-card-list组件的查看代码:

<mat-card *ngFor="let course of (courses | async)" class="course-card mat-elevation-z10">

  <mat-card-header>

    <mat-card-title>{{course.description}}</mat-card-title>

  </mat-card-header>

  <img mat-card-image [src]="course.iconUrl">

  <mat-card-content>
    <p>{{course.longDescription}}</p>
  </mat-card-content>

  <mat-card-actions class="course-actions">

    <button mat-button class="mat-raised-button mat-primary" [routerLink]="['/courses', course.id]">
      VIEW COURSE
    </button>

    <button mat-button class="mat-raised-button mat-accent"
            (click)="editCourse(course)">
      EDIT
    </button>

  </mat-card-actions>

</mat-card>

这是相关的后端代码:

import { Component, OnInit, Input } from '@angular/core';
import { Course } from '../model/course';
import { MatDialogConfig, MatDialog } from '@angular/material/dialog';
import { CourseDialogComponent } from '../course-dialog/course-dialog.component';

@Component({
  selector: 'courses-card-list',
  templateUrl: './courses-card-list.component.html',
  styleUrls: ['./courses-card-list.component.scss']
})
export class CoursesCardListComponent implements OnInit {

  @Input()
  courses: Course[] = [];


  constructor(private dialog: MatDialog) { }

  ngOnInit() {
  }

  editCourse(course: Course) {

    const dialogConfig = new MatDialogConfig();

    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = "400px";

    dialogConfig.data = course;

    const dialogRef = this.dialog.open(CourseDialogComponent, dialogConfig);

  }

}

问题是 运行 我的应用程序收到了以下似乎与两个 async 管道相关的错误消息:

core.js:4081 ERROR Error: InvalidPipeArgument: '[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]' for pipe 'AsyncPipe'
    at invalidPipeArgumentError (common.js:4148)
    at AsyncPipe._selectStrategy (common.js:4250)
    at AsyncPipe._subscribe (common.js:4240)
    at AsyncPipe.transform (common.js:4228)
    at Module.ɵɵpipeBind1 (core.js:24409)
    at CoursesCardListComponent_Template (courses-card-list.component.html:1)
    at executeTemplate (core.js:7329)
    at refreshView (core.js:7198)
    at refreshComponent (core.js:8335)
    at refreshChildComponents (core.js:6991)
defaultErrorLogger @ core.js:4081
handleError @ core.js:4129
(anonymous) @ core.js:28062
invoke @ zone-evergreen.js:364
run @ zone-evergreen.js:123
runOutsideAngular @ core.js:27065
tick @ core.js:28062
(anonymous) @ core.js:27941
invoke @ zone-evergreen.js:364
onInvoke @ core.js:27138
invoke @ zone-evergreen.js:363
run @ zone-evergreen.js:123
run @ core.js:27020
next @ core.js:27940
schedulerFn @ core.js:24535
__tryOrUnsub @ Subscriber.js:183
next @ Subscriber.js:122
_next @ Subscriber.js:72
next @ Subscriber.js:49
next @ Subject.js:39
emit @ core.js:24525
checkStable @ core.js:27074
onLeave @ core.js:27184
onInvokeTask @ core.js:27132
invokeTask @ zone-evergreen.js:398
runTask @ zone-evergreen.js:167
invokeTask @ zone-evergreen.js:480
invokeTask @ zone-evergreen.js:1621
globalZoneAwareCallback @ zone-evergreen.js:1658
load (async)
customScheduleGlobal @ zone-evergreen.js:1773
scheduleTask @ zone-evergreen.js:385
onScheduleTask @ zone-evergreen.js:272
scheduleTask @ zone-evergreen.js:378
scheduleTask @ zone-evergreen.js:210
scheduleEventTask @ zone-evergreen.js:236
(anonymous) @ zone-evergreen.js:1928
(anonymous) @ http.js:1764
_trySubscribe @ Observable.js:42
subscribe @ Observable.js:28
subscribeToResult @ subscribeToResult.js:9
_innerSub @ mergeMap.js:59
_tryNext @ mergeMap.js:53
_next @ mergeMap.js:36
next @ Subscriber.js:49
(anonymous) @ subscribeToArray.js:3
_trySubscribe @ Observable.js:42
subscribe @ Observable.js:28
call @ mergeMap.js:21
subscribe @ Observable.js:23
call @ filter.js:13
subscribe @ Observable.js:23
call @ map.js:16
subscribe @ Observable.js:23
call @ map.js:16
subscribe @ Observable.js:23
shareReplayOperation @ shareReplay.js:28
subscribe @ Observable.js:23
call @ map.js:16
subscribe @ Observable.js:23
call @ map.js:16
subscribe @ Observable.js:23
createSubscription @ common.js:4160
_subscribe @ common.js:4241
transform @ common.js:4228
ɵɵpipeBind1 @ core.js:24409
HomeComponent_Template @ home.component.html:9
executeTemplate @ core.js:7329
refreshView @ core.js:7198
refreshComponent @ core.js:8335
refreshChildComponents @ core.js:6991
refreshView @ core.js:7248
refreshEmbeddedViews @ core.js:8289
refreshView @ core.js:7222
refreshComponent @ core.js:8335
refreshChildComponents @ core.js:6991
refreshView @ core.js:7248
renderComponentOrTemplate @ core.js:7312
tickRootContext @ core.js:8507
detectChangesInRootView @ core.js:8532
detectChanges @ core.js:9918
tick @ core.js:28052
(anonymous) @ core.js:27941
invoke @ zone-evergreen.js:364
onInvoke @ core.js:27138
invoke @ zone-evergreen.js:363
run @ zone-evergreen.js:123
run @ core.js:27020
next @ core.js:27940
schedulerFn @ core.js:24535
__tryOrUnsub @ Subscriber.js:183
next @ Subscriber.js:122
_next @ Subscriber.js:72
next @ Subscriber.js:49
next @ Subject.js:39
emit @ core.js:24525
checkStable @ core.js:27074
onHasTask @ core.js:27152
hasTask @ zone-evergreen.js:419
_updateTaskCount @ zone-evergreen.js:440
_updateTaskCount @ zone-evergreen.js:263
runTask @ zone-evergreen.js:184
drainMicroTaskQueue @ zone-evergreen.js:569
Promise.then (async)
scheduleMicroTask @ zone-evergreen.js:552
scheduleTask @ zone-evergreen.js:388
scheduleTask @ zone-evergreen.js:210
scheduleMicroTask @ zone-evergreen.js:230
scheduleResolveOrReject @ zone-evergreen.js:847
then @ zone-evergreen.js:979
bootstrapModule @ core.js:27726
./src/main.ts @ main.ts:13
__webpack_require__ @ bootstrap:78
0 @ main.ts:14
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:44
webpackJsonpCallback @ bootstrap:31
(anonymous) @ main.js:1
Show 72 more frames
core.js:4081 ERROR Error: InvalidPipeArgument: '[object Object],[object Object],[object Object]' for pipe 'AsyncPipe'
    at invalidPipeArgumentError (common.js:4148)
    at AsyncPipe._selectStrategy (common.js:4250)
    at AsyncPipe._subscribe (common.js:4240)
    at AsyncPipe.transform (common.js:4228)
    at Module.ɵɵpipeBind1 (core.js:24409)
    at CoursesCardListComponent_Template (courses-card-list.component.html:1)
    at executeTemplate (core.js:7329)
    at refreshView (core.js:7198)
    at refreshComponent (core.js:8335)
    at refreshChildComponents (core.js:6991)

怎么了?我错过了什么?我该如何解决这个问题?

EDIT-1:* 这是我的服务class 代码:

@Injectable({
  providedIn: 'root'
})
export class CoursesService {

  constructor(private http:HttpClient) {}

  loadedAllCourses(): Observable<Course[]> {
    // The obsarvable return a JSON containing the "payload" property containing the array
    //return this.http.get<Course[]>("/api/courses");
    return this.http.get<Course[]>("/api/courses")
          .pipe(
            map(res => res["payload"]),
            /* Keep the result of this HTTP request in memory avoiding that n async pipe or subscription
               will cause n call to the API. Keep the result in memory and share between subsequence subscriber */
            shareReplay()
          );


  }

}

如您所见,loadedAllCourses() 方法 return 是一个 Observable,所以我用 async“订阅”它通过管道进入我的 HomeComponent 以检索我试图传递给我的子组件的课程数组

在此调用中,您将使用异步管道“解包”可观察对象,将其转换为常规数组并将其分配给 courses-card-list 的课程@Input()。

接下来,在 courses-card-list 的 HTML 模板中,您将通过尝试解包再次将此常规数组视为可观察对象。