无法分配给对象“[object Object]”的只读 属性 'winner'

Cannot assign to read only property 'winner' of object '[object Object]'

我遇到了错误

ContestDetailsModalComponent.html:21 ERROR TypeError: Cannot assign to read only property 'winner' of object '[object Object]'
    at ContestDetailsModalComponent.onWinner (contest-details-modal.component.ts:88:24)
    at Object.eval [as handleEvent] (ContestDetailsModalComponent.html:21:17)
    at handleEvent (core.js:43993:77)
    at callWithDebugContext (core.js:45632:1)
    at Object.debugHandleEvent [as handleEvent] (core.js:45247:1)
    at dispatchEvent (core.js:29804:1)
    at core.js:42925:1
    at HTMLButtonElement.<anonymous> (platform-browser.js:2668:1)
    at ZoneDelegate.invokeTask (zone-evergreen.js:399:1)
    at Object.onInvokeTask (core.js:39680:1)

当我尝试做作业时

this.contest.winner = winnerId;

您在以下代码片段中看到:

public onWinner(winnerId: number): void {
     const post: Post = new Post();
     post.title = `The winner of the contest has been elected: ${this.contest.title}`;
     post.description = `Tizio has been elected winner of the contest and ${this.user.name} gives him the most welcome compliments`;
     post.user = this.user;
     post.contest = this.contest;
     post.type = Type.WINNER;
     post.level = Level.SUCCESS;
     this.contest.winner = winnerId;
     this.store.dispatch(PostActions.savePost({post}));
     this.store.dispatch(ContestActions.saveContest({contest: this.contest}));
}

我和项目周围的其他 class 一起完成了这种任务,他们从来没有打扰过我。

我附上比赛class和post如果有用的话:

export class Contest {
  public id: number;
  public title: string;
  public description: string;
  public rules: string;
  public startDate: Date;
  public endDate: Date;
  public status: Status;
  public winner: number;
  public bannedUser: number[];
}


export class Post {
  public id: number;
  public title: string;
  public description: string;
  public level: Level;
  public type: Type;
  public user: User;
  public publishDate: Date;
  public contest: Contest;

}

我也尝试了一些总是在这个论坛上找到的解决方案,例如:

Object.assign(target, source);

但他正确地告诉我 this.contest.winner 为空或未定义。

希望得到您的帮助。谢谢

编辑:

这是存在 onWinner() 的整个 component.ts。

@Component({
  selector: 'app-contest-details-modal',
  templateUrl: './contest-details-modal.component.html',
  styleUrls: ['./contest-details-modal.component.scss'],
})
export class ContestDetailsModalComponent implements OnInit, OnDestroy, AfterViewChecked {
  private readonly subscriptions: Subscription = new Subscription();
  public id: number;
  public user: User;
  public contest: Contest;
  public images: Image[];
  public hasVoted: boolean;

  constructor(
    private readonly bsModalRef: BsModalRef,
    private readonly modalService: BsModalService,
    private readonly store: Store<AppState>,
    private cdRef: ChangeDetectorRef
  ) { }

  public ngOnInit(): void {

    this.subscriptions.add(this.store.pipe(select(AuthSelectors.getUser)).subscribe((user: User) => {
      if (user) {
        this.user = user;
      }
    }));

    this.subscriptions.add(this.store.pipe(select(ContestSelectors.getById)).subscribe((contest: Contest) => {
      if (contest) {
        this.contest = contest;
      }
    }));

    this.subscriptions.add(this.store.pipe(select(ImageSelectors.getImages)).subscribe((images: Image[]) => {
      if (images.length) {
        this.images = images;
      }
    }));

    this.subscriptions.add(this.store.pipe(select(UserSelectors.check)).subscribe((ack: Ack) => {
      if (ack) {
        this.store.dispatch(AuthActions.updatedUser({userId: this.user.id}));
        this.modalService.show(UploadImageModalComponent);
        this.bsModalRef.hide();
      }
    }));

    this.subscriptions.add(this.store.pipe(select(ImageSelectors.check)).subscribe((ack: Ack) => {
      if (ack) {
        this.bsModalRef.hide();
      }
    }));

  }

  public ngOnDestroy(): void {
    this.store.dispatch(UserActions.clean());
    this.store.dispatch(ContestActions.clean());
    this.subscriptions.unsubscribe();
  }

  public onWinner(winnerId: number): void {
    const post: Post = new Post();
    post.title = `The winner of the contest has been elected: ${this.contest.title}`;
    post.description = `Tizio has been elected winner of the contest and ${this.user.name} gives him the most welcome compliments`;
    post.user = this.user;
    post.contest = this.contest;
    post.type = Type.WINNER;
    post.level = Level.SUCCESS;
    this.contest.winner = winnerId;
    this.store.dispatch(PostActions.savePost({post}));
    this.store.dispatch(ContestActions.saveContest({contest: this.contest}));
  }

  public onJoin(): void {
    this.store.dispatch(UserActions.saveUser({idUser: this.user.id, id: this.contest.id}));
  }

  public onVote(image: Image): void {
    let vote: number = image.vote;
    vote = vote + 1;
    this.store.dispatch(ImageActions.updateImage({photoId: image.id, votes: vote, userId: this.user.id}));
    this.store.dispatch(AuthActions.updatedUser({userId: this.user.id}));
  }

  public isContain(contestId: number): boolean {
    if (this.user.myContest) {
      for (const i of this.user.myContest) {
        if (contestId === i) {
          return true;
        }
      }
    }
    return false;
  }

  public isImageVoted(id: number): boolean {
    if (this.user.favouritePhoto) {
      for (const imageVoted of this.user.favouritePhoto) {
            if (id === imageVoted) {
              this.hasVoted = true;
              return true;
            }
      }
      return false;
      }
   }

  public onBan(image: Image): void {
    this.modalService.show(BanModalComponent, {initialState : image});
    this.bsModalRef.hide();
  }

  public isBan(contestId: number): boolean {
    if (this.user.whereBanned) {
      for (const contestBanned of this.user.whereBanned) {
        if (contestId === contestBanned) {
          return true;
        }
      }
      return false;
    }
  }

  public ngAfterViewChecked(): void {
      this.cdRef.detectChanges();
  }
}

contest 包含对 Observable 发射的引用,并且 Observable 发射的所有引用都是只读的。克隆 contest:

this.contest = { ...contest };

或者,更好的做法是,将其保留为 Observable 并照原样使用它,通常通过 async 管道。此外,如果您使用的是 NgRx,则需要使用 store.select():

this.contest$ = this.store.select(ContestSelectors.getById);