olivernn / davis.js

RESTful degradable JavaScript routing using pushState
http://davisjs.com
532 stars 58 forks source link

Discover routing when page rendered. #35

Closed mohamedmansour closed 12 years ago

mohamedmansour commented 12 years ago

I was checking out Davis, and it looks like a really neat API. Thanks!

One thing I liked about Backbone Routing is that when a user visits http://localhost/foo/bar (or http://localhost/#/foo/bar) it will automatically discover which route it belongs to. Server side, we just render that page to the (index /) and then the JavaScript routes would call the correct listener.

Is Davis going to do something like that in the near future? The reason why I am asking, I am only using server side for RESTful / or WebSocket API, all the App runs client side, the server just spits out just the HTML5 and serves the basic JavaScript entry file. When a user visits a certain page directly, I just populate the models from the server into a JSON in the template so the models in client side will pick it up dynamically from page load.

Thanks!

mohamedmansour commented 12 years ago

Looking at the source more, while debugging it turned out to be how you handled the popped variable. It was working fine in your Notepad app which uses 0.7.0. In ToT version 0.8.1 it doesn't work since around three months ago you added the following cl 79ab45c5ce02757bed2c88dd5661ba1bcdf618a9, you explicitly want to prevent against the webkit initial page load pop. Are you planning to support this in the future, to allow us to pop at initial page load so that the routers will run?

olivernn commented 12 years ago

If I understand correct you are expecting a davis route to be triggered on the initial page load?

This used to be default behaviour before version 0.7 however I changed the defaults so that the initial page load does not trigger your route. The reason for this is that I think the ideal approach is have your server be able to respond to, and render your content, for all the routes you are defining in your client side davis app. If this is the case then running the same request on the client is a duplication of effort.

However I am aware that this doesn't work for all apps and therefore you can make davis run routes on the initial page load. There is a setting which you can change called generateRequestOnPageLoad see here.

So in your app you could do something like this:

var app = Davis(function () {
  this.config(function () {
    this.generateRequestOnPageLoad = true
  })

  this.get('/foo', function (req) {
    // your logic here
  })
})

With this app if the initial page request is for /foo then your server will render whatever, and then your davis app will trigger your /foo route.

Hope this makes sense and solves your problem.

tomwhatmore commented 12 years ago

Thanks for clarify this, but I think you mean this.configure() in the example you posted. this.config() throws an error.

olivernn commented 12 years ago

Ah yes you're right, I don't even know my own API!

Valloric commented 12 years ago

Just FYI: this should be very prominent in the docs. I just spent far too much time trying to figure out what was I doing wrong, and it turns out I'm missing this magic configuration switch.

olivernn commented 12 years ago

Yes point taken, it's a little hard currently to get this information, thanks.

evadnoob commented 11 years ago

I'm in the process of trying to get Davis to work, replacing Backbone.Router with Davis. I too, use the feature of Backbone that tells Backbone.Router "all requests go to '/'". This allows for one server side route, and an arbitrary number of client side(javascript) routes. With Davis it appears that I must have a matching route on the server, I prefer the Backbone.Router behavior....Would like it if Davis could behave this way as well.

Thanks

olivernn commented 11 years ago

Are you using hash based routing with the backbone router? It is possible to use the same kind of routing with Davis, using the Davis.hashRouting extension.

Davis.extend(Davis.hashRouting({
    forceHashRouting: true
}))

This will force Davis to use hash based routing, meaning that all routes will just be part of the hash, e.g. /#/foo. When reloading a page the hash is not sent to the server and therefore you only need to be able to respond too the route path.

If you want to use pushState routing then it is still possible to have only one 'route' visible to the server. Davis has a kind of route called state routes:

var app = Davis(function () {
    this.state('foo', function (req) {
        // route logic
    })

    this.state('bar', function (req) {
        // route logic
    })
})

This adds two routes, foo and bar, you can transistion to these routes using the method trans

app.trans('foo', {
    'params': 'here'
})

This will transition to the 'foo' state, and the second argument is used as the req.params in the route handler. The url will not change, meaning a reload of the page will cause a request to the server for /. The back and forward buttons on the browser will still work though, moving between states.

If at all possible I would try and make it so that your server can respond to each of the routes that you define client side, obviously this doesn't make sense for all apps though. In which case using the hash based routing makes sense, since you still have a url that can be passed around and shared between users.

Hope this makes sense, I'm happy to explain further if required.

evadnoob commented 11 years ago

This helped, thanks. I had seen the hashRouting plugin and thought that it would be the solution, but I had some trouble getting it to work, only because of the way our code was using the previous backbone router. I now have routes setup like this.get("#foo/bar", function(req) {})

So, instead of 'discovering routes' we just rely on hashRouting, here's the snippet that sets up our routes(this is in the constructor function of Davis():

          self.configure(function () {
            self.settings.throwErrors = true;
            self.settings.linkSelector = 'a:not(.dropdown-toggle)';
          });

          _.each(that.options.routings, function(r) {
            self.get(r.fragment, function(req) {
              application.req = req;
              if (req.options !== undefined && req.options.trigger !== undefined) {
                if (req.options.trigger) {
                  that.switchToView(r, req);
                }
              }
              else {
                //the default action if calling
                //application.navigate('#/some url') without any extra
                //options is to trigger a switch to view
                that.switchToView(r, req);
              }
            });
cnizzardini commented 11 years ago
            var app = Davis(function () {
                this.configure(function(){
                    this.generateRequestOnPageLoad = true;
                });
            }