IONIC-V3 : Wait page to pop before continue executing code - ionic-framework

I’m iterating over a JSON that contains some rules to build my page. The loop is something like this:
flux.forEach(element => {
this.navCtrl.push(element.pageName);
});
My issue here is that I need to wait for this page to execute its action before call the next, this loop makes a stack. How can I make sort of a promise to wait the page to execute its duty before continue the loop?
Thank you all!

To solve promises in sequence, you can use reduce() as explained here.
element.reduce((promise,item) => {
return promise.then(() => {
return new Promise((resolve, reject)=> {
this.navCtrl.push(element.pageName);
resolve();
})
})
},Promise.resolve())

Related

How to execute function after stream is closed in Dart/Flutter?

So basically I am using the flutter_uploader package to upload files to a server and I'd like to execute a function after the upload is complete:
final StreamSubscription<UploadTaskProgress> subscription = _uploader.progress.listen(
(e) {
print(e.progress);
},
onError: (ex, stacktrace) {
throw Exception("Something went wrong updating the file...");
},
onDone: () {
myFunction(); // won't run
},
cancelOnError: true,
);
The problem is the onDone function doesn't execute thus meaning myFunction never executes. I've done some digging and I found that onDone gets called when we close the stream but there is no such method on the subscription variable. I have not used streams much and therefore am pretty bad with them.
My question is, how can I run myFunction? once the stream is complete? I thought that onDone would get called when such is the case but I guess not.
Thank you!
I didn't used that package before but I was reading a litle bit about the package and I think you can execute your funciton inside the main block, the other ones are to handle internal processes like stopping a background job or some other external stuff like notify the error to some error monitoring tool, this is what I propose to you:
final StreamSubscription<UploadTaskProgress> subscription =
_uploader.progress.listen(
(e) {
if (e.status is UploadTaskStatus._internal(3)) {
myFunction()
}
print(e.progress);
},
onError: (ex, stacktrace) {
throw Exception("Something went wrong updating the file...");
},
cancelOnError: true,
);
Just to be clear I'm not sure of the specific implementation, is just and idea I get from the docs, seems like the event also contains an status property which has a constant for when the event is completed
https://pub.dev/documentation/flutter_uploader/latest/flutter_uploader/UploadTaskProgress/UploadTaskProgress.html
https://pub.dev/documentation/flutter_uploader/latest/flutter_uploader/UploadTaskStatus-class.html
Hope this helps you :D

await doesnt work with stream for me in flutter

I have a problem where i want to read some data from database and i want my function to wait for the data before proceeding executing the rest of my code. i am using stream with await and async but doesnt look like it is working for me.
here is my code
void updateIncome() async {
Stream<List<IncomeData>> _currentEntries;
_currentEntries = database.watchIncomeForUpdate(this.income);
await _currentEntries.forEach((List<IncomeData> x) {
x.forEach((element) {
print('AWAIT');
}
);
});
print('FINISH');
}
here is the procedure that call my database and get data
Stream<List<IncomeData>> watchIncomeForUpdate(IncomeData entry) {
return (select(income)..where((t) =>t.id.isBiggerOrEqualValue(entry.id) & t.groupId.equals(entry.groupId))
..orderBy([(t) => OrderingTerm(expression: t.dateReceived)])).watch();
}
when i run the function updateIncome(), it prints FINISH first which make me believe that the await/async is not working by waiting for the foreach to loop through all elements in the list.
i tried to move the await keyword in the function call
_currentEntries = await database.watchIncomeForUpdate(this.income);
i get a warning message: await applied to Stream<List> which i not a Future
can someone help me? what i am doing wrong?
i want to wait for database to get the data, loop and print AWAIT then when finish, it should proceed with rest of code and print FINISH. the function that call the database return 8 rows. so when i loop using foreach, it should print AWAIT 8 times follow by FINISH.
how can i fix my code so that the function calls the database ,loop through the elements and wait until the loop finish before proceeding with the rest of the code outside of the loop?
Since watchIncomeForUpdate is not a Future function, you can't wait for a non-future function.
void updateIncome() async {
await for(var x in database.watchIncomeForUpdate(this.income)){
x.forEach((element) {
print('AWAIT');
}
);
});
print('FINISH');
}
Ref: https://dart.dev/tutorials/language/streams
Thanks for all replies. i figured it out.
i changed function from this
Stream<List<IncomeData>> watchIncomeForUpdate(IncomeData entry) {
return (select(income)..where((t) =>t.id.isBiggerOrEqualValue(entry.id) & t.groupId.equals(entry.groupId))
..orderBy([(t) => OrderingTerm(expression: t.dateReceived)])).watch();
}
to this
Future<List<IncomeData>> watchIncomeForUpdate(IncomeData entry) async {
return (select(income)..where((t) =>t.id.isBiggerOrEqualValue(entry.id) & t.groupId.equals(entry.groupId))
..orderBy([(t) => OrderingTerm(expression: t.dateReceived)])).get();
}
then call the procedure as
data = await database.watchIncomeForUpdate(this.income);

Vertx CompositeFuture

