Page does not update after BLE scan

Hello, I’m having trouble showing two beacons BLE credentials within an array. If I capture the beacons credentials in a string var they display one after the other. If I try to push the credentials into an array and ngFor diplay them, they do not show.
This code updates the screen:

 data: string;
scanBLE() {
    this.services = this.ble.scan([], 20);
   
    this.services.subscribe(
      data => { 
        this.data = JSON.stringify(data); 
        this.applicationRef.tick();
      },
      error => { this.error = error}
    );
}
//template
<ion-list>
    <ion-item>
      {{data}}
    </ion-item>
</ion-list>

This code does not update the screen

data: any[];
scanBLE() {
    this.services = this.ble.scan([], 20);
   
    this.services.subscribe(
      data => { 
        this.data.push(data); 
        this.applicationRef.tick();
      },
      error => { this.error = error}
    );
}
//template
<ion-list *ngFor="let device of data">
    <ion-item>
      {{device | json}}
    </ion-item>
</ion-list>

What could be going wrong?

This is the actual project. The only difference between the two pages is in the manner in which I store the data from observable. Someone please run it on their phone. First run npm install to get the node modules.
BLEConnectProject

@DevorahT
mmmm… you forgot to initialize your array
in home.ts
replace
devices: Array<any>;
with
devices: Array<any>= [];
and that should fix it
that in the code in Dropbox
as for the code in the post
data: any[]=[];

1 Like

@MarcusIII that WAS the problem. Thank you for taking the time.

1 Like

applicationRef.tick() seems like using a nuclear bomb to swat a fly. Is that really needed?

2 Likes

@rapropos I tested the app without it and it will show the devices only if I click the button twice. I changed it from

private ref: ApplicationRef

to:

private ref: ChangeDetectorRef

and it detects the devices instantaneously as opposed to a 2 second delay. So yeah, maybe you where right.

1 Like

This confuses me. scan is returning an Observable, and Observables are change detection and zone-aware. The changes made to this.data in that subscription should be reflected in the template without you having to do anything else. Now that the initialization problem has been solved, is there a chance you can try just commenting out the manual change detection altogether?

@rapropos just tried it and it does not update. I have to click the button twice. I’m using BLE and Paul Halliday has a youtube tutorial that uses Eddystone protocol. He needed to use ChangeDetectorRef there too. ¯_(ツ)_/¯

1 Like

So this is an update: BLE is really spotty. Sometimes I get a response other times not. I went all day yesterday without being able to connect to my beacons - simply no response or so I thought. My screen would update if I rotated my phone 90 degrees (which I discovered by pure luck). I made a few changes and it seems to be more consistent. Rather than using ChangeDetectorRef I wrap the body of my function within a zone based on this blog post: Angular 2 Change Detection Zones An An Example

constructor (private zone: NgZone){}

scanBLE() {
  
  this.scanZone += this.zone.run(() => {
    this.services = this.ble.scan([], 20);
    
    this.services.subscribe(
      data => {  
          this.elements++;
          this.devices.push(JSON.stringify(data)); 

          //this.ref.detectChanges(); WAS HERE
      },
      error => { this.error = error}
    );

    return 1;
  });

}

Much more consistent.

Glad it’s working, but still shouldn’t be something that app code should have to be worrying about. If I had the requisite equipment to repro this, I would file an issue on ionic-native about it, although maybe there isn’t much that can be done at that level.

Fundamentally, Observables are supposed to be zone-aware, so they should always call their subscriptions from within the proper zone. I can’t think of any reason this would be an exception.

Yes I may bring it up with them. The problem is compounded by the fact that one can never be sure if the problem lies with the phone, the beacon or the app. It was working fine earlier, now it refuses to connect. So it must be a hardware issue. I don’t know. BLE is frustrating.

Here is the latest iteration of the project. It is a bit convoluted but you will see that I tried to track and record the data every step of the way. It may give you a head start if you decide to work with beacons.

BLEProject_V.01

1 Like

Finally discovered the last problem. I was lamenting the inconsistent discovery and connection of devices. Although it forced me to write a better connection method most of the problems resided in the functionality of the beacons or my ignorance of them. These beacons are meant to run for 2 years on a coin battery and so have power saving techniques built in. One of them being that if they are resting on their back, they turn off. If they are upright as they would be if you attached them to a wall, they turn on. If you move or shake them, they turn on. This explains the spotty connections. I was moving them close to my phone, setting them on the desk, sometimes upright others not.

Now if I place them upright, the code works every time instantaneously.

2 Likes

Yeah, I think it is broken. The observable can write the data to console, but the template value doesn’t get updated.

Using NgZone and zone.run() also allows the template to be updated.

Which is the better way to update the display…

NgZone, or ChangeDetectorRef ??