erikringsmuth / app-router

Router for Web Components
https://erikringsmuth.github.io/app-router/
MIT License
610 stars 83 forks source link

Allow a trailing wildcard to match when the final url segment is missing #68

Closed pdf closed 9 years ago

pdf commented 9 years ago

This allows you to define a route like:

<app-router>
 <app-route path="/user/*" template="/user-page.html"></app-route>
</app-router>

And have it match /user in addition to /user/sub.

In combination with #67, you can then do sane nested routing without redraws of the whole layout.

erikringsmuth commented 9 years ago

I think if I change the pattern matching rules it will be to add new options like optional patterns with () and multiple segments with **. I want to keep it as close to file globbing as possible where * matches 1 segment exactly where it isn't optional. I'll have to think about a new set of rules for a while. The set I have right now is pretty simple and not that powerful.

That said, you could use a regular expression in this case, but you wouldn't be able to get patch varialbes.

<app-route regex path="/\/user*./i" template="/user-page.html"></app-route>
pdf commented 9 years ago

The expression you want to be sure of matching only the path you're looking for is probably actually /^\/user\/*.*/i, and who wants to do that every time, or force users to work that out?

I know other routers handle a trailing wildcard this way - a trailing wild segment matches if empty, which leaves you with /user/, or /user once you drop the slash.

I was also going to look at adding **.

erikringsmuth commented 9 years ago

Yeah, regex is not fun if you haven't used it much. I want to look over some of the common routers like these and work out what they're all doing.

react router https://github.com/rackt/react-router/blob/master/docs/guides/path-matching.md

react router component (alternative react router) http://strml.viewdocs.io/react-router-component

angular ui-router https://github.com/angular-ui/ui-router/wiki/URL-Routing

backbone http://backbonejs.org/#Router

flatiron director https://github.com/flatiron/director#api-documentation

node file globbing https://github.com/isaacs/node-glob

benjaminapetersen commented 9 years ago

Interested in this thread. Been looking at a few routers, app-router seems promising. I'm looking at a use case where nested routers could be decoupled from a previous path, so something like:

path="/**/user/:userId"
- could have a leading path of a number of things, such as:
- /foo/123/user/456 or 
- /foo/123/bar/456/baz/789/user/123 or
- /foo/123/bar/456/baz/789/user/123?some_param=9876

I'd like to be able to load sub-modules that are concerned with just a particular chunk of the uri and still be able to get variable binding.

To support arbitrary url patterns now it seems like you can just use all params:

?foo=123&bar=456&baz=789&user=9876

But, that does make for uglier urls, and you miss out on the ability to declare those params i the route path. Meaning:

path="*"  // nothing needed to catch params foo, bar, baz... but now I'm not using paths in a meaningful way

Very interesting dilemma.

benjaminapetersen commented 9 years ago

Quick add to your router list, router.js is under Ember.js, and form what I've heard its supposedly the most powerful JS router.

router.js https://github.com/tildeio/router.js/

erikringsmuth commented 9 years ago

The Ember router looks similar to the React router. The user manually appends the view in the route's callback. I like the concept but I don't know how I would do it in HTML. I talked about it a little here https://github.com/erikringsmuth/app-router/issues/53.

I think there are three things we need to tackle to make the app-router handle multiple routers.

  1. We need the parent route to match zero to many child routes.
  2. We need the child to ignore the URL prefix.
  3. We need an option for the parent router to not re-render if only the child route changed. https://github.com/erikringsmuth/app-router/pull/67#issuecomment-69747202

Your example URLs + 1. The parent route should match all of them and the child route should match everything except the first URL.

Brain dumping syntaxes here...

parent routes

child routes

The thing to ballance is syntax simplicity and algorithm simplicity for speed's sake.

Globstar ** has the nice property of matching zero-to-many path segments. I think something like this might be simple enough to implement.

parent

child

The react-router has the additional feature of relative routes which ignore the prefix when they don't start with a /. https://github.com/rackt/react-router/blob/master/docs/guides/path-matching.md That would mean user/userId would also work as a child route.

Do you guys have a preference on any of these syntaxes?

benjaminapetersen commented 9 years ago

Nice thinking, chewing on this.

pdf commented 9 years ago

I think one of these is the right option for optionally dropping the slash:

/foo/:num/?**
/foo/:num(/**)

The first looks a bit janky, and the second makes me think it might be a match group. I think the second option looks better though.

erikringsmuth commented 9 years ago

This is the react style route /foo/:num/?**

And this is the backbone style route /foo/:num(/**)

Although that's not entirely true because they use a different syntax than ** for multiple segments.

I like the globstar syntax for multiple segments so I started implementing it here https://github.com/erikringsmuth/app-router/compare/globstar. It can also do optional trailing paths with /foo/:num/** since a globstar can match zero segments.

erikringsmuth commented 9 years ago

I got globstars ** working and tagged a new release 2.4.0. I also added support for relative routes.

https://erikringsmuth.github.io/app-router/#/api#path

The parent route can be set up like this.

/foo/:num/**

and the child route

user/:userId

which is the same as

/**/user/:userId