First of all, I’m new in AngularJS, Ionic and mobile programming, so be kind. I googled this and have no answer.
I’m programming a bluetooth app to control and view custom robot state. In the home page I’m listing bluetooth devices and once I select a device and connect I push to ControlPage. I have test (simulate) changes with this ControlPage as root and it works perfect, dynamic simulated changes are performnt in browser and in my phone. But when I use HomePage, select the device and connect, no changes in the view are performed. State variables change and data is send to the robot, but I’ve no live refresh from the components.
I paste some of the code:
HomePage
import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { AndroidFullScreen } from '@ionic-native/android-full-screen';
import { BluetoothSerial } from '@ionic-native/bluetooth-serial';
import { ControlPage } from '../control/control';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
devices = {
paired: null,
unpaired: null,
scanning: false
};
mostrar = {
conocidos: "none",
disponibles: "none"
};
constructor(public navCtrl: NavController,
private alertCtrl:AlertController,
private bluetoothSerial: BluetoothSerial,
private androidFullScreen: AndroidFullScreen) {
this.androidFullScreen.isImmersiveModeSupported()
.then(() => this.androidFullScreen.immersiveMode())
.catch((error: any) => console.log(error));
this.bluetoothSerial.enable();
this.devices.paired = null;
this.devices.unpaired = null;
this.devices.scanning = false;
//this.getBluetoothDevices("all");
}
scanAllDevices() {
if(this.devices.scanning === false) {
this.devices.paired = null;
this.devices.unpaired = null;
this.mostrar.conocidos = "none";
this.mostrar.disponibles = "none";
this.getBluetoothDevices("all");
}
}
getBluetoothDevices(from) {
if(this.devices.scanning === false) {
this.bluetoothSerial.isEnabled().then(data => {
if(data){
if(from === "paired" || from === "all") {
this.devices.paired = null;
this.bluetoothSerial.list().then(pairedDevices=> {
if(pairedDevices!= null){
if(pairedDevices.length > 0){
this.devices.paired = pairedDevices;
this.mostrar.conocidos = "inline";
}}
});
}
if(from === "unpaired" || from === "all") {
this.devices.unpaired = null;
this.devices.scanning = true;
this.bluetoothSerial.discoverUnpaired().then((unpairedDevices) => {
if(unpairedDevices!= null){
if(unpairedDevices.length > 0){
this.devices.unpaired = unpairedDevices;
this.mostrar.disponibles = "inline";
}}
this.devices.scanning = false;
});
}
}
}).catch(err => {
let alert = this.alertCtrl.create({
title: 'Bluetooth',
subTitle: 'Verifique su conexión bluetooth.',
buttons: ['Descartar']
});
alert.present();
});
} else {
let alert = this.alertCtrl.create({
title: 'Bluetooth',
subTitle: 'Scaneando...',
buttons: ['Descartar']
});
alert.present();
}
}
success = (data) => {
this.bluetoothSerial.isConnected().then(() => {
this.navCtrl.push(ControlPage, {
bluetoothSerial: this.bluetoothSerial
});
});
}
fail = (error) => {
let alert = this.alertCtrl.create({
title: error,
message: 'No hay conexión con este dipositivo',
buttons: [
{
text: 'Cancelar',
role: 'cancel',
handler: () => {
this.bluetoothSerial.disconnect();
}
}
]
});
alert.present();
}
connectTo(device: any) {
let alert = this.alertCtrl.create({
title: device.name,
message: '¿Se desea conectar con este dispositivo?',
buttons: [
{
text: 'Cancelar',
role: 'cancel',
handler: () => {
}
},
{
text: 'Conectar',
handler: () => {
this.bluetoothSerial.connect(device.address).subscribe(this.success, this.fail);
}
}
]
});
alert.present();
}
}
ControlPage:
import { Component } from '@angular/core';
import { NavParams } from 'ionic-angular';
import { BluetoothSerial } from '@ionic-native/bluetooth-serial';
@Component({
selector: 'page-control',
templateUrl: 'control.html'
})
export class ControlPage {
colorRunStop : string = "secondary";
iconRunStop : string = "play";
constructor(private navParams: NavParams) {
this.bluetoothSerial = navParams.get('bluetoothSerial');
this.robot.memory = new Uint8Array(256);
this.robot.registers = new Uint8Array(16);
this.getName();
this.bluetoothSerial.subscribeRawData().subscribe((data) => {
if(this.state.gettingName) this.stateGettingName(new Uint8Array(data));
});
}
ionViewWillLeave() {
this.bluetoothSerial.disconnect();
}
stateGettingName(bytes : Uint8Array) : void {
for(var i=0; i < bytes.length && this.state.gettingName; ++i) {
if(!this.state.retrievingData) {
if(bytes[i] == this.commands.START) {
this.state.retrievingData = true;
}
} else if(bytes[i] != this.commands.STOP) {
this.robot.name += String.fromCharCode(bytes[i]);
} else {
this.state.gettingName = false;
this.state.retrievingData = false;
}
}
}
getName() : void {
this.bluetoothSerial.write([this.commands.GETNAME]);
this.state.gettingName = true;
}
actionRunStop() : void {
if(this.state.running) {
this.iconRunStop = "play";
this.colorRunStop = "secondary";
this.showingElements = "inline";
this.state.running = false;
} else {
//this.bluetoothSerial.write([this.commands.RUN]);
this.state.gettingRegisters = true;
this.state.gettingMemory = true;
this.state.gettingPC = true;
this.state.gettingIR = true;
this.iconRunStop = "remove-circle";
this.colorRunStop = "danger";
this.showingElements = "none";
this.state.running = true;
}
alert("iconRunStop: "+this.iconRunStop+"\n"+
"colorRunStop: "+this.colorRunStop+"\n"+
"showingElements: "+this.showingElements+"\n"+
"showingSpinner: "+this.showingSpinner+"\n"+
"state.running: "+this.state.running);
}
}
<ion-header>
<ion-navbar color="primary">
<ion-title>
Conectado
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list [style.display]="showingElements" no-lines>
<ion-item>
<ion-label class="titles" stacked>Nombre del robot</ion-label>
</ion-item>
<ion-item>
<ion-label class="bot-info" >{{ robot.name }}</ion-label>
</ion-item>
<ion-item>
<ion-label class="titles" stacked>Memoria principal</ion-label>
</ion-item>
<ion-item>
<ion-label class="bot-info">{{ change.mem }}</ion-label>
<button ion-button round color="dark" type="button" item-right>
<ion-icon name="open"></ion-icon>
</button>
</ion-item>
<ion-item>
<ion-label class="titles" stacked>Registros</ion-label>
</ion-item>
<ion-item>
<ion-label class="bot-info">{{ change.reg }}</ion-label>
<button ion-button round color="dark" type="button" item-right>
<ion-icon name="open"></ion-icon>
</button>
</ion-item>
<ion-item>
<ion-label class="titles" stacked>Contador de programa</ion-label>
</ion-item>
<ion-item>
<ion-label class="bot-info">{{ change.pc }}</ion-label>
</ion-item>
<ion-item>
<ion-label class="titles" stacked>Registro de Instrucción</ion-label>
</ion-item>
<ion-item>
<ion-label class="bot-info">{{ change.ir }}</ion-label>
<button ion-button round color="dark" type="button" item-right>
<ion-icon name="open"></ion-icon>
</button>
</ion-item>
</ion-list>
<div *ngIf="showingElements == 'none'" >
<ion-spinner name="bubbles" ></ion-spinner>
<div class="spinnerText"> Ejecutando...</div>
</div>
</ion-content>
<ion-footer no-shadow>
<ion-grid>
<ion-row justify-content-around>
<ion-col>
<div align="center">
<button ion-button icon-only [color]="colorRunStop" full clear (click)="actionRunStop()" >
<ion-icon [name]="iconRunStop"></ion-icon>
</button>
</div>
</ion-col>
<ion-col>
<div align="center">
<button ion-button icon-only color="energized" full clear (click)="actionStep()" [disabled]="state.running" >
<ion-icon name="skip-forward"></ion-icon>
</button>
</div>
</ion-col>
<ion-col>
<div align="center">
<button ion-button icon-only color="dark" full clear [disabled]="state.running" >
<ion-icon name="repeat"></ion-icon>
</button>
</div>
</ion-col>
</ion-row>
</ion-grid>
</ion-footer>
In the code above the running state do not show the spinner. But when ControlPage is the root page it works… I don’t know what i’m doing wrong. And when I go back to the HomePage the spinner appears for a second in the leaving ControlPage. ¯_(ツ)_/¯
Please, help me! You’re my only hope.
PS: sorry about my english.
@AaronSterling was right, but i don’t understand why in the root page works without NgZone
.
(...)
constructor(private navParams: NavParams, zone : NgZone) {
(...)
//in some action performed:
this.zone.run( () => {
//changing values...
}
I suppose there is a better way to do this…