Dismiss loadingController from external provider - ionic-framework

I have implemented a provider which uses loadingController.
I'm able to show the loading screen but unable to dismiss it.
Currently I'm getting this error:
Code as follows:
export class CommonsProvider {
constructor(private toast: Toast,public loadingCtrl: LoadingController) {
}
showLoading(controlVariable,textToDisplay){
controlVariable = this.loadingCtrl.create({
content: textToDisplay
});
controlVariable.present();
}
cancelLoading(controlVariable){
console.log("controlVariable",controlVariable);
controlVariable.dismiss();
}
.TS (neither the following 2 below is able to work)
this.commonsProvider.showLoading("getUserAccount","Please wait...");
this.commonsProvider.cancelLoading("getUserAccount");
or
test:any;
...
this.test =this.commonsProvider.showLoading("getUserAccount","Please wait...");
this.commonsProvider.cancelLoading(this.test);

Based on #Suraj Rao ,
Using
public controlVariable:any; and in your function refer as this.controlVariable works.
Code:
cancelLoading(){
this.controlVariable.dismiss();
}

Related

How to connect a Phantom wallet to my Flutter web app?

I've been trying unsuccesfully to connect a Flutter web app to a Phantom wallet. No pub.dev packages have been released in order to accomplish this and can't figure out how to do it with dart-js interop.
Wondering if someone already figured it out?
I have a (crude) working piece of code that could be useful for somebody trying to accomplish the same:
// web/index.html
<script src="../lib/wallet.js" />
// wallet.js
class ClientWallet {
constructor() {
this.pubKey = '';
}
async connect() {
const resp = await window.solana.connect();
this.pubKey = resp.publicKey.toString();
}
address() {
return this.pubKey;
}
disconnect() {
window.solana.disconnect();
}
}
var walletModule = { ClientWallet: ClientWallet };
// main.dart
import 'package:js/js.dart';
import 'package:js/js_util.dart';
#JS('walletModule.ClientWallet')
class ClientWallet {
external Future<void> connect();
external void disconnect();
external String get pubKey;
}
Future<void> connectWallet() async {
ClientWallet wallet = ClientWallet();
await promiseToFuture(wallet.connect());
}
And then for connecting simply call connectWallet(). This works for me for the Phantom wallet, now I'm trying to integrate the Solana Dart package for signing a transaction.

How to handle two calls and the loading controller in Ionic 4

I have a requirement where I have 2 API calls, and I want the first two calls to be there for the first request. And 2nd API call to be there when navigated back.
I am calling 1st API in ngOnInit webhook and 2nd API on ionViewWillEnter webhook.
The issue which I am facing is sometimes my loader doesn’t get dismissed when both of the request complete at the same time.
So the possible solution which I am thinking is that if I could call both APIs on the first load synchronously and thereafter call another API every time the back button is clicked.
NOTE: I am using loaders in my interceptor.
CODE: For interceptor
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Clone the request to add the new header.
const authReq = req.clone();
this.showLoading();
// send the newly created request
return next.handle(authReq).pipe(catchError((error) => {
if (error.status === 401) {
this._navCtrl.navigateForward('/login');
}
return throwError(error);
}), finalize( () => {
console.log('hi');
this.dismissLoading();
})
);
}
EDIT:
Code to show loader and hide loader:
async showLoading() {
return await this._loadingCtrl.create().then(a => {
a.present();
});
}
async dismissLoading() {
return await this._loadingCtrl.dismiss();
}
In my case, I will create a LoaderService to handle the Loading by myself. The special thing is I will create a flag called isShowing, so if the loading is already showing, we just need to update the loading message by calling presentLoader function again. There will be only one Loading popup show up on your screen.
In your case, I would not recommend to display the Loader in HTTP Interceptor because we cannot handle the HTTP call stack there. Just create a new function that combines all necessary API calls and show/dismiss popup when you start/finish processing the data.
import { LoadingController } from '#ionic/angular';
import { Injectable } from '#angular/core';
#Injectable()
export class LoaderService {
private loading: HTMLIonLoadingElement;
private isShowing = false;
constructor(private loadingController: LoadingController) {}
public async presentLoader(message: string): Promise<void> {
if (!this.isShowing) {
this.loading = await this.loadingController.create({
message: message
});
this.isShowing = true;
return await this.loading.present();
} else {
// If loader is showing, only change text, won't create a new loader.
this.isShowing = true;
this.loading.message = message;
}
}
public async dismissLoader(): Promise<void> {
if (this.loading && this.isShowing) {
this.isShowing = false;
await this.loading.dismiss();
}
}
}
The simple solution would be to make a function call whenever you click the bak button and inside the function you can make a API call.
Instead of linking to the back button you can use ionViewWillEnter, which is called whenever you are about to leave a page but the downside would be it is called every time view is changed regardless of the fact that only when back button is clicked.
Also you should check, is your service singleton and it creates a single instance of ionic-loader. I think in your case more than one instance of loader is being created.
Also instead of calling the loader in interceptor, you can call showLoading() in ionViewWillEnter and hideLoading() in ionViewDidEnter() of your page.
You can create a Singleton Loader Service as shown below.
This service will take care of creating only a single instance of ionic loader.
import { Injectable } from '#angular/core';
import { LoadingController } from '#ionic/angular';
#Injectable({
providedIn: 'root'
})
export class LoaderService {
private loader: HTMLIonLoadingElement;
constructor(private loadingController: LoadingController) {}
async showLoader() {
if (!this.loader) {
this.loader = await this.loadingController.create({ message: 'Loading' });
}
await this.loader.present();
}
async hideLoader() {
if (this.loader) {
await this.loader.dismiss();
this.loader = null;
}
}
}
private loading: HTMLIonLoadingElement;
constructor(public loadingController: LoadingController) { }
public async show(): Promise<void> {
return await this.loadingController.create({
message: 'Please wait...',
spinner: 'crescent'
}).then(a => {
a.present().then(() => {
console.log('presented');
});
});
}
return await this.loadingController.dismiss().then(() =>
console.log('dismissed'));
}`enter code here`

