NLev
NLev

Reputation: 1

nativescript-angular - UI won't update when running a callback from a service

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:

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).

Upvotes: 0

Views: 2248

Answers (1)

Nick Iliev
Nick Iliev

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

Related Questions