鍍金池/ 問(wèn)答/HTML5/ @angular2+,在回調(diào)函數(shù)中更新了模型,但是視圖不渲染的問(wèn)題。

@angular2+,在回調(diào)函數(shù)中更新了模型,但是視圖不渲染的問(wèn)題。

場(chǎng)景很簡(jiǎn)單,調(diào)用遠(yuǎn)程方法,返回的Observable對(duì)象的subscribe方法中,(或者Promise的then),更新了數(shù)據(jù)模型,但是視圖沒(méi)有渲染。

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,通過(guò)taskId遠(yuǎn)程(非angular的http)獲取數(shù)據(jù)
this.taskService.getTask(taskId).subscribe(
    resp=>{
      console.log('get task: ----------------');
      console.log(resp);
      this.taskData = resp; // 場(chǎng)景一,View不更新

      // this._ngZone.run(()=>this.taskData = resp); //場(chǎng)景二,使用NgZone,View會(huì)更新

      /* 場(chǎng)景二,View會(huì)更新, changeDetectorRef是注入的ChangeDetectorRef
      this.taskData = resp;
      this.changeDetectorRef.markForCheck();  
      this.changeDetectorRef.detectChanges();   */
    }
  );
......

方式一就無(wú)法更新視圖,而且如果在方式一中使用router.navigate(...)也會(huì)不正常;方式二可以更新視圖,但是如果每次都要把回調(diào)用ngZone.run()封裝起來(lái)也太不優(yōu)雅了;方式三和方式二差不多,而且在angular-material下不正常。

不知道有什么好辦法可以解決一下這個(gè)問(wèn)題?還是我哪里寫的有問(wèn)題嗎?

回答
編輯回答
怪痞

下面的這個(gè)方法是在什么調(diào)用的?
我按照你的代碼寫了個(gè)例子, 是沒(méi)問(wèn)題的啊。

  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

點(diǎn)擊Set button后

clipboard.png

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

2017年10月21日 12:41
編輯回答
玄鳥

如果你不使用內(nèi)置的http服務(wù),同時(shí)zonejs又沒(méi)有對(duì)你使用的請(qǐng)求服務(wù)做patched的話,只能手動(dòng)觸發(fā)了。

對(duì)于代碼本身,我認(rèn)為和優(yōu)雅不優(yōu)雅沒(méi)有關(guān)系,因?yàn)榧热粵](méi)有使用內(nèi)置的http服務(wù),那自己需要額外的代碼來(lái)解決問(wèn)題。不過(guò)通過(guò)NgZone.runOutsideAngular把在Angular作用域外執(zhí)行的方法包裹起來(lái)可能比直接調(diào)用在請(qǐng)求方法返回的回調(diào)中調(diào)用NgZone.run優(yōu)雅一些?

2017年2月22日 04:22