How to pass parameters between different routes (in Ember 2.x)?

First of all, I’ve asked the question at the SO at Sep 2. It didn’t get enough attention.

While going from one route to another, I want to pass some data (especcially arrays). How is it possible?

I’ve found some solutions with drawbacks:

  • by using query-params: need to serialize, deserialize. Seems not suitable for different-sized arrays.

  • by using a service to store data: it is not only available to routes, but available to whole app. It can be modified unintentially. Also it will not have a garbage remove mechanism. It stores the values from routes that was displayed far before.

  • by using transition object as promise: It modifies the returning hash of model hook. Involves in someone else’s business.

  • by using transition object’s data attribute: It fits well. The only problem we found is: it is not working on page refreshs. (Of course page refresh means to reload the whole SPA. But it is totally acceptable from the users’ perspective. Also using services may cause this problem.)

So, what is the suitable approach to passing parameters between different routes?

Hi,

Try to store value in a mixin. And, Use that mixin.

It will help you.

Thanks

How? Isn’t it have the same drawbacks same with storing values in services?

I believe service is all you need. If you need to invalidate some resources you should do it manually.

Could you provide some more context please? Do you need to share data between nested routes? Do you need to share the same resource by id? How does your router.js look like?

1 Like

So, service drawbacks are:

  • Unintential modification of data of other routes.
  • Garbage collection is needed. ==> as you suggested, I think manually removing is acceptable.
  • At page refreshs, it doesn’t work.

To provide some more context:

  • The routes are not used as nested.
  • Need to pass a big json or ember object between routes
  • router does only have model ids or query parameters.

You can pass query params directly from your {{link-to}}

http://emberjs.com/api/classes/Ember.Templates.helpers.html#method_query-params

1 Like

It was one of the options, I’ve mentioned at the question:

by using query-params: need to serialize, deserialize. Seems not suitable for different-sized arrays.

After all, I found that query-params is well suitable. But, I need to override serializeQueryParam and deserializeQueryParam hooks to send complex objects.

No matter in arrays, if I define them as the following in my route:

  queryParams: {
    arr:{
      type:'array'
    }
  },

As a workaround, I can send all complex objects in an array as following:

this.transitionTo('my-route', {queryParams:{[myComplexObject]});

Or I can override serializeQueryParam and deserializeQueryParam hooks. See my question about overriding them.

1 Like

Further more about query-params: It has a feature “stickyness”. But actually it is not a feature, but a bug!

According to the guide:

If you wish to reset a query param, you have two options:

  1. explicitly pass in the default value for that query param into link-to or transitionTo.
  2. use the Route.resetController hook to set query param values back to their defaults before exiting the route or changing the route’s model.

According to option 1: If you want add some queryParams to one of your route, you need to change all your current code that navigates to that route to reset your new query parameters. If you don’t do that, your route will open with your last query-params!

According to option 2: Actually, option 2 is not working in case of the current route is not changing. For example: You have a menu that is rendered by application.hbs and if user selects to go to the X route while at X route (with some query params), resetController hook will not work. And current query params are still be displayed. I saw some addons relying on this hook. But they cannot solve the problem of staying on the same route.

Anyway, if ones wrote an addon that tries to eliminate one of behaviours of the framework, isn’t it an indicator of that behaviour should be closed with a config parameter?

EDIT: Third option is to override one of the private methods of Router: see working in twiddle. Method is: _hydrateUnsuppliedQueryParams

Assuming you have a products page where you can see 10 different products and you want to open multiple tabs together(new route). What method do you think fits in this use case? I need to keep the selected product data so a page refresh wouldn’t lose it. Would query-params be the right choice?

Yes, I think that sounds like a good place to user a query param.

I know this sounds kind of messy, but why not just add the complex Object/Array that you need in the next route directly into the new route’s model hash? Assuming of course your new route is returning an RSVP.hash from its model (easy refactor if it isn’t):

// the route.js you're leaving
...
actions: {
  someActionThatTransitionsToNewRoute(complexObject) {
    this.transitionTo('some.new.route')
      .then((newRoute) => {
        newRoute.set('controller.model.complexObjectFromPreviousRoute', complexObject);
      });

    return true;
  }
}
...

It’s not a beautiful solution; but it is something you’re free to do during transitions. This will not work if the transition is opened in a new tab and it won’t do anything for page refreshes. I hope that’s obvious.

This is very convenient in passing complex information from route to route; usually improving your end-user’s experience.

Route intercourse isn’t pretty but it’s a means to an end :wink: