Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you maintain the page state, so that you can provide permalinks using emberjs?

I can't to get a good idea of how you support permalinks. This is perhaps simply because emberjs doesn't support permalinks.

I'm building a UI that allows users to choose certain reports, so in ember this is easy enough you just add a route 'reports' that takes in an id so the URL looks like this:

#/reports/10/

What I need to have is some extra parameters to also be present in that URL for example start and end dates and metric types e.g.

#/reports/10/metric/impressions/start/10-08-2013/end/11-08-2013

So those parameters need to be picked up if I paste them in the browser, AND importantly when the user changes those settings e.g. via a date picker the URL should update to reflect the new parameters.

Edit:

Here is a link to a jsbin with a solution based on the answer below. http://jsbin.com/ucanam/703

like image 575
davidbuttar Avatar asked Aug 10 '13 17:08

davidbuttar


3 Answers

Just throwing my 2 cents into this topic. Please note that i am using this approach in production and it works fine. Actually there are 2 parts to this question.

1. How can i have multiple dynamic segments?

One approach is described by Mike Grasotti using nested resources. This approach works but i think this approach is a little bit cumbersome in this case.

Why do i think it is cumbersome?

Routes are a means to separate concerns in Ember. In this case i do not see separate concerns. It looks to me like you are trying to mirror the state of a form in your URL. I think it should be one route that is responsible for the concern "state of the form". Therefore i recommend to have a look at the following post, in which i describe how to implement multiple dynamic parameters per Route: Is resource nesting the only way to enable multiple dynamic segments?

2. How is it possible to trigger the serialize hook to update the URL, when you have changed just one parameter in your form?

The problem is that the serialize hook is only triggered, when the Route gets entered with a new model. I guess you have some logic in place, that deals with the event of changing the parameters start or end. I suppose that you do not re enter the Route in this case. So how do you trigger the serialize hook in this case again to update the URL? I am handling a event like this in my router and there i am using the following code:

var currentRouteName = this.controllerFor("application").get("currentPath");//the ApplicationController stores the name of the current Route
var url = App.Router.router.generate(currentRouteName);
App.Router.router.updateURL(url);

PS: You can have a look at my production app here. This app shows the best movies in cinemas in Germany. Even if you do not know german, you can click on one of the controls in the top area and see the URL getting updated. I guess this is pretty much the same you want?

like image 106
mavilein Avatar answered Nov 18 '22 15:11

mavilein


I have wondered how to do this as well. The data has to go in the URI since we want to share links, but you don't want to confuse the application location with the application state.

The hash: #/reports/10 would be the minimal information required to tell the application where to go. All the other data which is independent of location should probably go in the search portion of the URI. I would suggest something like this:

#/reports?metrics=impressions&start=10-08-2013&end=11-08-2013

In theory you could parse the query string when you enter a route and then update your model accordingly. From my understanding the route's model() function is called when navigating to a route by changing the URL directly or clicking a link so that would be the place.

Unfortunately, in practice this didn't work as I expected. I'm not sure if it's just JSBin, but there is some weird behavior where the link with the extra application data doesn't actually navigate which is the whole point for a permalink. Notice that if you follow the directions in the JSBin the start and end dates are taken from the url instead of the default values. This concept could be extended to send extra requests for different model data using findQuery etc so almost any thing is possible.

http://jsbin.com/abadet/7

Anyways, it might give you some ideas.

like image 1
Matt Mazzola Avatar answered Nov 18 '22 15:11

Matt Mazzola


There are a couple of ways to get this done in ember. If you need a lot of flexibility for misc parameters that might be passed to a report, check out ember-query which adds query-string support to ember applications.

Another option is to use nested resources. So for example:

App = Ember.Application.create({});

App.Router.map(function() {
  this.resource('report', {path: '/reports/:report'}, function() {
    this.resource('metric', {path: '/:metric'}, function() {
      this.resource('start', {path: '/:start'}, function() {
        this.route('end', {path: '/:end'});
      });
    });

  });
});

App.StartEndRoute = Ember.Route.extend({
  model: function(params, transition){
    return transition.params
  }
});

<script type="text/x-handlebars" data-template-name="start/end">
<pre>
Report ID: {{report}}
metric: {{metric}}
start: {{start}}
end: {{end}}
{{log this}}
</pre>
</script>

See this jsbin for working example

like image 1
Mike Grassotti Avatar answered Nov 18 '22 17:11

Mike Grassotti