【问题标题】:Unable to update UI even when data of model changes (using Angular 4 - observables)即使模型的数据发生变化也无法更新 UI(使用 Angular 4 - observables)
【发布时间】:2017-07-25 14:14:52
【问题描述】:

1) 我有 SiteMap 组件,它显示: a) 3 个按钮:确认、再次上传文件、更新 UI(用于测试) b) Component TreeView:这需要一个数组作为输入并显示它 在用户界面上。

<!--siteMap-component.html -->
<div class="tree">
  <tree-view [siteTree]="siteMapTree">

  </tree-view>
</div>
<div class="col-xs-12">
  <button type="button" class="pull-right btn-primary" (click)="approveAndUploadLandingPages()">Confirm</button>
  <button type="button" class="pull-left btn-inverse" (click)="updateSiteMapTree()">Refresh UI</button>
  <button type="button" class="pull-left btn-inverse" (click)="uploadAgain()">Upload Again</button>
</div>

2) 我有一个 siteMapDataObservable,它是用一个值初始化的。现在这个 Observable 的值会在 updateSiteMapTree() 调用 this.siteMapDataObservable.next() 时更新。

// SitemapComponent
import ...
@Component({
  selector: 'app-gb-sitemap',
  templateUrl: './sitemap.component.html',
  styleUrls: ['./sitemap.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class SitemapComponent implements OnInit {

  siteMapTree: Array<any>;
  siteMapDataObservable: BehaviorSubject<Object> = new BehaviorSubject<Object>(this.contactServerService.getSiteMapObject());


  constructor(private contactServerService: ContactServerService, private route: ActivatedRoute, private router: Router, public modal: Modal) {
  }

  updateSiteMapTree() {
    this.siteMapDataObservable.next(this.contactServerService.getSiteMapObject());// this.contactServerService.getSiteMapObject() retrieves the data from sessionStorage
  }

  uploadAgain() {
    return this.modal.open(CustomModalComponent,  overlayConfigFactory({ }, BSModalContext));
  }

  rejectUpload() {
    this.router.navigate(['/home']);
    this.clearSessionStorage();
  }

  approveAndUploadLandingPages() {
    this.contactServerService.uploadLandingPages(this.landingPagesObj)
      .subscribe(
        (response) => {
          console.log(response);
          this.clearSessionStorage();
          this.router.navigate(['/']);
        },
        (error) => console.log(error)
      );
  }

  clearSessionStorage() {
    sessionStorage.removeItem('siteMapTree');
  }


  ngOnInit() {
    this.siteMapDataObservable
      .subscribe(
        siteMapTreeObj => {
          this.siteMapTree = [siteMapTreeObj['tree']];
        }
    );
  }
}

3) 再次上传按钮打开一个模态; CustomModalComponent 用于从用户那里获取另一个文件,在 http 的回调中,修改数据模型并调用 SiteMapComponent 中的 updateSiteMapTree() 以更新 siteMapTree。

// CustomModalComponent
import ...
@Component({
  selector: 'modal-content',
  templateUrl: './custom-modal-sample.html',
  encapsulation: ViewEncapsulation.None,
  providers: [SitemapComponent],
  styleUrls: ['./custom-modal-sample.scss']
})


export class CustomModalComponent implements OnInit {
  fileTypes: Array<string>;

  private uploadExcelUrl: string;
  public uploaderExcel: FileUploader;

  constructor(private router: Router, public dialog: DialogRef<any>, private contactServerService: ContactServerService,
              private siteMapComponent: SitemapComponent) {
    this.fileTypes = ['.xls', '.xlsx'];

    this.uploadExcelUrl = this.contactServerService.getExcelUploadUrl();
    this.uploaderExcel = new FileUploader({url: this.uploadExcelUrl});
  }

  ngOnInit() {

    this.uploaderExcel.onSuccessItem = function(fileItem, response, status, headers) {
      fileItem.remove();

      const RESPONSE_DATA = JSON.parse(response);
      sessionStorage.setItem('landingPagesTree', JSON.stringify(RESPONSE_DATA));

      dialogBox.dismiss();

    };

    this.siteMapComponent.updateSiteMapTree();
  }

  getNextRouteState() {
    return this.router;
  }

  clearError() {
    this.dialog.dismiss();
  }
}

发现:1) 从 CustomModalComponent 调用 SiteMapComponent 中的 updateSiteMapTree() 会更新“siteMapTree”,但更改不会反映在 UI 中。

2) 为了测试,我在 SiteMapComponent 组件中有一个按钮 Refresh UI,它也调用 updateSiteMapTree()。但是,单击此按钮会更新 UI。

问题: 1) 为什么当我从 CustomModalComponent 调用 SiteMapComponent 中的 updateSiteMapTree() 时我的 UI 没有更新,即使我的数据模型已更改。

2) 当我通过单击同一组件中的按钮调用 SiteMapComponent 中的 updateSiteMapTree() 时,UI 是如何变化的。

编辑: 添加树视图组件

import ...;

@Component({
  selector: 'tree-view',
  templateUrl: './tree-view.component.html',
  styleUrls: ['./tree-view.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class TreeViewComponent implements OnInit, OnChanges {

  @Input() siteTree: Array<any>;

  warnings: Array<string>;

  constructor() {
    this.warnings = [];
  }

  ngOnInit() {
  }

  ngOnChanges ( ...args: any[]) {
    console.log('OnChange');
    console.log(this.siteTree);
  }

  toggle(subtree) {
    subtree.showChild = !subtree.showChild;
  }
}

【问题讨论】:

    标签: angular angular-observable


    【解决方案1】:

    您可以使用ApplicationRef 中的tick() 方法强制检测更改。

    @Injectable()
    export class Service {
    
        constructor(private appref: ApplicationRef){}
    
        public someMethod():void {
              //some actions, ie pushing next value to observable
              this.appref.tick();
        } 
    }
    

    https://angular.io/api/core/ApplicationRef

    【讨论】:

    • 在 SitemapComponent 的 'updateSiteMapTree()' 中,我添加了 this.appref.tick();在最后。我在最后添加了它,这样一旦我的 next() 函数调用 this.siteMapDataObservable.subscribe(),才会调用 appref.tick()。但是 UI 仍然没有更新。
    • 你改变检测策略了吗?
    • 我应该如何/在哪里更改检测策略?
    • 从 '@angular/core' 导入 { ChangeDetectionStrategy }; @Component({ changeDetection: ChangeDetectionStrategy.OnPush })
    • 我使用了检测策略,但仍然无法更新 UI。然而,我发现了一些东西。请查看我添加的“TreeViewComponent”的描述,它是负责生成 UI 的子组件。 TreeViewComponent 中的 ngOnChange() 仅在 Angular 首次呈现页面时调用。当我更改 TreeViewComponent 的 @Input 数据模型时,不会再次调用 ngOnChange()。我相信这就是 UI 没有更新的原因。目前我在 SitemapComponent 的 updateSiteMapTree() 中使用了 appref.tick()。你有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2019-10-17
    • 2018-04-07
    • 2017-11-25
    相关资源
    最近更新 更多