my ionic2 app get data from cordova plugin,but input's value had not update automatic.thank you first.
my demo code:
import { Component } from '#angular/core';
import { NavController, Events } from 'ionic-angular';
declare var AMapPlugin;
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
gps: string = '';
_distance: number = 0;
constructor(public navCtrl: NavController, private event: Events) {
}
getDistance() {
return new Promise<number>((resolve, reject) => {
AMapPlugin.getDistance(data => {
resolve(data);
});
});
}
location() {
AMapPlugin.startLocation(10, success => {
let lo = { lat: success.latitude, lng: success.longitude };
this.gps = JSON.stringify(lo);
}, error => {
});
}
start() {
this.getDistance().then(data => {
this._distance = data;
});
}
}
location will trigger gps 10 seconds per time,but html value not realtime modify.
<ion-item>
<ion-label>distance</ion-label>
<ion-input type="text" [(ngModel)]="_distance" readonly></ion-input>
</ion-item>
<ion-item>
<ion-label>current</ion-label>
<ion-input type="text" [(ngModel)]="gps | async" readonly></ion-input>
</ion-item>
You have to detect the change manually. Use ngZone or another change detector in angular, check this answer
Related
I am very new to ionic and angular.
Anyway, I am trying to following an tutorial to create a notes app using ionic4 https://www.joshmorony.com/building-a-notepad-application-from-scratch-with-ionic/.
So, I follow the instruction. Everything is ok except that the view doesn't updated when I add new note. The code is as follow:
Note services:
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
import { Note } from '../interfaces/note';
#Injectable({
providedIn: 'root'
})
export class NotesService {
public notes: Note[] = [];
public loaded: boolean = false;
constructor(private storage: Storage) {
}
load(): Promise<boolean> {
// Return a promise so that we know when this operation has completed
return new Promise((resolve) => {
// Get the notes that were saved into storage
this.storage.get('notes').then((notes) => {
// Only set this.notes to the returned value if there were values stored
if (notes != null) {
this.notes = notes;
}
// This allows us to check if the data has been loaded in or not
this.loaded = true;
resolve(true);
});
});
}
save(): void {
// Save the current array of notes to storage
this.storage.set('notes', this.notes);
}
getNote(id): Note {
// Return the note that has an id matching the id passed in
return this.notes.find(note => note.id === id);
}
createNote(title): Promise<boolean> {
return new Promise((resolve) => {
// Create a unique id that is one larger than the current largest id
let id = Math.max(...this.notes.map(note => parseInt(note.id)), 0) + 1;
this.notes.push({
id: id.toString(),
title: title,
content: ''
});
this.save();
console.log('Service Log ' + this.notes);
resolve(true);
});
}
}
The HTML code:
<ion-header>
<ion-toolbar color="primary">
<ion-title>Notes</ion-title>
<ion-buttons slot="end">
<ion-button (click)="addNote()">
<ion-icon slot="icon-only" name="clipboard"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item button detail *ngFor="let note of notesService.notes" [href]="'/notes/' + note.id" routerDirection="forward">
<ion-label>{{ note.title }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
I've followed the same tutorial and got the same issue. The issue is because of something very interesting and powerful called Zones.
The idea is that you'd need to let Angular know that the array with the notes has changed, by doing something like this:
// Angular
import { Component, NgZone } from '#angular/core';
// Ionic
import { NavController, AlertController } from '#ionic/angular';
// Services
import { NotesService } from '../services/notes.service';
import { AlertOptions } from '#ionic/core';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(
private ngZone: NgZone, // Add this in the constructor
private navCtrl: NavController,
private alertCtrl: AlertController,
private notesService: NotesService,
) { }
ngOnInit() {
this.notesService.load();
}
addNote() {
const alertOptions: AlertOptions = {
header: 'New Note',
message: 'What should the title of this note be?',
inputs: [
{
type: 'text',
name: 'title'
}
],
buttons: [
{
text: 'Cancel'
},
{
text: 'Save',
handler: (data) => {
// Create the note inside a Zone so that Angular knows
// that something has changed and the view should be updated
this.ngZone.run(() => {
this.notesService.createNote(data.title);
});
}
}
]
};
this.alertCtrl
.create(alertOptions)
.then((alert) => {
alert.present();
});
}
}
I am trying to achieve a log out functionality. I am using FB authentication. My problem here is after I do a logout successfully(This happens from the Side menu ) I return to the Login Screen. But now if I tap the device's back button it is taking me to the homepage(. Any idea how to prevent this ?
This is my app.component.ts
import { Component, ViewChild } from '#angular/core';
import { Platform, Nav, AlertController } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { LoginPage } from '../pages/login/login';
import { NativeStorage } from '#ionic-native/native-storage';
import { TabsPage } from '../pages/tabs/tabs';
import { Facebook } from 'ionic-native';
#Component({
templateUrl: 'app.html',
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage: any = LoginPage;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, private nativeStorage: NativeStorage, private alertCtrl: AlertController) {
platform.ready().then(() => platform.ready().then(() => {
this.nativeStorage.getItem("userId").then((data) => {
console.log(data.userExists);
this.rootPage = TabsPage;
this.nav.push(TabsPage);
}, (error) => {
console.log("No data in storage");
this.nav.push(LoginPage);
})
statusBar.styleDefault();
splashScreen.hide();
})
)
}
presentConfirm() {
let alert = this.alertCtrl.create({
title: "Confirm Logout",
message: "Do you really really want to quit this awesome app?",
buttons: [{
text: 'Nah! Just Kidding!', role: 'cancel', handler: () => {
}
},
{
text: "Ok",
handler: () => {
this.nativeStorage.clear();
this.nav.push(LoginPage);
this.rootPage = LoginPage;
Facebook.logout().then((response) => {
}, (error) => {
})
}
}]
});
alert.present();
}
}
This is my login page. Login.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Facebook } from 'ionic-native';
import { NativeStorage } from '#ionic-native/native-storage';
import { TabsPage } from '../tabs/tabs'
#Component({
selector: 'login-home',
templateUrl: 'login.html'
})
export class LoginPage {
constructor(public navCtrl: NavController, private nativeStorage: NativeStorage) {
}
FBLogin() {
//this.navCtrl.push(TabsPage); - To be used on browser environment
Facebook.login(['email']).then((response) => {
Facebook.getLoginStatus().then((response) => {
if (response.status == 'connected') {
this.navCtrl.push(TabsPage); // - to be used on device
console.log("Setting Storage")
this.nativeStorage.setItem("userId", { userExists: true });
Facebook.api('/' + response.authResponse.userID + '?fields=id,name,gender', []).then((response) => {
}, (error) => {
alert(error)
})
}
else
alert("Not Logged in");
})
}, (error) => {
console.log((error));
})
}
}
This is my Menu
<ion-menu swipeEnabled="false" side="right" [content]="content">
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<p> </p>
<button menuClose padding-top ion-item> Test 1 </button>
<button menuClose ion-item> Test 2 </button>
<button menuClose ion-item (click)="presentConfirm()"><ion-icon name="power"></ion-icon> Logout </button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav id="nav" [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>
Your issue is you are doing:
this.nav.push(LoginPage);
in your logout handler.
This means LoginPage is added on top of your old navigation stack. You need to set a new stack and set LoginPage as root.
Do :
this.nav.setRoot(LoginPage);
.Am working on an app using ionic 2. I have my data in couchdb about 9 differents items. How can i display each data from the database corresponding to the item clicked. The items are in a list?
This s the provider diagnosis.ts
import { Injectable } from '#angular/core';
import PouchDB from 'pouchdb';
#Injectable()
export class Diagnosis{
data: any;
db: any;
remote: any;
constructor() {
this.db = new PouchDB('ezy');
this.remote = 'http://localhost:5984/ezy';
let options = {
live: true,
retry: true,
continuous: true
};
this.db.sync(this.remote, options);
}
getTodos() {
if (this.data) {
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.db.allDocs({
include_docs: true
}).then((result) => {
this.data = [];
let docs = result.rows.map((row) => {
this.data.push(row.doc);
});
resolve(this.data);
this.db.changes({live: true, since: 'now', include_docs: true}).on('change', (change) => {
this.handleChange(change);
});
}).catch((error) => {
console.log(error);
});
});
}
createTodo(todo){
this.db.post(todo);
}
getTodo(todo){
this.db.get(todo);
}
updateTodo(todo){
this.db.put(todo).catch((err) => {
console.log(err);
});
}
deleteTodo(todo){
this.db.remove(todo).catch((err) => {
console.log(err);
});
}
handleChange(change){
let changedDoc = null;
let changedIndex = null;
this.data.forEach((doc, index) => {
if(doc._id === change.id){
changedDoc = doc;
changedIndex = index;
}
});
//A document was deleted
if(change.deleted){
this.data.splice(changedIndex, 1);
}
else {
//A document was updated
if(changedDoc){
this.data[changedIndex] = change.doc;
}
//A document was added
else {
this.data.push(change.doc);
}
}
}
}
provider usage is as
.ts
constructor(public navCtrl: NavController, public navParams: NavParams,public diagnose:Diagnosis) {
this.pet = "puppies";
console.log(diagnose.getTodos());
diagnose.getTodos().then(result=>{
this.pest = result;
console.log(result);
})
}
.html
<ion-grid>
<ion-row>
<ion-col *ngFor="let val of pest" width-100>
<ion-list>
<ion-item><h3>{{val.name}}</h3></ion-item>
<ion-item><h3>{{val.description}}</h3></ion-item>
<ion-item><h3>{{val.disease}}</h3></ion-item>
<ion-item><h3>{{val.prevention}}</h3></ion-item>
</ion-list>
</ion-col>
</ion-row>
</ion-grid>
I'm not sure what you want.. If you need to display clicked item what you have to do is add (click) event where you call a function sending the item (Again, I don't know if you are asking this)...
<ion-item (click)="viewItem(val.prevention)"><h3>{{val.prevention}}</h3></ion-item>
I have an ion-list with a ngFor loop. Here is the html:
<ion-list>
<ion-item *ngFor="let kiosk of kiosks" (click)="goToKioskProfilePage(kiosk)">
{{kiosk.name}}
</ion-item>
</ion-list>
And here is the constructor:
kiosks: any;
constructor(public navCtrl: NavController, navParams: NavParams, public locationTracker: LocationTracker, public api: ApiService, public zone: NgZone) {
this.kiosks = [];
this.zone.run(() => {
this.locationTracker.getGeolocation().then(location => {
this.api.getClosestKiosks(location, constants.AMOUNT_OF_CLOSEST_KIOSKS).then(
data => {
console.log("ready");
this.kiosks = data['data'];
},
err => {
console.log(err);
}
);
});
});
}
The console logs "ready" but the list does not update. I already tried it with NgZone but it's still not working. Only when I open the sidemenu the list updates, but not before. Someone know how to fix that?
I've encountered a similar issue before. What fixed it for me was putting only the variable update/assignment in between zone.run(), as it's after the promise resolves that you want to update the values.
Try:
this.locationTracker.getGeolocation().then(location => {
this.api.getClosestKiosks(location, constants.AMOUNT_OF_CLOSEST_KIOSKS).then(
data => {
console.log("ready");
this.zone.run(() => {
this.kiosks = data['data'];
});
},
err => {
console.log(err);
}
);
});
I have created an Ionic2 App using cordova FileTransferplugin, i am downloading remote server file.
Everything is working perfectly, but when I try to update template while fileTransfer.OnProgress event, the template is not updating the % downloaded.
Pleas see this video for my problem.
Ionic_youtube_link
My Code is, logic is in downloadFile function
import {Component, AfterViewInit, ViewChild} from '#angular/core';
import {NavController, NavParams, ViewController, Nav} from 'ionic-angular';
import {Page, Platform} from 'ionic-angular';
import {File, Device, Cordova, Transfer} from 'ionic-native';
import { SafeResourceUrl, DomSanitizationService } from '#angular/platform-browser';
#Component({
templateUrl: 'build/pages/video-download-modal/video-download-modal.html',
providers: [File, Transfer]
})
export class VideoDownloadModal {
selectedItem: any;
#ViewChild(Nav) nav: Nav;
videoPathUrl: string;
isPlatformReady: boolean;
platformName: string;
directoryName: string = "socialAppDir";
totalVideoSize:number;
totalDownloaded:number;
totalPercent:string = "0%";
constructor(public navCtrl: NavController, navParams: NavParams, private _viewController: ViewController, platform: Platform, private transfer:Transfer) {
// If we navigated to this page, we will have an item available as a nav param
if (platform.is('core')) {//if on dekstop
console.log('dektop');
} else {
this.videoPathUrl = navParams.get('videoPath');
console.log(this.videoPathUrl);
platform.ready().then((readySource) => {
this.isPlatformReady = true;
console.log('ready 1234');
const fs: string = cordova.file.externalRootDirectory;
console.log(cordova.file.dataDirectory);
this.platformName = Device.device.platform;
File.checkDir(cordova.file.externalDataDirectory, this.directoryName).then(() => {
console.log('directory exists');
this.downloadFile();
}, (error) => {
console.log('directory not exists');
this.createDirectory();
})
})
}
}
dismiss() {
let data = { 'foo': 'bar' };
this._viewController.dismiss(data);
}
createDirectory():void{
File.createDir(cordova.file.externalDataDirectory, this.directoryName, true).then(() => {
console.log("created externalDataDirectory");
this.downloadFile();
},(error) => {
console.log('some error happen')
})
}
downloadFile = () => {
console.log(this);
let fileName: string = this.videoPathUrl.split("/").pop();
let targetPath = cordova.file.externalDataDirectory + this.directoryName + "/" + fileName;
console.log(targetPath);
this.transfer.download(this.videoPathUrl, targetPath, true, {}).then(() => {
console.log('video downloaded')
}, (error) => {
console.log(error)
})
this.transfer.onProgress((progress) => {
console.log(this);
this.totalVideoSize = progress.total;
this.totalDownloaded = progress.loaded;
this.totalPercent = ((progress.loaded / progress.total) * 100).toString();
console.log(this.totalPercent);
})
}
ionViewDidEnter() {
console.log("enter login1");
}
}
And HTML is
<ion-content>
<div id="modalContainer" class="abd">
<ion-spinner></ion-spinner>
<br />
{{**totalPercent**}}
<br />
<button dnager block (click)="dismiss()">Exit</button>
</div>
</ion-content>
The totalPercent value either has 0 or 100.But not updating.
Please help.
This is because the totalPercent of this inside the handler was set to the global Window object instead of the object itself.
I have finally got it to work
import { NgZone } from '#angular/core';
fileTransfer.onProgress((progressEvent: ProgressEvent) => {
this.ngZone.run(() => {
if (progressEvent.lengthComputable) {
let lp = progressEvent.loaded / progressEvent.total * 100;
this.loadingPercent = Math.round(lp * 100) / 100;
}
});
})