I am trying to add a LoadingController to my Ionic 5 app.
With the below code, the loading spinner is appearing:
async presentLoading() {
const loading = await this.loadingCtrl.create({
message: 'Please wait...',
});
await loading.present();
}
getPosts() {
this.posts = [];
this.presentLoading();
query.get()
.then((docs) => {
docs.forEach((doc) => {
this.posts.push(doc);
})
}).catch((err) => {
console.log(err)
})
}
But I don't know how to dismiss the LoadingController once the posts array has been populated.
Can someone please show me how this is done?
You have to dismiss the controller. For that you will have to keep a reference to it, something like this,
async presentLoading() {
this.loading = await this.loadingCtrl.create({
message: 'Please wait...',
});
await this.loading.present();
}
getPosts() {
this.posts = [];
this.presentLoading();
query.get()
.then((docs) => {
docs.forEach((doc) => {
this.posts.push(doc);
this.loading.dismiss();
})
}).catch((err) => {
console.log(err)
})
}
If you need to get notice when the dismiss occurs, you can listen to onDidDismiss event.
Links:
Ionic Docs - LoadingController
Related
This is my onSavedChange func for user Information updating. also where do i need to add toast/snackbar, i cannot figure it out please help.
void onSavedChange() async {
if (!_formKey.currentState!.validate()) {
return;
} else {
try {
loadingController.add(true);
final response = await userApi.changeUserInformation(
newEmail: textEditingControllerEmail.text.trim(),
newFirstName: textEditingControllerFirstName.text.trim(),
newLastName: textEditingControllerLastName.text.trim(),
);
printMe("response:$response");
await LocalStorage.saveUserData(firstName: response.firstName, lastName: response.lastName, email: response.email );
AppConstant.FIRST_NAME = await LocalStorage.read(key: LocalStorage.FIRSTNAME);
AppConstant.LAST_NAME = await LocalStorage.read(key: LocalStorage.LAST_NAME);
AppConstant.USER_EMAIL = await LocalStorage.read(key: LocalStorage.UER_EMAIL_KEY);
// printMe("data1 is ${AppConstant.FIRST_NAME}");
// printMe("data2 is ${AppConstant.LAST_NAME}");
// printMe("data3 is ${ AppConstant.USER_EMAIL}");
bool? isLoading = await Navigator.push(context, MaterialPageRoute(builder: (context) => const HomePage(startPageIndex: 4, )));
if (isLoading != null) {
loadingController.add(isLoading);
}
}
catch (error) {
isLoading.add(false);
UIHelper.showErrorMessageDialog(error, context);
}
}
}
app.get('/prenotazione', async (req, res) => {
await dbo.collection("Noleggi").find({}).toArray().then((nol) => {
await dbo.collection("Ogetti").findOne({ _id : nol.id_oggetto}).toArray().then((nol) => {
console.log(nol);
res.render('prenotazione', { ciao : nol});
}).catch((error) => {
res.status(500).write(error);
});
}).catch((error) => {
res.status(500).write(error);
});
});
With one request the function work, but with the second request nested it doesn't,'t work and print me "Await in only valid in async function"
It`s not necessary in the second await. But if u want it, u can add async:
await dbo.collection("Noleggi").find({}).toArray().then(async (nol) => {
await dbo.collection("Ogetti").findOne({ _id : nol.id_oggetto}).toArray().then((nol) => {
console.log(nol);
res.render('prenotazione', { ciao : nol});
}).catch((error) => {
res.status(500).write(error);
});
})
Been trying to copy subcollections of a collection into another collection. The code below is aimed at that, but jumps from the first then and logs out "Done" without logging out anything before.
So the question is what is not correct here?
exports = module.exports = functions.https.onRequest(async (req, res) => {
let db = admin.firestore();
try {
await db.collection("users").get().then((query) => {
return query.forEach(async (doc) => {
console.log("Here"); //This doesn't print
const polCollection = await db.collection("users").doc(doc.id).collection("xyz").get();
if (polCollection.docs.length > 0) { //This checks if any subcollections
for (const x of polCollection.docs) { //This copies them into a doc in the copy collection
db.collection("CopyUsers")
.doc(doc.id)
.set({ x : x.data() }, { merge: true });
}
}
});
})
.then(() => {
console.log("Done"); //This is the only thing that prints in the console
res.end();
})
.catch((e) => {
console.log("e", e);
res.end();
});
} catch (error) {
console.log("error", error);
res.end();
}
});
After the suggestion below, it now looks as follows:
exports = module.exports = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
const promises = [];
let count = 0;
let size = 0;
return await admin
.firestore()
.collection("testUsers")
.get()
.then((query) => {
console.log("query length:", query.size); //prints x of users
size = query.size;
query.forEach(async (doc) => {
const promise = async () => {
console.log("Here", doc.id); //This doesn't print
await admin
.firestore()
.collection("testUsers")
.doc(doc.id)
.collection("xyz")
.get()
.then(async (polCollection) => {
if (polCollection.docs.length > 0) {
for (const x of polCollection.docs) {
return await admin
.firestore()
.collection("testBackUpUsers")
.doc(doc.id)
.set(
{ xyz: x.data() },
{ merge: true }
);
}
} else {
return;
}
})
.catch((e) => console.log("error from then after get xyz", e));
};
count++;
return promises.push(promise);
});
return promises;
})
.then(async (promises) => {
if (size <= count) {
console.log("running return Promise.all(promises)", promises.length); //prints number of promises = users
return Promise.all(promises);
}
})
.catch((e) => console.log("err from the last catch", e));
});
Any thoughts?
Unfortunately the forEach iterator does not support async/await. Even if you write an await inside it will just go trough it without waiting on the execution.
I would recommend to use Promise.all. That would also execute the code in parallel and would finish faster.
If you would only change data you could also use a batch change but in your example you first get the data and then change it.
Here is an example how you could write your code:
exports = module.exports = functions.https.onRequest(async (req, res) => {
let db = admin.firestore();
const promises = [];
try {
const query = await db.collection("users").get();
query.forEach((doc) => {
console.log("doc", doc);
const promise = async () => {
console.log("Here", doc.id); //This doesn't print
const polCollection = await db
.collection("users")
.doc(doc.id)
.collection("xyz")
.get();
if (polCollection.docs.length > 0) {
//This checks if any subcollections
for (const x of polCollection.docs) {
//This copies them into a doc in the copy collection
await db
.collection("CopyUsers")
.doc(doc.id)
.set({ x: x.data() }, { merge: true });
}
}
};
promises.push(promise);
});
console.log("promises", promises);
await Promise.all(promises);
console.log("Done");
res.end();
} catch (error) {
console.log("error", error);
res.end();
}
});
I created a simple function of creating a loading like this
async presentLoading() {
const loading = await this.loadingController.create({
message: 'Please Wait...',
});
await loading.present();
}
And i am closing the loader when the data is fetch like this
getUserData(){
console.log(this.userID);
this.api.getCompanyEmploye(this.userID).subscribe(res => {
this.loadingController.dismiss(); //closing here
console.log(res);
this.user = res.records[0];
this.familyMembers = res.records[0].family_members;
});
}
I am calling both function in constructor
constructor(public loadingController: LoadingController){
this.presentLoading();
this.getUserData();
}
Its showing error of ERROR Error: Uncaught (in promise): overlay does not exist
The issue is that your API call responds sooner than the loading controller gets instantiated. Instead of parallel calls, you should try to serialize those this way:
Make your presentLoading method to return Promise:
async presentLoading() {
const loading = await this.loadingController.create({
message: 'Please Wait...',
});
return loading.present();
}
Now you can call it this way:
getUserData(){
this.presentLoading().then(()=>{
this.api.getCompanyEmploye(this.userID).subscribe(res => {
this.loadingController.dismiss(); //closing here
console.log(res);
this.user = res.records[0];
this.familyMembers = res.records[0].family_members;
});
})
}
And in your constructor you need only to call for the API
for me, the issue is simply because I don't have .catch() for the promise. As#Sergey suggested, this is because the loader is not ready when you calling the ionic loader
this.loadingController.dismiss()
.then(async () => {
await this.setStorageForLocalData(data);
})
.catch(console.error);
where .catch() will dismiss the error
I am using Ionic 2 HTTP native plugin and running http.post from a provider. The data is received from the API in the provider but does not seem to be being sent back to the page component. I get error:
TypeError: undefined is not an object (evaluating
'this.authProvider.login(formData).then')
PAGE: login.ts
doLogin() {
this.spinner = 'true';
this.authProvider.login(formData).then((result:any) => {
if(result.status == 'isTrue') {
this.storage.set('userId', result.userId);
this.storage.set('userToken', result.token);
this.storage.set('profilePic', result.profilepic);
this.storage.set('userUsername', result.username);
this.navCtrl.setRoot(TabsPage);
}
else {
this.presentToast('Incorrect email or password, try again');
console.log('not a user');
}
this.spinner = 'false';
}, (err) => {
});
}
PROVIDER: authProvider
login(data) {
if (this.platform.is('ios'))
{
this.http2.post(this.apiUrl+'/api/login', data, {})
.then((dataresult) => {
return dataresult; // this outputs ok in console.log, but doesnt
return back to page
//console.log(dataresult);
})
.catch(error => {
});
}
}
You should have to return promise from authProvider,
return new Promise(resolve => {
this.http2.post(this.apiUrl+'/api/login', data, {})
.subscribe(dataresult => {
resolve(dataresult);
});
});