I have a nativescript-angular app which runs a bluetooth service to connect to a peripheral (device). The app presents a label with a message indicating that no bluetooth device has been connected yet to the mobile device running the app. What I'm trying to do is to update the UI so that the label will disappear when a connection occurs (and reappear when a disconnection occurs).
app.component.tns.html
<StackLayout orientation="vertical" marginBottom="50">
<Label text="No bluetooth device detected." id="noBluetoothWarning" horizontalAlignment="center" color="#B11" *ngIf="bluetoothDisconnected" marginTop="30" visibility="{{ isBluetoothConnected ? 'collapsed' : 'visible' }}"></Label>
</StackLayout>
app.component.ts
export class NSAppComponent extends AppComponent implements OnInit {
pageData: Observable;
ngOnInit() {
this.bluetoothDisconnected = true;
let _page = <Page>topmost().currentPage;
_page.actionBarHidden = true;
_page.frame.bindingContext = this.pageData;
let that = this;
this.bluetoothScanner.connectionStateChangeEvent.subscribe((connectionState) => {
that.log.debug(`Am I in an angular zone? ${NgZone.isInAngularZone()}`);
this.ngZone.run(() => {
that.log.debug(`connectionStateEvent triggered! state is: ${connectionState}`);
that.bluetoothDisconnected = !connectionState;
that.pageData.set("isBluetoothConnected", connectionState);
that.pageData.notify({ object: that.pageData, eventName: Observable.propertyChangeEvent, propertyName: "isBluetoothConnected", value: connectionState });
this.pageData.notify({ object: that.pageData, eventName: Observable.propertyChangeEvent, propertyName: "bluetoothDisconnected", value: !connectionState });
})
});
}
constructor( @Inject(LogService) public log: LogService, private ngZone: NgZone) {
this.pageData = new Observable();
this.pageData.set("isBluetoothConnected", false);
this.bluetoothScanner = new BluetoothScanner(...);
}
}
bluetoothScanner.ts
export class BluetoothScanner {
private connectionState = new BehaviorSubject<boolean>(false);
...
that.connectionState.next(true);
}
You can see that the code is a mess, but the reason is that for over a month I've tried to use every single possible combination of actions I've been mentioned that might help me to get the UI to update - but to no avail.
Here are the following things I've previously attempted that did not work as well:
- wrap callback in
zonedCallback() - wrap callback in
ngZone.run() - manually update Component's variable value (which is used by the tns.html template)
- instead of setting a boolean value, I'd try to pass a literal string of
collapsedorvisible
- instead of setting a boolean value, I'd try to pass a literal string of
- use
*ngIfandVisibilityproperties - use angular's
Renderer.listen - use nativescript's
Observableclass (import { Observable } from "data/observable") with the.notify()functionality to emit an event + listen to that event in NSAppComponent.BluetoothScannerwould extendObservable - use rxjs
BehaviorSubjectobject (import { Observable } from "rxjs/BehaviorSubject") - use Angular's
changeDetectorRefobject to call for an update of the UI after updating the variable - set an Observable to be bound to the page. (note it's possible that I haven't properly set bound the Observable to the page object [based on what I've been trying to do in the code mentioned above]).
Through all of these, I was able to update the variable value, but not update the UI. The only thing that actually updated my UI was when I preformed the variable value change in a call that originated from a UI event (e.g. a button tap event handler).
thisobject in the closure rather than use thethatvariable as I do in my example, nothing changed in that case.