Routing

edited March 2012 in Enyo 2
I'm building web application with Enyo and I'm wondering if anybody did routing already? I can bolt it on myself, of course, but I'm interested in seeing what others are doing in this direction.

Comments

  • It's not in our immediate roadmap for the framework.
  • Ok, sure. I was just thinking if anybody already had done some steps in this direction himself.
  • You should look into the enyo.Signals kind and the mechanisms for application-level custom events if you hook up something.
  • So is there any particular reason that waterfallDown on an UiComponent only sends message to this.children (i.e. UiComponents) instead of distributing across this.$ (as normal Component does)? I'm not sure if this is a feature or a bug.

    I thought about implementing routing as a component of a kind, where you define what you can consume here, it fires your handlers for matches and then waterfalls the rest of a path to components of an owner so that routers on level lower will be able to consume more of an url.

    But the thing is that my Router is a Component kind, so it doesn't get any events waterfalled from it's owner... which is a shame. Maybe it should just put handler on an owner at time of creation (so that it will also be able to stop waterfalling event about changed path until it consumes necessary data)? This seems viable - I just need to cover existing event handler (that's the only thing I dislike in current event system - you can't have multiple handlers for single event).
  • Ah, forgot last bit: and it seems I can't put my own handler on this.owner since component.handlers mapping contains names and can't contain actual function.

    So I'm a bit stuck here, unsure what to do. :\
  • A workaround might be to make your Router kind subclass NoDom rather than Component. I agree that Component makes more sense (it's not a UI Component, after all) but NoDom at least puts you in the UI branch under component but doesn't actually render anything (hence, the name).
  • Hm, sure, not exactly as pure, but it will work.

    But now as I'm thinking about it I would prefer to put handler on Router's owner, so I will be able to stop waterfalling of 'path changed' event on subelements. I can do that by generating unique name and placing a callback directly on my owner, of course. But that doesn't sound that good to me. I was thinking if handlers should be 'name to name' mapping or maybe it can be modified to be 'name to (name or function)'? Is that highly undesirable? If not, I will submit a patch...
  • my Router is a Component kind, so it doesn't get any events waterfalled from it's owner
    This is a bug, it will be fixed soon.
  • Okay, I need some help and maybe a bit of feedback on my idea.

    Right now it is that you can define few Routers in your components (naturally), and then put components which want to receive waterfalled events about changed path from your routers as their components.

    But I have a trouble here: how do I find those components of routers? They are being assigned to owner.$ in this case which doesn't help me to find them. Any direction I should go?

    Or, do you think I'm doing right thing with Routers? For me it seems that it's worth it, flexibility could be quite high, but in other case maybe it should be single big Router with routes defined in it, but I don't see how this can fit in Enyo philosophy.
  • edited June 2013
    When running in a browser, is there a way to update the URL in the nav bar when rerouting programatically?
    {myRouteController}.handle('/newPath');
    I know it can be done by playing with the window state, but can (and should) the Router controller handle this?
  • Also wondering if there's a way to wire in exception handlers for the routes (i.e. 404, 500) ? Or would that have to be in a default route handler?
  • How would you trigger a 404/500 handler? If you change the URL to a page with those errors, you wouldn't have any Enyo code loaded on the client to run for it.
  • edited June 2013
    I guess what I'm trying to figure out is internal linking within the app, for example this is a valid URI
    .../index.html/#pageA
    But this will fail
    .../index.html#/pageA?param=A
    Because the hash has a location '/pageA', but can't handle URI paramaters.

    The Router could parse the arguments, and stick the parameters into a JSON object for the consuming handler. Something like this would be useful for dynamic deep linking to functionality within an app (or web site).

    Looks like I could override the
    handle(path)
    to do something like this? Maybe also
    trigger()
    ? What else would I need to change?

    ...

    Oh wait... I can use dynamic routing like this?
    /users/:user/:id
    I'll try that.
  • A separate question (suggestion?) about the Router....

    It appears that the Application takes a single Router (routes) instance? It would be useful for complex apps if there could be multiple Routers chained together. I tried adding multiple Router controllers to an app, but looks as if the last one took precedence and the others are ignored.

    The benefit is code maintenance/readability. Not sure how significant the downside of multiple objects might have on memory management. The goal is to create a web site (ideally responsive for smaller devices). I'm finding it easier to break apart content by functional domain (user login/signup, app functionality, user settings, ect) and it would be nice to break up router instances to map to each area.
  • @pcimino What code were you looking at that gave you this notion of "1" router? Make sure to take a look at the enyo.Router source. I think you're looking at some very old code. Currently there is no direct association between a Router and an Application object. You can have as many routers as you need. And some of them could be "internal" only (not related to hash-change events and just internal message passing).
  • edited June 2013
    I added multiple routers to my application. But it behaved as if only one router was intercepting anything.
    controllers: [{name:'route1',kind:'Route1'},
    {name:'route2',kind:'Route2'}]
    But when I'd try to trigger
    /some_path_in_route1
    it would go to the default path in Route2.

    Maybe I had a conflicting path somewhere? I'll take another look. Thanks.
  • Oddly I am getting this problem too. I have two separate apps on a page. Each with it's own router. The idea is to build modular apps. However, only the first application's router is every fired. They both work individually but not together. The controllers work as well. Is this an incorrect use case?

    App1:

    enyo.kind({ name: 'Home', kind: 'enyo.Application', controllers: [{ name: 'Home.routes', kind: 'Home.Routes' }] }); enyo.kind({ name: 'Home.Routes', kind: 'enyo.Router', history: true, navVw: null, routes: [{ path: '/main', default: true, handler: 'changeScreen' }, { path: '/sign-in', handler: 'changeScreen' }, changeScreen: function (route) { switch (route) { case '/sign-in': { vw = new Home.SignIn.Controller(); break; }; case '/main': { if (!this.navVw) { this.navVw = new Home.Navigation.Controller(); } vw = this.navVw; break; }; default: if (!this.navVw) { this.navVw = new Home.Navigation.Controller(); } vw = this.navVw; break; }; if (vw) vw.renderInto('MyBase'); } });

    App2:

    enyo.kind({ name: 'History', kind: 'enyo.Application', controllers: [{ name: 'History.routes', kind: 'History.Routes' }] }); enyo.kind({ name: 'History.Routes', kind: 'Router', history: true, routes: [{ path: '/history', default: true, handler: 'changeScreen' }], changeScreen: function (route) { switch (route) { case '/history': { vw = new History.Controller(); break; }; }; if (vw) vw.renderInto('MyBase'); } });

    index.html:

    <!DOCTYPE html> App Server new History(); var me = new Home(); me.renderInto('MyBase');
    I had to trim the code a bit before showing it, but the above is the gist of it. The controller's are ViewControllers.
  • edited August 2013
    Fixed it. One problem was mine, and the other is an error that enyo throws but doesn't seem to break things.

    My issue was a duh! The routes had a default entry in the switch. So...every time one found a route it didn't know it went to the default and stomped the other routes.

    The other issue clouded the problem for me. Applications have a kind of ViewController which means they require a view property or they break on line 67 in ViewController.js in the nightly build from 8/13/13. This stops enyo from properly cataloging more than one app into it's global applications object. Both of my ViewControllers are based off a custom kind that extends ViewController. However, I didn't want extend Application or base the root of my app off anything other than Application.

    I'll leave the duh! code up in case it can help anyone else.
    I'll leave the line 67, single app issue, here for the enyo team incase they want to add it to their JIRA. Unless the old external JIRA is still in use?
  • You should be able to have multiple enyo.Application instances and use that instead of a ViewController. Were you trying to have a single enyo.Application own a bunch of ViewControllers? You can do that, but you need some sort of simple view still, although if you turn off automatic rendering, you can get away with the App's view never actually being put into the DOM.
  • I'm using the Router to control what shows up, so I wanted the applications to load blank and let the router take control. I added a literal blank control as a view which I use as the app view, and the applications object gets built ok. The view Controllers inherit from a third View Controller with basic authentication and session features written in. By using the View Controller to host that common functionality, I can use an app with one View Controller or multiple View Controllers and everything uses the same code. Also, if the user comes in by bookmark, I know they will still get challenged when necessary.
Sign In or Register to comment.