离子新手在这里。我使用的是Ionic 3和BLE插件。此插件的工作方式是您开始扫描蓝牙设备,每次新的扫描结果都会通知您,然后在您完成后取消扫描。我每次收到新的扫描结果时都会尝试将元素附加到ion-list
。
这个Cordova插件使用回调,其中离子包含在Observables和Promises中。方法startScan
会返回Observable<any>
,并且&#34;任何&#34;}是一个对象,包含有关检测到的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)中将一个元素添加到列表中吗?
答案 0 :(得分:5)
尝试使用detectChanges()
代替markForCheck()
。
也许你想看看this aproach。
作者使用ngZones run()
将找到的设备添加到列表中,其中包括changeDetection。非常有趣的imho。这是nice article about ngZone
答案 1 :(得分:2)
这是最终奏效的:
this.ble.startScan([])
.subscribe(device => {
this.results.push(device);
this.changeDetector.detectChanges();
});
答案 2 :(得分: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
}
答案 3 :(得分:-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>