【问题标题】:ionic: ngFor not updating automatically after changes in array离子:ngFor在数组更改后不会自动更新
【发布时间】:2018-08-09 16:27:10
【问题描述】:

离子新手在这里。我正在使用 Ionic 3 和 BLE 插件。这个插件的工作方式是你开始扫描蓝牙设备,每个新的扫描结果都会通知你,然后当你完成后取消扫描。我只是想在每次收到新的扫描结果时将一个元素附加到 ion-list 中。

这个 Cordova 插件使用 ionic 封装到 Observables 和 Promises 中的回调。方法startScan 返回一个Observable<any>,“any”是一个包含检测到的BLE 设备信息的对象。

我首先尝试将这个 observable 直接插入到 ngFor:

<ion-list>
    <button ion-item *ngFor="let result of results | async">
        {{ result | json}}
    </button>  
</ion-list>

开始扫描的调用返回了 observable:

this.results = this.ble.startScan([]);
this.results.subscribe(...);

但是我听说ngFor 仅适用于数组,因此它需要Observable&lt;Array&gt; 而不是单个对象的可观察对象。所以我放弃了 Observable 并使用了一个数组。异步管道不再工作,所以我不得不修改列表:

<ion-list>
    <button ion-item *ngFor="let result of results">
        {{ result | json}}
    </button>  
</ion-list>

然后将results的类型改为Array&lt;any&gt;。扫描代码现在看起来像这样:

this.ble.startScan([])
.subscribe(device => {
    this.results.push(device); //Does not work    
});

但是直到屏幕中的一些其他组件发生变化,列表才会显示。显然 Angular 不会检测 Array 元素内部的变化,它只检测对象内部引用和属性的变化。所以我尝试了这个无能的黑客:

this.ble.startScan([])
.subscribe(device => {
    this.results = this.results.concat([device]); //Does not work    
});

但即使这样也没有用。然后经过几个小时的阅读,我知道了这个叫做ChangeDetector的东西,据称它应该可以解决问题。我尝试了 OnPush 检测策略,默认也没有用:

this.ble.startScan([])
.subscribe(device => {
    this.results = this.results.concat([device]);
    this.changeDetector.markForCheck() //Does not work    
});

当然它不起作用,因为它只是标记检查,但在那一刻不执行检查。

TL;DR ELI5 你到底需要在 Ionic(或 Angular)中做什么才能将元素添加到列表中?

【问题讨论】:

  • 如果没有其他方法,您可以尝试:this.changeDetectorRef.detectChanges();。您可以在this post 中找到其他触发变更检测的方法。

标签: angular ionic-framework ionic3 ngfor


【解决方案1】:

尝试detectChanges() 而不是markForCheck()

也许你想看看this aproach

作者使用 ngZones run() 将找到的设备添加到列表中,其中包括 changeDetection。很有趣的恕我直言。这是nice article about ngZone

【讨论】:

    【解决方案2】:

    这终于奏效了:

    this.ble.startScan([])
    .subscribe(device => {
        this.results.push(device);
        this.changeDetector.detectChanges();
    });
    

    【讨论】:

      【解决方案3】:

      我发现的另一个解决方案是使用对页面上运行的 Angular 应用程序的引用,请参阅以下link,并调用它的 tick() 方法来显式处理更改检测及其副作用。我在 Ionic 中所做的如下:

      import { ApplicationRef } from '@angular/core';
      export class HomePage {
        constructor ( private app: ApplicationRef ) {}
      
        .. my code ...
      
        this.app.tick();  //start change detection to cause a screen update
      }
      

      【讨论】:

      • 实际上是 Ionic 4 中唯一对我有用的东西。我尝试过 ngZone.run、chDet.detectChanges()。
      【解决方案4】:

      您根本不必将数据推送到列表中。

         Consider you are returning data
      
          shoppingItems: FirebaseListObservable<any[]>;
      
          this.shoppingItems = af.list('/Items', {
              query: {
                  limitToLast: 1000
      
              }
          });
      
      
         If you are not using firebase then just return the data from service directly as below.
      
       this.shoppingItems = http('your service url'); 
      

      HTML

      <ul *ngFor="let item of shoppingItems | async" >
      
      <li>{{item.name}} </li>
      
      </ul>
      

      【讨论】:

        猜你喜欢
        • 2019-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多