I am working on a solution where I am using vertx 3.8.4 and vertx-mysql-client 3.9.0 for asynchronous database calls.
Here is the scenario that I have been trying to resolve, in a proper reactive manner.
I have some mastertable records which are in inactive state.
I run a query and get the list of records from the database.
This I did like this :
Future<List<Master>> locationMasters = getInactiveMasterTableRecords ();
locationMasters.onSuccess (locationMasterList -> {
if (locationMasterList.size () > 0) {
uploadTargetingDataForAllInactiveLocations(vertx, amazonS3Utility,
locationMasterList);
}
});
Now in uploadTargetingDataForAllInactiveLocations method, i have a list of items.
What I have to do is, I need to iterate over this list, for each item, I need to download a file from aws, parse the file and insert those data to db.
I understand the way to do it using CompositeFuture.
Can someone from vertx dev community help me with this or with some documentation available ?
I did not find good contents on this by googling.
I'm answering this as I was searching for something similar and I ended up spending some time before finding an answer and hopefully this might be useful to someone else in future.
I believe you want to use CompositeFuture in vertx only if you want to synchronize multiple actions. That means that you either want an action to execute in the case that either all your other actions on which your composite future is built upon succeed or at least one of the action on which your composite future is built upon succeed.
In the first case I would use CompositeFuture.all(List<Future> futures) and in the second case I would use CompositeFuture.any(List<Future> futures).
As per your question, below is a sample code where a list of item, for each item we run an asynchronous operation (namely downloadAnProcessFile()) which returns a Future and we want to execute an action doAction() in the case that all the async actions succeeded:
List<Future> futures = new ArrayList<>();
locationMasterList.forEach(elem -> {
Promise<Void> promise = Promise.promise();
futures.add(promise.future());
Future<Boolean> processStatus = downloadAndProcessFile(); // doesn't need to be boolean
processStatus.onComplete(asyncProcessStatus -> {
if (asyncProcessStatus.succeeded()){
// eventually do stuff with the result
promise.complete();
} else {
promise.fail("Error while processing file whatever");
}
});
});
CompositeFuture.all(futures).onComplete(compositeAsync -> {
if (compositeAsync.succeeded()){
doAction(); // <-- here do what you want to do when all future complete
} else {
// at least 1 future failed
}
});
This solution is probably not perfect and I suppose can be improved but this is what I found works for me. Hopefully will work for someone else.

#ngrx Effect does not run the second time

I've just started learning about #ngrx/store and #ngrx.effects and have created my first effect in my Angular/Ionic app. It runs ok the first time but if I dispatch the event to the store again (i.e when clicking the button again), nothing happens (no network call is made, nothing in console logs). Is there something obvious I'm doing wrong? Here's the effect:
#Effect() event_response$ = this.action$
.ofType(SEND_EVENT_RESPONSE_ACTION)
.map(toPayload)
.switchMap((payload) => this.myService.eventResponse(payload.eventId,payload.response))
.map(data => new SentEventResponseAction(data))
.catch((error) => Observable.of(new ErrorOccurredAction(error)));
Thanks
It sounds like an error is occurring. In that situation, the action in the observable returned by catch will be emitted into the effect's stream and the effect will then complete - which will prevent the effect from running after the error action is emitted.
Move the map and the catch into the switchMap:
#Effect() event_response$ = this.action$
.ofType(SEND_EVENT_RESPONSE_ACTION)
.map(toPayload)
.switchMap((payload) => this.myService
.eventResponse(payload.eventId, payload.response)
.map(data => new SentEventResponseAction(data))
.catch((error) => Observable.of(new ErrorOccurredAction(error)))
);
Composing the catch within the switchMap will prevent the effect from completing if an error occurs.
You must move map() and catchError() into swithchMap() as following
#Effect()
public event_response$ = this.action$.pipe(
ofType(SEND_EVENT_RESPONSE_ACTION),
switchMap((payload) => {
return this.myService.eventResponse(payload.eventId,payload.response).pipe(
map((data: DataType) => new SentEventResponseAction(data)),
catchError((error) => Observable.of(new ErrorOccurredAction(error)))
})
);
);
Please note that, evetResponse() method inside myService should return an observable in order to use pipe afterward.
In case your method inside service returns Promise, you can convert it into an observable by the use of from in the rxjs package as below:
import { from } from 'rxjs';
...
const promise = this.myService.eventResponse(payload.eventId,payload.response);
const observable = from(promise);
return observable.pipe(...
For more and detail description take a look at this link

Confused about side effects / ContinueAfter

I have a scenario in which I download parent entities from an api and save them to a database. I then want, once all of the parents have been saved, to download and save their children.
I've seen (or misunderstood) some comments about how this is a side-effect as I will not be passing the result of the parent save operation to the save children operation. I simply want to begin it when the parents are saved.
Could someone explain to me the best way of doing this?
Perhaps try something like this:
Observable
.Create<int>(o =>
{
var parentIds = new int?[] { null };
return
Observable
.While(
() => parentIds.Any(),
parentIds
.ToObservable()
.Select(parentId => Save(parentId)))
.Finally(() => { /* update `parentIds` here with next level */ })
.Subscribe(o);
})
.Subscribe(x => { });
This is effectively doing a breadth-first traversal of all of the entities, saving them as it goes, but outputting a single observable that you can subscribe to.