@angular2+,在回调函数中更新了模型,但是视图不渲染的问题。

新手上路,请多包涵

场景很简单,调用远程方法,返回的Observable对象的subscribe方法中,(或者Promise的then),更新了数据模型,但是视图没有渲染。

task.component.html
<div class="vertical-form-container">
  <form #taskForm>
      <mat-form-field>
        <input matInput #title type="text" name="title" placeholder="Title" required [(ngModel)]="taskData.title">
      </mat-form-field>

      <mat-form-field class="example-full-width">
        <input matInput #deadlineDate name='deadlineDate' [matDatepicker]="picker" placeholder="Deadline Date" required [(ngModel)]="taskData.deadlineDate">
        <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
        <mat-datepicker touchUi="true" #picker></mat-datepicker>
      </mat-form-field>
        
      <mat-form-field class="example-full-width">
          <textarea matInput matTextareaAutosize minRows='2' maxRows='10' #description name='description' placeholder="Task Description" [(ngModel)]="taskData.description"></textarea>
        </mat-form-field>
      <button mat-raised-button color="primary" type="button" (click)='submitTask()'>ADD</button>  
  </form>
</div>
task.component.ts
......
// taskService是Service,通过taskId远程(非angular的http)获取数据
this.taskService.getTask(taskId).subscribe(
    resp=>{
      console.log('get task: ----------------');
      console.log(resp);
      this.taskData = resp; // 场景一,View不更新

      // this._ngZone.run(()=>this.taskData = resp); //场景二,使用NgZone,View会更新

      /* 场景二,View会更新, changeDetectorRef是注入的ChangeDetectorRef
      this.taskData = resp;
      this.changeDetectorRef.markForCheck();  
      this.changeDetectorRef.detectChanges();   */
    }
  );
......

方式一就无法更新视图,而且如果在方式一中使用router.navigate(...)也会不正常;方式二可以更新视图,但是如果每次都要把回调用ngZone.run()封装起来也太不优雅了;方式三和方式二差不多,而且在angular-material下不正常。

不知道有什么好办法可以解决一下这个问题?还是我哪里写的有问题吗?

阅读 3.6k
2 个回答

如果你不使用内置的http服务,同时zonejs又没有对你使用的请求服务做patched的话,只能手动触发了。

对于代码本身,我认为和优雅不优雅没有关系,因为既然没有使用内置的http服务,那自己需要额外的代码来解决问题。不过通过NgZone.runOutsideAngular把在Angular作用域外执行的方法包裹起来可能比直接调用在请求方法返回的回调中调用NgZone.run优雅一些?

下面的这个方法是在什么调用的?
我按照你的代码写了个例子, 是没问题的啊。

  setTask(): void {
    this.getTask(2).subscribe((res: any) => {
      this.taskData = res;
    });
  }

  getTask(id: number): Observable<any> {
    return Observable.of({
      title: id,
      deadlineDate: new Date(id + 100),
      description: id + 200
    });
  }

clipboard.png

点击Set button后

clipboard.png

还有你的angular core版本是多少?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进