Ionic 3 and Ngzone is not working - not updating the results to HTML view
Asked Answered
D

1

7


I want to perform some action after Bluetooth connection is done and vice versa.
Handled scenarios for connection and added success and failure handler also, and changing a flag to True and False in those handler functions.
I printed that value using console.log, it changes in a component file but does not reflect in HTML.
I tried using ngZone, but it's not working.
Success and failure handle code are as follows:

BluetoothService

import { Injectable } from "@angular/core";
import { BLE } from '@ionic-native/ble';


@Injectable()
export class BlueToothService {

    constructor(private ble: BLE){
    }

     public connect = (deviceId, onConnect, onFailure) => {
        this.ble.isConnected(deviceId)
            .then(response => {                   
                onConnect(response);
            },
            error =>  {
                this.ble.connect(deviceId)
                    .subscribe(response => {
                        onConnect(response);
                    },
                    error =>  {
                        onFailure(error);         
                    });            
        });
    } }

Component File

import {Component, NgZone} from '@angular/core';
import {Events, IonicPage, NavController, NavParams, ViewController} from 'ionic-angular';

import {BlueToothService} from '../../../providers/bluetooth/bluetooth.service';

@IonicPage()
@Component({
    selector: 'test-data',
    templateUrl: 'test-data.html',
})
export class AddTestKitDataPage {
    public isBluetoothConnected: boolean = false;
    public deviceId: any;

    public connectToBLE() {
        this.blueToothService.connect(this.deviceId, onConnectionSuccess, onConnectionFailure);  //Assume device id is already present
    }

    private onConnectionSuccess = (reason) => {
        this.zone.run(() => {
            this.isBluetoothConnected = true;       
        });
    };

    private onConnectionFailure = (reason) => {
        this.zone.run(() => {
            this.isBluetoothConnected = false;
        });
    } }

HTML

<ion-content>

    <div text-center *ngIf="!isBluetoothConnected">
        Bluetooth Connection failure
    </div>

    <div text-center *ngIf="isBluetoothConnected">
        Bluetooth Connection success
    </div>

    <button ion-button full class="primaryBlockButton" (click)="connectToBLE()">Click</button>

</ion-content>
Debouch answered 15/5, 2018 at 11:20 Comment(11)
where is onConnectionSuccess called?Kure
it's passed as this.bluetoothService.connect(this.onConnectionSuccess, this.onConnectionFailure);Debouch
Can you edit your post to provide the minimal reproducible example?Kure
@SurajRao, added code.Debouch
All console logs are printed? but if is not toggled?Kure
Yes. Not toggled and changed at view section.Debouch
So what is the reason to use zones here? By default angular won't do change detection for state change of bluetooth, correct?Ladylike
if console.log shows changes OK and the view is not updating - this means Angular is not picking up a change here. Try this hack: private onConnectionSuccess = (reason) => { this.zone.run(() => { setTimeout(()=>{ this.isBluetoothConnected = true; console.log("isBluetoothConnected---", this.isBluetoothConnected); },0) }); };Ladylike
@SergeyRudenko, Hack works for me.Debouch
Cool. Basically this means for change detection to happen you need a proper trigger. This “hack” is using async function that angular cares about hence it works. So to avoid hack you may need to use other approach that makes angular run the check or use change detection methodsLadylike
See this: #34827834Ladylike
L
4

Since console.log does confirm that in your case data actually changes, while the view (template) is not getting an update - this hints that Change Detection is not taking place.

To validate that you did already try the "hack" and according to you in comments it worked:

private onConnectionSuccess = (reason) => { 
    this.zone.run(() => { 
        setTimeout(() => { 
            this.isBluetoothConnected = true; 
            console.log("isBluetoothConnected---", this.isBluetoothConnected); 
        },0) 
     }); 
};

Basically the hack "wraps" your data change into an async (setTimeout) activity that Angular picks up.

Now to address it you could either ensure that data change in your case happens via event that Angular picks up naturally (add custom even listener for example).

Or try to use change detection to detectChanges manually after data changed:

import CDR:

import { ChangeDetectorRef } from '@angular/core';

inject it:

constructor (private cdr: ChangeDetectorRef) {}

Add it to your method:

private onConnectionSuccess = (reason) => { 
    this.isBluetoothConnected = true; 
    console.log("isBluetoothConnected---", this.isBluetoothConnected);
    this.cdr.detectChanges();
};

Try this approach as I think it will be better than the hack.

Ladylike answered 16/5, 2018 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.