Обновление компонента вручную после успешного вызова API - PullRequest
0 голосов
/ 16 мая 2019

Итак, я написал свой собственный API, и я делаю довольно много API-вызовов. Проблема в том, что мои компоненты не обновляются после завершения вызовов. Я провел небольшое исследование, и вот что я придумал:

  onSubmit() {
    if (this._user) {
      this._commentDataService
        .postComment(
          this.imageId,
          new Comment(
            this.loggedInUser.firstName + ' ' + this.loggedInUser.lastName,
            this.messageForm.value.message,
            new Date(),
            this.imageId,
            this.loggedInUser.id
          )
        )
        .subscribe(com => {
          console.log(com);
          this._changeDetectorRef.markForCheck();
        });
    } else {
      this.openSnackBar('You need to be logged in to send a message.');
    }
  }

Но, с другой стороны, markForCheck() не обновляет мой компонент после завершения запроса:

  postComment(imageId: number, comment: Comment): Observable<Comment> {
    return this.http.post<Comment>(
      `${environment.apiUrl}/images/${imageId}/comments`,
      comment.toJSON()
    );
  }

Мне также нужно, чтобы это произошло для PUT и DELETE (тех, которые я еще не проверял)

Не могли бы вы мне помочь?

Следующая часть вопроса (теперь, когда мой компонент обновляется :)) Поэтому, когда я POST / PUT для комментария, он выглядит совершенно нормально, но когда я пытаюсь удалить сообщение, он удаляет нужный пост в базе данных, но визуально удаляет комментарий прямо под комментарием, который я хочу удалить. Когда я обновляю, правильный комментарий визуально удаляется, а комментарий, который был визуально удален, возвращается на свое место. Я не знаю, почему это происходит (может быть, это как-то связано с тем, что иногда меняется порядок комментариев (я не выяснил, в каком состоянии они меняются или почему) код:

DeleteCommentComponent:

import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MatSnackBar, MAT_DIALOG_DATA } from '@angular/material';
import { CommentDataService } from '../comment-data.service';

@Component({
  selector: 'app-delete-comment',
  templateUrl: './delete-comment.component.html',
  styleUrls: ['./delete-comment.component.css']
})
export class DeleteCommentComponent implements OnInit {
  constructor(
    public dialogRef: MatDialogRef<DeleteCommentComponent>,
    private _commentDataService: CommentDataService,
    private _snackBar: MatSnackBar,
    @Inject(MAT_DIALOG_DATA) public data: any
  ) {}

  ngOnInit() {}

  cancel() {
    this.openSnackbar('Comment did not get deleted.');
    this.onNoClick();
  }

  delete() {
    this._commentDataService
      .deleteComment(this.data.comment.myImageId, this.data.comment.id)
      .subscribe(c => {
        console.log(c);
        if (c) {
          this.data.array.pop(c);
          this.openSnackbar('Comment succesfully deleted.');
        } else {
          this.openSnackbar(
            'Something went wrong deleting the comment, please try again.'
          );
        }
      });
    this.onNoClick();
  }

  private onNoClick(): void {
    this.dialogRef.close();
  }

  private openSnackbar(message: string) {
    this._snackBar.open(message, 'Close', { duration: 2000 });
  }
}
<h2 mat-dialog-title>Delete a comment</h2>
<mat-dialog-content>
  Are you sure you want to delete this comment?
</mat-dialog-content>
<mat-dialog-actions>
  <button mat-raised-button class="noBtn right" (click)="cancel()">No</button>
  <button mat-raised-button class="yesBtn" (click)="delete()">Yes</button>
</mat-dialog-actions>

Метод, который открывает это диалоговое окно:

  openDeleteDialog(comment: Comment) {
    const dialogRef = this.dialog.open(DeleteCommentComponent, {
      width: '300px',
      height: '200px',
      data: { comment, array: this.comments }
    });
  }

Это вызывается, когда вы нажимаете на кнопку удаления:

<div class="overflow">
  <div
    fxLayout="row"
    fxLayoutAlign="space-between"
    *ngFor="let comment of comments"
  >
    <div>
      <div class="commentDiv" data-cy="comments">
        <span class="user left">{{ comment.author }}: </span>
        <span>{{ comment.content }}</span>
      </div>
      <div class="iconDiv right" *ngIf="isAuthor(comment)">
        <mat-icon class="edit" (click)="openChangeDialog(comment)"
          >edit</mat-icon
        ><mat-icon class="delete" (click)="openDeleteDialog(comment)"
          >delete</mat-icon
        >
      </div>
    </div>
  </div>
</div>
<form [formGroup]="messageForm" (ngSubmit)="onSubmit()" data-cy="commentForm">
  <mat-form-field>
    <input
      matInput
      aria-label="Message"
      placeholder="Message"
      type="text"
      class="browser-default"
      formControlName="message"
    />
    <mat-error
      *ngIf="
        messageForm.get('message')['errors'] &&
        messageForm.get('message').touched
      "
    >
      {{ getErrorMessage(messageForm.get('message')['errors']) }}
    </mat-error>
  </mat-form-field>

  <button mat-raised-button type="submit" [disabled]="!messageForm.valid">
    <mat-icon>send</mat-icon>
  </button>
</form>

1 Ответ

0 голосов
/ 17 мая 2019

Вы должны использовать асинхронный канал, чтобы применить новое изменение, когда ваш вызов API сделан

Из документа

AsyncPipe подписывается на наблюдаемое или обещание и возвращает последнее значение он выпустил. Когда испускается новое значение, труба отмечает компонент, подлежащий проверке на наличие изменений.

Пример

@Component({
  selector: 'async-observable-pipe',
  template: `<div><code>observable|async</code>:
       Time: {{ time | async }}</div>`
})
export class AsyncObservablePipeComponent {
  time = new Observable(observer =>
    setInterval(() => observer.next(new Date().toString()), 1000)
  );
}

Больше можно найти здесь

...