Ionic 3 NavController does not pop the view instead creates a new one

The ionViewDidLoad function seem to get called twice, which is causing multiple views being created of AddressPage. I have debugged this and it looks like whenever data is updated the new instance of view gets created. This behaviour seems to happen only when I use fireabse to save the address. If I comment out the code to save the address new view is not created and app navigates to previous screen.
Any way to avoid this?
I have tried ViewCotnroller.dismiss() and NavController.pop() inside saveAddress method but non seem to avoid creation of new view.
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = HomePage;
constructor(platform: Platform, statusBar: StatusBar) {
platform.ready().then(() => {
statusBar.styleDefault();
statusBar.backgroundColorByHexString('#1572b5');
});
}
}
Home Page
import {NavController } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, public firebaseProvider:
FirebaseProvider) {
}
//navigate to different view
navigate(){
this.navCtrl.push(AddressPage, {address:newAddress});
}
}
Address Page
import {NavController } from 'ionic-angular';
#Component({
selector: 'page-address',
templateUrl: 'address.html'
})
export class AddressPage {
constructor(public navCtrl: NavController, public firebaseProvider:
FirebaseProvider, private navParams: NavParams) {
this.addressKey = this.navParams.get('key');
}
ionViewDidEnter(){
//load some data from server
}
saveAddress(){
//save data to server
this.firebaseProvider.saveAddress(newAddress);
//move back
this.navCtrl.pop();
}
}
Firebase provider that uses AngularFireDatabase
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
#Injectable()
export class FirebaseProvider {
constructor(public afd: AngularFireDatabase) { }
saveAddress(address) {
this.afd.list('/addresses').push(address);
}
updateAddress(key,dataToUpdate){
return this.afd.list('addresses').update(key,dataToUpdate);
}
}
I have also tried this but it has the same issue.
this.firebaseProvider.saveAddress(newAddress).then(result => {
// loadingSpinner.dismiss();
this.navCtrl.pop();
});
this.firebaseProvider.updateAddress(this.addressKey, updateItems)
.then(() => {
// loadingSpinner.dismiss();
this.navCtrl.pop()
});
The HTML of save button
<button type="button" ion-button full color="primary-blue" (click)='saveAddress()'>Save</button>
Looks like unsubscribing to the subscribers fixes the issue. The HomePage view had subscribers which were not unsubscribed. I added the Observable Subscriptions into the array and unsubscribed as per code below.
ionViewWillLeave(){
this.subscriptions.forEach(item=>{
item.unsubscribe();
});
}
the push method returs a promise with the result of the action. I would change the save method like this:
saveAddress(address) {
return this.afd.list('/addresses').push(address);
}
Then in the controller I’d change it in this way:
saveAddress(){
//save data to serve
this.firebaseProvider.saveAddress(newAddress).then(result => {
//do yours validations
this.navCtrl.pop();
});
}
With thos you tide up the navigation of the page to the result of the Firebase execution. Give it a try to this approach and let me know if it didn’t work, anyway I would use oninit to load data only once as I guess you wanna do it rather than ionViewDidEnter.

