ionic:ng在数组更改后不自动更新

问题描述 投票:2回答:4

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

这个Cordova插件使用回调,其中离子包含在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<Array>而不是一个可观察的单个对象。所以我放弃了Observable并使用了一个数组。异步管道不再工作,所以我不得不修改列表:

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

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

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)中你需要做什么才能在列表中添加一个元素?

angular ionic-framework ionic3 ngfor
4个回答
5
投票

试试detectChanges()而不是markForCheck()

也许你想看看this aproach

作者使用ngZones run()将找到的设备添加到列表中,其中包括changeDetection。非常有趣的imho。这是一个nice article about ngZone


2
投票

这是最终奏效的:

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

1
投票

我找到的另一个解决方案是使用对页面上运行的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
}

-2
投票

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

   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>
© www.soinside.com 2019 - 2024. All rights reserved.