如何在 Angular 4 和 IONIC 3 中使用 $apply 和 $digest?
How to $apply and $digest in Angular 4 and IONIC 3?
我正在尝试在 IONIC 3 中创建应用程序,但它似乎无法正确刷新视图。
我记得 $apply 和 $digest 会在 Angular 1X 中解决此类问题。
在 Angular 4 中是如何完成的?
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BLE } from '@ionic-native/ble';
@Component({
selector: 'page-led',
templateUrl: 'led.html'
})
export class LEDPage {
constructor(public navCtrl: NavController, private ble: BLE) {
this['myCount'] = 0;
this['valor'] = 0;
this['messages'] = [];
this['service_id'] = "19B10010-E8F2-537E-4F6C-D104768A1214";
this.setMessage("Constructor: Begin!");
this['ble'] = ble;
this['ComandoTXT'] = "FIND BLYNK";
this['targetDevice'] = {};
}
public Command(){
if(this['ComandoTXT']==="FIND BLYNK") {
this.findBlynk();
}
if(this['ComandoTXT']=== "CAMBIAR LED"){
//this.txData();
this.setMessage("CAMBIAR LED txData DISABLEd");
}
}
public findBlynk(){
this.setMessage("SCAN: Begin!");
this['ComandoTXT'] = "Scanning...";
let ble = this['ble'];
this.setMessage("SCAN: BLE ENABLE!");
ble.enable();
this.setMessage("SCAN: Setting Interval...");
this['intervalHandle'] = setInterval(() => { // SET AN INTERVAL THAT RUNS EVERY 3 Seconds
this.setMessage("INTERVAL: BLE SCAN...");
//https://ionicframework.com/docs/native/ble/
ble.scan([], 2 /*seconds (0) */).subscribe( data => { //DO SCAN DURING 1 SECOND
this.setMessage("SCAN SUBSCRIBER: " + data['id'] + ' | ' + data['name'] + ' | ' + data['rssi']);
if(data['name']=="Blynk"){
this.setMessage("SCAN SUBSCRIBER: BLYNK FOUND! STOPPED SCANNING!");
clearInterval(this["intervalHandle"]);
this["targetDevice"] = data;
this["ComandoTXT"] = "CAMBIAR LED";
let idx = 0;
while(idx<10000){
this["test"] = idx;
idx ++;
}
}
});
},2100);//END OF INTERVAL DEFINITION
}
/*
public findBlynk(){
this.setMessage("findBlynk: BEGIN...");
this['ComandoTXT'] = "Buscando...";
this.setMessage("findBlynk: BLE ENABLE...");
this['ble'].enable();
this.setMessage("findBlynk: encontrar()...");
this.ble.scan([],500).subscribe(deviceData=>{
this.setMessage("SUBSCRIBER: Found Device...");
let deviceMessage = deviceData.id + ":" + deviceData.name + "(" + deviceData.rssi + ")";
this.setMessage(deviceMessage);
if(deviceData.name == "Blynk"){
this.setMessage("BLYNK FOUND!");
this["ComandoTXT"] = "CAMBIAR LED";
this['dispositivo'] = deviceData;
this.ble.stopScan().then(() => {
this.setMessage('SCANNING STOPPED!');
});
} else {
//setTimeout(()=>{this.findBlynk();},500);
}
}, error=>{
this.setMessage("BLE SCAN ERROR");
this.setMessage(error.message);
setTimeout(()=>{this.findBlynk();},1000);
});
}
public txData(){
this.setMessage("txData: BEGIN! Doing ble connect...");
let id = this['deviceData'].id;
this.ble.connect(id).subscribe(datos=>{
this.setMessage("BLE CONNECT SUBSCRIBE: BEGIN. Doing ble write...");
this.ble.write(id,this['service_id'],this['service_id'],this['valor'].buffer).then(()=>{
this.setMessage("BLE WRITE THEN!");
this['valor'] = (this['valor'] + 1) % 2;
this.ble.disconnect(id);
},(error)=>{
this.setMessage("BLE Write ERROR!");
});
},error=>{
this.setMessage("BLE Connect ERROR!");
});
}
*/
/*
public conectar(id){
this.ble.connect(id).subscribe(datos=>{
this.escribir(id);
},error=>{
this.encontrar();
});
}
public escribir(id){
}
*/
public setMessage(message){
this['myCount'] ++;
message = this['myCount'] + ':' + message;
this['messages'].unshift(message);
}
}
<ion-header>
<ion-navbar>
<ion-title>LED </ion-title>
<button ion-button (click)="Command()">{{ComandoTXT}}</button>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>LED Messages: ({{myCount}} | {{test}})</p>
<hr />
<p *ngFor="let message of messages">{{message}}</p>
</ion-content>
您可以使用 LifeCycle::tick() 方法来完成。见下面代码
import {Component, LifeCycle, NgZone} from 'angular2/angular2'
@Component({
selector: 'my-app',
template: `
<div>
Hello world!!! Time: {{ time }}.
</div>
`
})
export class App {
time: number = 0;
constructor(lc: LifeCycle, zone: NgZone) {
zone.runOutsideAngular(() => {
setInterval(() => {
this.time = Date.now();
lc.tick(); // comment this line and "time" will stop updating
}, 1000);
})
}
doCheck() {
console.log('check', Date.now());
}
}
基本上问题是我不明白如何在 Typescript 中调用 ApplicationRef 对象。
所以我在 .ts 文件顶部的第 4 行添加了“import { ApplicationRef } from '@angular/core'
”,然后在第 28 行的构造函数私有“applicationRef : ApplicationRef
”中注入它,最终调用“this.applicationRef.tick();
" 在回调的末尾,例如第 81 行。
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BLE } from '@ionic-native/ble';
import { ApplicationRef } from '@angular/core'
@Component({
selector: 'page-led',
templateUrl: 'led.html'
})
export class LEDPage {
/**
* Constants that we will use around the controller
*/
public constants = {
CMD_FIND_ANGU:"FIND ANGU",
CMD_STOP_SCAN:"Scanning... (Click to Stop)",
CMD_TOGGLE_LED:"CAMBIAR LED",
ON:"ON",
OFF:"OFF"
};
/**
* Constructor for the controller. Everything begins here.
*/
constructor(public navCtrl: NavController, private ble: BLE, private applicationRef : ApplicationRef ) {
this['messages'] = [];
this['value'] = "ON FIRST TIME";
this['service_id'] = "19B10010-E8F2-537E-4F6C-D104768A1215";
this['characteristic_id'] = "19B10011-E8F2-537E-4F6C-D104768A1215";
this['ble'] = ble;
this['ComandoTXT'] = this.constants.CMD_FIND_ANGU;
this['targetDevice'] = {};
this.setMessage("Constructor: Begin!");
this["applicationRef"] = applicationRef;
}
/**
* This is triggered when the button is clicked.
*/
public Command(){
this.setMessage("COMMAND RECEIVED!");
this.setMessage(this["ComandoTXT"]);
if(this['ComandoTXT']===this.constants.CMD_FIND_ANGU) {
this['ComandoTXT'] = this.constants.CMD_STOP_SCAN;
this.findANGU();
} else if (this['ComandoTXT']===this.constants.CMD_STOP_SCAN) {
this.setMessage("Command: STOPING SCAN...");
clearInterval(this['intervalHandle']);
this['ComandoTXT'] = this.constants.CMD_FIND_ANGU;
} else if(this['ComandoTXT']=== this.constants.CMD_TOGGLE_LED){
this.setMessage("ComandoTXT = CAMBIAR LED: Calling txData()");
this.txData();
}
}
/**
* This searches for ANGU in the AIR using SCAN technique.
*/
public findANGU(){
this.setMessage("SCAN: Begin!");
let ble = this['ble'];
this.setMessage("SCAN: BLE ENABLE!");
ble.enable();
this.setMessage("SCAN: Setting Interval...");
this['intervalHandle'] = setInterval(() => { // SET AN INTERVAL THAT RUNS EVERY 3 Seconds
this.setMessage("INTERVAL: BLE SCAN...");
//https://ionicframework.com/docs/native/ble/
ble.scan([], 2 /*seconds (0) */).subscribe( data => { //DO SCAN DURING 1 SECOND
this.setMessage("SCAN SUBSCRIBER: " + data['id'] + ' | ' + data['name'] + ' | ' + data['rssi']);
if(data['name']=="COMANDO LED"){
this.setMessage("SCAN SUBSCRIBER: ANGU FOUND! STOPPED SCANNING!");
clearInterval(this["intervalHandle"]);
this["targetDevice"] = data;
this["ComandoTXT"] = this.constants.CMD_TOGGLE_LED;
}
this.applicationRef.tick();
});
},2100);//END OF INTERVAL DEFINITION
}
/**
* This transmits data to the selected ANGU device
*/
public txData(){
this.setMessage("txData: BEGIN! Doing ble connect...");
let id = this['targetDevice'].id;
this.setMessage(id);
this.ble.connect(id).subscribe(datos=>{
this.setMessage("BLE CONNECT SUBSCRIBE: BEGIN. Doing ble write..." + this["value"]);
this.ble.write(this['targetDevice'].id, this['service_id'],this['characteristic_id'], this.stringToBytes(this["value"]) ).then(()=>{
this.setMessage("BLE WRITE THEN:" + this["value"]);
if(this["value"]==this.constants.ON){
this["value"] = this.constants.OFF;
} else {
this["value"] = this.constants.ON;
}
this.ble.disconnect(id);
this.applicationRef.tick();
},(error)=>{
this.setMessage("BLE Write ERROR!");
this.setMessage(error);
this.ble.disconnect(id);
});
},error=>{
this.setMessage("BLE Connect ERROR!");
this.setMessage(error.message);
});
}
/**
* Adds message to the history on screen
*/
public setMessage(message){
var count = this['messages'].length;
message = count + ':' + message;
this['messages'].unshift(message);
this.applicationRef.tick();
}
// ASCII only
public stringToBytes(string) {
let array = new Uint8Array(string.length);
for (let i = 0, l = string.length; i < l; i++) {
array[i] = string.charCodeAt(i);
}
return array.buffer;
}
// ASCII only
public bytesToString(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
}
<ion-header>
<ion-navbar>
<ion-title>LED </ion-title>
<button ion-button (click)="Command()">{{ComandoTXT}}</button>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>LED Messages: ({{myCount}} | {{test}})</p>
<hr />
<p *ngFor="let message of messages">{{message}}</p>
</ion-content>
我正在尝试在 IONIC 3 中创建应用程序,但它似乎无法正确刷新视图。
我记得 $apply 和 $digest 会在 Angular 1X 中解决此类问题。
在 Angular 4 中是如何完成的?
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BLE } from '@ionic-native/ble';
@Component({
selector: 'page-led',
templateUrl: 'led.html'
})
export class LEDPage {
constructor(public navCtrl: NavController, private ble: BLE) {
this['myCount'] = 0;
this['valor'] = 0;
this['messages'] = [];
this['service_id'] = "19B10010-E8F2-537E-4F6C-D104768A1214";
this.setMessage("Constructor: Begin!");
this['ble'] = ble;
this['ComandoTXT'] = "FIND BLYNK";
this['targetDevice'] = {};
}
public Command(){
if(this['ComandoTXT']==="FIND BLYNK") {
this.findBlynk();
}
if(this['ComandoTXT']=== "CAMBIAR LED"){
//this.txData();
this.setMessage("CAMBIAR LED txData DISABLEd");
}
}
public findBlynk(){
this.setMessage("SCAN: Begin!");
this['ComandoTXT'] = "Scanning...";
let ble = this['ble'];
this.setMessage("SCAN: BLE ENABLE!");
ble.enable();
this.setMessage("SCAN: Setting Interval...");
this['intervalHandle'] = setInterval(() => { // SET AN INTERVAL THAT RUNS EVERY 3 Seconds
this.setMessage("INTERVAL: BLE SCAN...");
//https://ionicframework.com/docs/native/ble/
ble.scan([], 2 /*seconds (0) */).subscribe( data => { //DO SCAN DURING 1 SECOND
this.setMessage("SCAN SUBSCRIBER: " + data['id'] + ' | ' + data['name'] + ' | ' + data['rssi']);
if(data['name']=="Blynk"){
this.setMessage("SCAN SUBSCRIBER: BLYNK FOUND! STOPPED SCANNING!");
clearInterval(this["intervalHandle"]);
this["targetDevice"] = data;
this["ComandoTXT"] = "CAMBIAR LED";
let idx = 0;
while(idx<10000){
this["test"] = idx;
idx ++;
}
}
});
},2100);//END OF INTERVAL DEFINITION
}
/*
public findBlynk(){
this.setMessage("findBlynk: BEGIN...");
this['ComandoTXT'] = "Buscando...";
this.setMessage("findBlynk: BLE ENABLE...");
this['ble'].enable();
this.setMessage("findBlynk: encontrar()...");
this.ble.scan([],500).subscribe(deviceData=>{
this.setMessage("SUBSCRIBER: Found Device...");
let deviceMessage = deviceData.id + ":" + deviceData.name + "(" + deviceData.rssi + ")";
this.setMessage(deviceMessage);
if(deviceData.name == "Blynk"){
this.setMessage("BLYNK FOUND!");
this["ComandoTXT"] = "CAMBIAR LED";
this['dispositivo'] = deviceData;
this.ble.stopScan().then(() => {
this.setMessage('SCANNING STOPPED!');
});
} else {
//setTimeout(()=>{this.findBlynk();},500);
}
}, error=>{
this.setMessage("BLE SCAN ERROR");
this.setMessage(error.message);
setTimeout(()=>{this.findBlynk();},1000);
});
}
public txData(){
this.setMessage("txData: BEGIN! Doing ble connect...");
let id = this['deviceData'].id;
this.ble.connect(id).subscribe(datos=>{
this.setMessage("BLE CONNECT SUBSCRIBE: BEGIN. Doing ble write...");
this.ble.write(id,this['service_id'],this['service_id'],this['valor'].buffer).then(()=>{
this.setMessage("BLE WRITE THEN!");
this['valor'] = (this['valor'] + 1) % 2;
this.ble.disconnect(id);
},(error)=>{
this.setMessage("BLE Write ERROR!");
});
},error=>{
this.setMessage("BLE Connect ERROR!");
});
}
*/
/*
public conectar(id){
this.ble.connect(id).subscribe(datos=>{
this.escribir(id);
},error=>{
this.encontrar();
});
}
public escribir(id){
}
*/
public setMessage(message){
this['myCount'] ++;
message = this['myCount'] + ':' + message;
this['messages'].unshift(message);
}
}
<ion-header>
<ion-navbar>
<ion-title>LED </ion-title>
<button ion-button (click)="Command()">{{ComandoTXT}}</button>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>LED Messages: ({{myCount}} | {{test}})</p>
<hr />
<p *ngFor="let message of messages">{{message}}</p>
</ion-content>
您可以使用 LifeCycle::tick() 方法来完成。见下面代码
import {Component, LifeCycle, NgZone} from 'angular2/angular2'
@Component({
selector: 'my-app',
template: `
<div>
Hello world!!! Time: {{ time }}.
</div>
`
})
export class App {
time: number = 0;
constructor(lc: LifeCycle, zone: NgZone) {
zone.runOutsideAngular(() => {
setInterval(() => {
this.time = Date.now();
lc.tick(); // comment this line and "time" will stop updating
}, 1000);
})
}
doCheck() {
console.log('check', Date.now());
}
}
基本上问题是我不明白如何在 Typescript 中调用 ApplicationRef 对象。
所以我在 .ts 文件顶部的第 4 行添加了“import { ApplicationRef } from '@angular/core'
”,然后在第 28 行的构造函数私有“applicationRef : ApplicationRef
”中注入它,最终调用“this.applicationRef.tick();
" 在回调的末尾,例如第 81 行。
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BLE } from '@ionic-native/ble';
import { ApplicationRef } from '@angular/core'
@Component({
selector: 'page-led',
templateUrl: 'led.html'
})
export class LEDPage {
/**
* Constants that we will use around the controller
*/
public constants = {
CMD_FIND_ANGU:"FIND ANGU",
CMD_STOP_SCAN:"Scanning... (Click to Stop)",
CMD_TOGGLE_LED:"CAMBIAR LED",
ON:"ON",
OFF:"OFF"
};
/**
* Constructor for the controller. Everything begins here.
*/
constructor(public navCtrl: NavController, private ble: BLE, private applicationRef : ApplicationRef ) {
this['messages'] = [];
this['value'] = "ON FIRST TIME";
this['service_id'] = "19B10010-E8F2-537E-4F6C-D104768A1215";
this['characteristic_id'] = "19B10011-E8F2-537E-4F6C-D104768A1215";
this['ble'] = ble;
this['ComandoTXT'] = this.constants.CMD_FIND_ANGU;
this['targetDevice'] = {};
this.setMessage("Constructor: Begin!");
this["applicationRef"] = applicationRef;
}
/**
* This is triggered when the button is clicked.
*/
public Command(){
this.setMessage("COMMAND RECEIVED!");
this.setMessage(this["ComandoTXT"]);
if(this['ComandoTXT']===this.constants.CMD_FIND_ANGU) {
this['ComandoTXT'] = this.constants.CMD_STOP_SCAN;
this.findANGU();
} else if (this['ComandoTXT']===this.constants.CMD_STOP_SCAN) {
this.setMessage("Command: STOPING SCAN...");
clearInterval(this['intervalHandle']);
this['ComandoTXT'] = this.constants.CMD_FIND_ANGU;
} else if(this['ComandoTXT']=== this.constants.CMD_TOGGLE_LED){
this.setMessage("ComandoTXT = CAMBIAR LED: Calling txData()");
this.txData();
}
}
/**
* This searches for ANGU in the AIR using SCAN technique.
*/
public findANGU(){
this.setMessage("SCAN: Begin!");
let ble = this['ble'];
this.setMessage("SCAN: BLE ENABLE!");
ble.enable();
this.setMessage("SCAN: Setting Interval...");
this['intervalHandle'] = setInterval(() => { // SET AN INTERVAL THAT RUNS EVERY 3 Seconds
this.setMessage("INTERVAL: BLE SCAN...");
//https://ionicframework.com/docs/native/ble/
ble.scan([], 2 /*seconds (0) */).subscribe( data => { //DO SCAN DURING 1 SECOND
this.setMessage("SCAN SUBSCRIBER: " + data['id'] + ' | ' + data['name'] + ' | ' + data['rssi']);
if(data['name']=="COMANDO LED"){
this.setMessage("SCAN SUBSCRIBER: ANGU FOUND! STOPPED SCANNING!");
clearInterval(this["intervalHandle"]);
this["targetDevice"] = data;
this["ComandoTXT"] = this.constants.CMD_TOGGLE_LED;
}
this.applicationRef.tick();
});
},2100);//END OF INTERVAL DEFINITION
}
/**
* This transmits data to the selected ANGU device
*/
public txData(){
this.setMessage("txData: BEGIN! Doing ble connect...");
let id = this['targetDevice'].id;
this.setMessage(id);
this.ble.connect(id).subscribe(datos=>{
this.setMessage("BLE CONNECT SUBSCRIBE: BEGIN. Doing ble write..." + this["value"]);
this.ble.write(this['targetDevice'].id, this['service_id'],this['characteristic_id'], this.stringToBytes(this["value"]) ).then(()=>{
this.setMessage("BLE WRITE THEN:" + this["value"]);
if(this["value"]==this.constants.ON){
this["value"] = this.constants.OFF;
} else {
this["value"] = this.constants.ON;
}
this.ble.disconnect(id);
this.applicationRef.tick();
},(error)=>{
this.setMessage("BLE Write ERROR!");
this.setMessage(error);
this.ble.disconnect(id);
});
},error=>{
this.setMessage("BLE Connect ERROR!");
this.setMessage(error.message);
});
}
/**
* Adds message to the history on screen
*/
public setMessage(message){
var count = this['messages'].length;
message = count + ':' + message;
this['messages'].unshift(message);
this.applicationRef.tick();
}
// ASCII only
public stringToBytes(string) {
let array = new Uint8Array(string.length);
for (let i = 0, l = string.length; i < l; i++) {
array[i] = string.charCodeAt(i);
}
return array.buffer;
}
// ASCII only
public bytesToString(buffer) {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
}
}
<ion-header>
<ion-navbar>
<ion-title>LED </ion-title>
<button ion-button (click)="Command()">{{ComandoTXT}}</button>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>LED Messages: ({{myCount}} | {{test}})</p>
<hr />
<p *ngFor="let message of messages">{{message}}</p>
</ion-content>