firebase upload & get photo with ionic 2

I'm trying to upload an get photo in my Ionic 2 app. I succeeded to run the camera and save the photo in Firebase but not to get and display it on my app. I'm not sure i'm doing it right, the save in Firebase.
I put here my code.
add-note.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Camera } from 'ionic-native';
import {NotesData} from "../../providers/notes-data";
/*
Generated class for the AddNote page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-add-note',
templateUrl: 'add-note.html'
})
export class AddNote {
public notePicture: any;
constructor(public navCtrl: NavController,public notesData:NotesData) {}
ionViewDidLoad() {
}
addNote() {
this.notesData.addPhoto(this.notePicture);
this.navCtrl.pop();
}
takePicture(){
Camera.getPicture({
quality : 95,
destinationType : Camera.DestinationType.DATA_URL,
sourceType : Camera.PictureSourceType.CAMERA,
allowEdit : true,
encodingType: Camera.EncodingType.PNG,
targetWidth: 500,
targetHeight: 500,
saveToPhotoAlbum: true
}).then(imageData => {
this.notePicture = imageData;
}, error => {
console.log("ERROR -> " + JSON.stringify(error));
});
}
}
note-data.ts //provider for notes to upload the photo to firebase
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import firebase from 'firebase'
/*
Generated class for the NotesData provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class NotesData {
//user data
public currentUser: any;
public profilePictureRef: any;
//notedata
public notesList: any;
//firebase data
public photoRef:any;
constructor() {
this.currentUser = firebase.auth().currentUser.uid;
this.fireRef=firebase.database().ref();
this.photoRef=firebase.database().ref('users/'+this.currentUser+'/photos');
this.notesList =
}
addPhoto(notePicture:any){
this.photoRef.push({id:"data:image/jpeg;base64,"+notePicture});
}
}
my firebase structure photo
You want to use Firebase Storage and store URLs in your Firebase. You're going to cost yourself a lot of extra money and headaches by storing your image data in the realtime database.
The new SDKs have great APIs for uploading images that can be publicly accessed.
Don't save the whole url, just save short path. As you can find at my blog post about uploading, and getting data from firebase storage, it's just 2 lines of code to get actual url with permissions.
this.storageRef = firebase.storage().ref().child('images/image.png');
this.storageRef.getDownloadURL().then(url =>
console.log(url)
);
you can use angular-firebase npm package it is simple and easy to use
npm install angular-firebase
and you can simply upload the captured base 64 image
with this code
this.firebase.uploadString(encodedFile,'images/1.jpg','base64',
(v)=>{
console.log('Upload progress :'v + '% uploaded');
// event detect the data uploaded used to monitor the persentage of the download process
// this will return 'Upload progress : 24% uploaded'
// for example
}).then((url)=>{
console.log(url);
//the URL of uploaded file or image
});

force view to reload in ionic2 framework

After going through Clear History and Reload Page on Login/Logout Using Ionic Framework
I want to know same question, but for ionic2 using typescript.
On login and logout I need reload the app.ts, because there are classes that run libraries on construct.
it would be basically redirect to home and reload.
Found this answer here, (please note especially the line this.navCtrl.setRoot(this.navCtrl.getActive().component); which is by far the simplest solution that I've come across to reload present page for Ionic 2 & 3 and later versions of Angular (mine is 4), so credit due accordingly:
RELOAD CURRENT PAGE
import { Component } from '#angular/core';
import { NavController, ModalController} from 'ionic-angular';
#Component({
selector: 'page-example',
templateUrl: 'example.html'
})
export class ExamplePage {
public someVar: any;
constructor(public navCtrl: NavController, private modalCtrl: ModalController) {
}
refreshPage() {
this.navCtrl.setRoot(this.navCtrl.getActive().component);
}
}
If you want to RELOAD A DIFFERENT PAGE please use the following (note this.navCtrl.setRoot(HomePage);:
import { Component } from '#angular/core';
import { NavController, ModalController} from 'ionic-angular';
import { HomePage } from'../home/home';
#Component({
selector: 'page-example',
templateUrl: 'example.html'
})
export class ExamplePage {
public someVar: any;
constructor(public navCtrl: NavController, private modalCtrl: ModalController) {
}
directToNewPage() {
this.navCtrl.setRoot(HomePage);
}
}
Ionic 1
I haven't used Ionic 2 but currently i m using Ionic 1.2 and if they are still using ui-router than you can use reload: true in ui-sref
or you can add below code to your logout controller
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
Angular 2
Use
$window.location.reload();
or
location.reload();
You have to implement the CanReuse interface, and override the routerCanReuse to return false. Then, try calling router.renavigate().
Your component should look like this:
class MyComponent implements CanReuse {
// your code here...
routerCanReuse(next: ComponentInstruction, prev: ComponentInstruction) {
return false;
}
}
And then, when you perform login/logout, call:
// navigate to home
router.renavigate()
This is a hack, but it works.
Wrap the logic that follows your template adjustment in a setTimeout and that gives the browser a moment to do the refresh:
/* my code which adjusts the ng 2 html template in some way */
setTimeout(function() {
/* processing which follows the template change */
}, 100);
For ionic 2 it works for me when you force page reload by triggering fireWillEnter on a view controller
viewController.fireWillEnter();
Here is what worked for me to refresh only current page-
I am trying to call refreshMe function when I call onDelete from my view page,
See how my page.ts file looks-
export class MyPage {
lines of code goes here like
public arr1: any;
public arr2: any;
public constructor(private nav: NavController, navParams: NavParams) {
this.nav = nav;
this.arr1 = [];
this.arr2 = [];
// console.log("hey array");
}
onDelete() {
perform this set of tasks...
...
...
refreshMe()
}
refreshMe() {
this.nav.setRoot(MyPage);
}
}
This is just refreshing only current page.
We can also call this function from view if we need as--
<ion-col width-60 offset-30 (click)="refreshMe()">
....
....
</ion-col>
I personally use these three lines to totally refresh a component
let active = this.navCtrl.getActive(); // or getByIndex(int) if you know it
this.navCtrl.remove(active.index);
this.navCtrl.push(active.component);
You can use the ionViewWillLeave() to display your splashscreen while component is reloading and then hide it with ionViewDidEnter() once its loaded.
Hope it helps