How to Pass Data with Angular Router in Ionic [v4]

ionic-4-pass-data-router

When you are migrating your Ionic 3 app to Ionic 4 one of the biggest problems you will face is converting your logic to the new routing. Especially passing objects to new routes becomes problematic as you should rely on only using IDs inside the path.

In this Quick Win we will look at 3 different solutions to pass data with Angular Router to your Ionic pages. Not all of them are recommended, but all of them would work and can make your life a lot easier when migrating your app to Ionic 4.

pass-data-ionic-4

Setting up the App

Before we get into the details we need a testing app. Therefore, start a blank new app and add one details page that we can navigate to:

Now we need some buttons to trigger our actions so simply add a few to our app/home/home.page.html:

Also, the details page will always have the same markup which just displays a few values that we (hopefully) pass to the page. Go ahead and change the app/details/details.page.html to:

Now we can get into the three different solutions we got for our problem.

1. Using Query Params (bad)

The first option is more like an ugly hackish thing and not recommended. Still, I wanted to include this way as well so you know about it.

The trick here is to use Query params which are normally in your URL like ionic.com?user=simon&skill=ionic.

We can create these parameters with the Angular router as well, and we are normally limited to strings – but we can of course stringify every object as well, right?

Therefore, you can change the code inside your app/home/home.page.ts to:

Now we create additional information that we pass to the routing and we include our user object in the query params as a string.

When you do this, the page you navigate to receives the value but of course only as a string so you need to convert it back then.

But this can be done pretty easily, we just have to subscribe to the changes of the query params of the navigation and then we are able to use the result like this inside the app/details/details.page.ts:

Again, this is a pretty dirty solution. If you only pass small chunks of information inside of the query params that’s fine, but look how the URL would look like in our case:

You don’t really want to have that, so let’s explore a more recommended way.

2. Service and Resolve Function (legit)

A better way (besides using only an ID and then making another call from the details page) is to use a service in the middle to keep track of your data.

Therefore, generate a service and another service that we will use as a resolver (not 100% needed but recommended):

The service has very limited functionality in our example as it’s just to showcase the way of doing things so change the services/data.service.ts to:

This service can be used from everywhere inside our app and will exist as one instance only – so we can use it perfectly to hold some data for us.

We could also use this service directly now by setting the value before navigating and then getting the data again on the next page but we’ll also use a resolver. We’ve also talked about this when using route guards and resolver.

By using a resolver you can make sure the data is already available in your page once you arrive there. That means, you don’t have to use the safe navigation operator inside the view or wrap everything inside an *ngIf.

The resolver could be implemented simply like this inside the app/resolver/data-resolver.service.ts:

Now we also need to change the routing a bit so it includes both an ID that we can pass to the page (like you have seen in many tutorials) but additionally also the resolve function we just created, so change the app/app-routing.module.ts to:

Now whenever we navigate to that route, the resolver will strike and try to get the ID from the route, look up the data from our service and return it.

That means the mechanism is in place and we just have to call it accordingly, so add a new function openDetailsWithService that both stores the local data to our service and then makes the navigation call inside the app/home/home.page.ts:

As said, the resolver will now resolve all information for us upfront so inside the app/details/details.page.ts we got immeditaley access to the resolved information that we have named special inside the routing setup before:

This way includes a lot more steps then with the first solution, however it’s one of the best ways to pass data around. You could even add storage to the service to persist the information so you could load it if you only refresh the page!

3. Using Extras State (new since Angular 7.2)

Finally, a solution I only discovered when writing this Quick Win that was added since Angular 7.2 (which your Ionic 4 app should have).

This is almost like you wish it to be, simple and clean, just attaching whatever information to the additional routing extras and then unwrapping them in your page.

You can add whatever object you want to the state like this inside your app/home/home.page.ts:

In the app/details/details.page.ts this information can now easily be accesed by using the Router directly and getting access to the extras:

If you are converting your Ionic 3 application to Ionic 4, most likely this is the easiest solution for your problem.

However, be aware that your passed data will be added to the history of the location so your app might end up holding onto a lot of data!
You can find the Github issue and further comments on this topic here.

Conclusion

Another solution would be to save data to the storage, navigate and then load the data again but it involves dealing with async code and would make the process even slower.

Therefore, the last proposed solution might be your best bet. However, keeping data inside the service instead of attaching it to the Router is also an equally good solution but it’s a bit more complex yet will work great if setup correctly once!

You can also find a video version of this Quick Win below.