AlexGalays/abyssa-js

is matching multiple parameters in a route supported?

Closed this issue · 14 comments

Similar to Crossroads, I would like to match multiple parameters in the route definition. For instance, new State('app/:params') would match*
app/param1 AND
app/param1/param2 AND
app/param1/param2/param3

Is this functionality supported in abyssa?

Crossroads Reference
http://millermedeiros.github.io/crossroads.js/#crossroads-add_route

It also allows "rest" segments (ending with ) which can match multiple segments. Rest segments can be optional and/or required and don't need to be the last segment of the pattern. The pattern "{foo}/:bar:" will match news "news/123", "news/123/bar", "news/123/lorem/ipsum".

Right now, it's not supported. It looks easy to add though and could be useful indeed.
Can you give me a real life use case for it?
Also, would it be fine if it was mandatory that the rest path segments be the last ones? This is required to prevent conflicts.

With the current version of abyssa, the workaround would be to create 3 states and have two of them immediately redirect to the first one.

Hi,

Say I'm supporting 10 apps. I am looking to define as few routes as possible as over time, each app may require route maintenance. I may try to be very general at first with something like
app1/:params*
app2/:params*
...
app10/:params*

or even
:app/:params* (I don't think this is currently supported)

As routing / application use cases get better defined as the apps evolve, I may try to define more, but I want initially to have the most general use cases and fewest routes possible so that I have flexibility down the road to fine tune and build out the stateful routing use cases appropriately.

If I start with 30 routes or so initially and need to make updates, that's a lot more maintenance across the routes and applications.

Does this make sense? I would be happy to get rest path segments in any fashion. Ultimately, I'm looking for flexibility in defining less routes in whatever way possible. I think less State definitions will be easier to maintain.

Thanks,
Mark

Yes that makes sense. I want to tackle a rather fundamental refactoring first but I should be able to add this shortly after. Thanks for the suggestion.

So, new State('app/:rest*') would match
app/param1 AND
app/param1/param2 AND
app/param1/param2/param3

and in the enter handler of that state, we would get the usual params object with a rest property of either param1, param1/param2 or param1/param2/param3. Is this truly workable?

Hi,

Sorry the lag, I was away. Yes, if 'rest' could contain 'param1', 'param1/param2', 'param1/param2/param3', that would work well.

The consumer of the route (me) would have to parse the parameters further for routing specific needs. I think this is similar to how Crossroads works. I'm not suggesting Crossroads behavior needs to always be matched, but here it seems like a decent reference.

@saunders99999 You may factor out the States of your sub-applications and require them in your root application (if you know the sub-apps location relative to the root app). The Abyssa demo works that way.

@AlexGalays I think more important feature is to be able to add/remove the Router states in runtime after the router has been initialized. That would allow the self-contained components to construct States on the fly when they become available to the user (e.g. when they are lazy-loaded).

A real application example is a lazy-loading wizard (a dialog with steps). The application controller may not know all the wizard's States during the Router initialization because the wizard is not yet loaded.

@sompylasar I think it's a different issue. It looks like @saunders99999 simply wants to have less boilerplate/duplication when declaring many states that (at least at first) have similar logic.

Lazily loading code and states could be interesting for big apps. I thought locking the state tree at router init was a good idea at the time because it was easier to reason about a final state tree than a partial one that can change later. Can you perhaps create a new issue for that?

@AlexGalays Done. #21

As far as I understood, less boilerplate for @saunders99999 would be having some of the States abstracted and reused across applications.

FYI, #21 is a different feature request. Matching multiple parameters and dynamically updating states after init are two separate feature requests. I think both have value and give quite a bit of flexibility to end users.

Yes, I think I like both :)

Does this test make sense and cover your use case?

asyncTest('rest params', function() {

  var lastParams;

  var router = Router({
    index: State(),
    colors: State('colors/:rest*', function(params) {
      lastParams = params;
    })
  }).init('');

  whenSignal(router.changed)
    .then(goToColors)
    .then(wentToColorsOk)
    .then(goToColors2)
    .then(wentToColors2Ok)
    .then(goToColors3)
    .then(wentToColors3Ok)
    .done(start);

  function goToColors() {
    router.state('colors');
  }

  function wentToColorsOk() {
    return nextTick().then(function() {
      strictEqual(lastParams.rest, undefined);
    });
  }

  function goToColors2() {
    router.state('colors/red');
  }

  function wentToColors2Ok() {
    return nextTick().then(function() {
      strictEqual(lastParams.rest, 'red');
    });
  }

  function goToColors3() {
    router.state('colors/red/blue');
  }

  function wentToColors3Ok() {
    return nextTick().then(function() {
      strictEqual(lastParams.rest, 'red/blue');
    });
  }

});

@AlexGalays, yes, that matches the use case I outlined and makes sense. The matching extends as far as 'red/blue', but seems like the test will also work with 'red/blue/green/yellow/orange/indigo' ...

Looks good to me.

Should be fixed in ec965c1
I will release once I see the tests passing.

Thanks for the updates...