AlexxNB / tinro

Highly declarative, tiny, dependency free router for Svelte's web applications.
MIT License
675 stars 30 forks source link

Nesting with params #55

Closed larryhengl closed 3 years ago

larryhengl commented 3 years ago

Starting new to this lib and struggling to get the routes structured with optional params.

<!-- App.svelte --> 
...
<Route path="/*">
   <Main />
</Route>

<!-- Main.svelte --> 
...
<Route path="/targets/*" breadcrumb="Targets" firstmatch>
  <TargetsPage />
</Route>

<!-- TargetsPage.svelte --> 
...
  <Route path="/list/:T1/:T2" let:meta><List /></Route>
  <Route path="/summary/:T1/:T2" let:meta><Summary /></Route>
  <Route path="/:T1/:T2" let:meta><List /></Route>
  <Route fallback>
    <div>No Page</div>
  </Route>

What I want to see: /targets --> show List /targets/:T1 --> show List with meta T1 defined /targets/:T1/:T2 --> show List with meta T1 & T2 defined /targets/list --> show List /targets/list/:T1 --> show List with meta T1 defined /targets/list/:T1/:T2 --> show List with meta T1 & T2 defined /targets/summary --> show Summary /targets/summary/:T1 --> show Summary with T1 defined ...etc

What I'm seeing: /targets --> incorrectly shows No Page /targets/aa --> incorrectly shows No Page /targets/aa/bb --> correctly shows List with T1=aa & T2=bb /targets/list --> incorrectly shows No Page /targets/list/aa --> incorrectly shows List with T1=list and T2=aa /targets/list/aa/bb --> correctly shows List with T1=aa and T2=bb

In theory, I shouldn't need the fallback as the (sub)roots should land. But maybe could redirect if needed. The missing and mismatching of params is what's throwing me.

Anything obvious I'm missing?

Thank you for this library!

AlexxNB commented 3 years ago

There no optional params in URL. If you have /:T1/:T2 - both should exist to match route. /targets --> incorrectly shows No Page -- no any route with '/' path under '/targets' /targets/aa --> incorrectly shows No Page -- no any route with '/:T1' path under '/targets' /targets/list --> incorrectly shows No Page -- no any route with '/' path under '/targets/list' And so on...

In your case it should be something like this:

<!-- TargetsPage.svelte --> 
...
 <Route path="/list/*">
     <Route path="/"><List/></Route>
     <Route path="/:T1" let:meta><List {meta}/></Route>
     <Route path="/:T1/:T2" let:meta><List {meta}/></Route>
 </Route>
  <Route path="/summary/*">
     <Route path="/"><List/></Route>
     <Route path="/:T1" let:meta><Summary {meta}/></Route>
     <Route path="/:T1/:T2" let:meta><Summary {meta}/></Route>
 </Route>
  <Route path="/:T1" let:meta><List {meta}/></Route>
  <Route path="/:T1/:T2" let:meta><List {meta}/></Route>
  <Route fallback>
    <div>No Page</div>
  </Route>

Or you may create component-helper to extract params from URL as you want.

// Multiparams.svelte
<script>
    import {Route,meta} from 'tinro';
    const routeMeta = meta();

    export let names = '/';

    function makeParams(url,match,names){
        const params = names.split('/').slice(1);
        const values = url.replace(match,'').split('/').slice(1);
    return params.reduce((result,name,i)=>(result[name.replace(':','')]=values[i],result),{});
    }
</script>

<slot params={makeParams($routeMeta.url,$routeMeta.match,names)}/>
//TargetsPage.svelte
<Route path="/list/*">
    <Multiparams names="/:T1/:T2" let:params><List {params}/></Multiparams>
</Route>
<Route path="/summary/*">
    <Multiparams names="/:T1/:T2" let:params><Summary {params}/></Multiparams>
</Route>
<Route>
    <Multiparams names="/:T1/:T2" let:params><List {params}/></Multiparams>
</Route>
larryhengl commented 3 years ago

@AlexxNB , ok I'm starting to see how you've got this working. Very helpful response, much appreciated. Thanks again for tinro!