Reputation: 1
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:
zonedCallback()
ngZone.run()
collapsed
or visible
*ngIf
and Visibility
propertiesRenderer.listen
Observable
class (import { Observable } from "data/observable"
) with the .notify()
functionality to emit an event + listen to that event in NSAppComponent. BluetoothScanner
would extend Observable
BehaviorSubject
object (import { Observable } from "rxjs/BehaviorSubject"
)changeDetectorRef
object to call for an update of the UI after updating the variableThrough 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).
Upvotes: 0
Views: 2248
Reputation: 9670
No need to use Observable within N+Angular-2 application - use the angular binding techniques instead. Another thing I noticed is that you are also using the binding syntax for vanilla NativeScript which is not compatible with the binding syntax for the N+Angular-2 application.
Here is the difference: NativeScript Core binding syntax:
visibility="{{ isBluetoothConnected ? 'collapsed' : 'visible' }}"
NativeScript + Angular-2 binding syntax:
[visibility]="isItemVisible ? 'visible' : 'collapsed'"
Example on how to bind the data from a callback can be found here basically, you should do the following
export class UsingConnectivityExampleComponent implements OnInit {
public connectionType: string; // use this variable to for binding in your html
constructor(private zone: NgZone) {
}
ngOnInit() {
connectivity.startMonitoring((newConnectionType: number) => {
this.zone.run(() => {
switch (newConnectionType) {
case connectivity.connectionType.none:
this.connectionType = "None"; // assign value
console.log("Connection type changed to none.");
break;
case connectivity.connectionType.wifi:
this.connectionType = "Wi-Fi"; // assign value
console.log("Connection type changed to WiFi.");
break;
case connectivity.connectionType.mobile:
this.connectionType = "Mobile"; // assign value
console.log("Connection type changed to mobile.");
break;
}
});
});
}
And finally bind it with the ng-2 syntax (the example shows one way binding)
<Label [text]="connectionType"></Label>
more about data binding in NativeScript+Angular-2 in this documentation article
p.s. When using TypeScript lambda you do not need to do the var that = this; to preserve the scope meaning of this within callbacks. Reference: https://basarat.gitbooks.io/typescript/content/docs/arrow-functions.html
Upvotes: 5