Skip to content

Commit

Permalink
feat(router-lite): ce aliases as configured route (#1723)
Browse files Browse the repository at this point in the history
<!---
Thanks for filing a pull request 😄 ! Before you submit, please read the
following:

Search open/closed issues before submitting since someone might have
pushed the same thing before!
-->

# Pull Request

## 📖 Description

<!---
Provide some background and a description of your work.
-->

This feature is requested internally by @brandonseydel.

### 🎫 Issues

<!---
* List and link relevant issues here.
-->

## 👩‍💻 Reviewer Notes

<!---
Provide some notes for reviewers to help them provide targeted feedback.
-->

## 📑 Test Plan

<!---
Please provide a summary of the tests affected by this work and any
unique strategies employed in testing the features/fixes.
-->

## ⏭ Next Steps

<!---
If there is relevant follow-up work to this PR, please list any existing
issues or provide brief descriptions of what you would like to do next.
-->

<!--
Love Aurelia? Please consider supporting our collective:
👉  https://opencollective.com/aurelia
-->
  • Loading branch information
Sayan751 committed Apr 4, 2023
1 parent 53dc8c2 commit 2b7f9fc
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 3 deletions.
27 changes: 27 additions & 0 deletions docs/user-docs/router-lite/configuring-routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,33 @@ You can see this configuration in action below.

{% embed url="https://stackblitz.com/edit/router-lite-component-ce-instance-jx3kee?ctl=1&embed=1&file=src/my-app.ts" %}

## Using classes as routes

Using router-lite it is also possible to use the routed view model classes directly as routes configuration.
The following example demonstrates that the `C1` and `C2` classes are used directly as the child routes for the `Root`.

```typescript
@customElement({ name: 'c-1', template: 'c1', aliases: ['c-a', 'c-one'] })
class C1 { }

@customElement({ name: 'c-2', template: 'c2', aliases: ['c-b', 'c-two'] })
class C2 { }

@route({
routes: [C1, C2]
})
@customElement({ name: 'ro-ot', template: '<au-viewport></au-viewport>' })
class Root { }
```

The example above implies that `router.load('c-1')` and `router.load('c-2')` will load the `C1` and `C2` respectively.

{% hint style="info" %}
To know more about the router API refer [this section](./navigating.md#using-the-router-api).
{% endhint %}

Note that this extends also for alias; that is using `router.load('c-a')` and `router.load('c-two')` will load the `C1` and `C2` respectively.

## Distributed routing configurations

The examples discussed so far demonstrate the classic use-cases of route configurations where the parents define the child routes.
Expand Down
149 changes: 149 additions & 0 deletions packages/__tests__/router-lite/smoke-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5472,4 +5472,153 @@ describe('router-lite/smoke-tests.spec.ts', function () {
await au.stop(true);
});
});

describe('CE alias', function () {
it('using the aliases as path works', async function () {
@customElement({ name: 'c-1', template: 'c1', aliases: ['c-a', 'c-one'] })
class C1 { }

@customElement({ name: 'c-2', template: 'c2', aliases: ['c-b', 'c-two'] })
class C2 { }

@route({
routes: [C1, C2]
})
@customElement({ name: 'ro-ot', template: '<au-viewport></au-viewport>' })
class Root { }

const { au, container, host } = await start({ appRoot: Root });
const router = container.get(IRouter);

assert.html.textContent(host, '');

await router.load('c-a');
assert.html.textContent(host, 'c1');

await router.load('c-b');
assert.html.textContent(host, 'c2');

await router.load('c-1');
assert.html.textContent(host, 'c1');

await router.load('c-2');
assert.html.textContent(host, 'c2');

await router.load('c-one');
assert.html.textContent(host, 'c1');

await router.load('c-two');
assert.html.textContent(host, 'c2');

await au.stop();

});

it('order of route decorator and the customElement decorator does not matter', async function () {
@route({ title: 'c1' })
@customElement({ name: 'c-1', template: 'c1', aliases: ['c-a', 'c-one'] })
class C1 { }

@customElement({ name: 'c-2', template: 'c2', aliases: ['c-b', 'c-two'] })
@route({ title: 'c2' })
class C2 { }

@route({
routes: [C1, C2]
})
@customElement({ name: 'ro-ot', template: '<au-viewport></au-viewport>' })
class Root { }

const { au, container, host } = await start({ appRoot: Root });
const router = container.get(IRouter);
const doc = container.get(IPlatform).document;

assert.html.textContent(host, '');

await router.load('c-a');
assert.html.textContent(host, 'c1');
assert.strictEqual(doc.title, 'c1');

await router.load('c-b');
assert.html.textContent(host, 'c2');
assert.strictEqual(doc.title, 'c2');

await router.load('c-1');
assert.html.textContent(host, 'c1');
assert.strictEqual(doc.title, 'c1');

await router.load('c-2');
assert.html.textContent(host, 'c2');
assert.strictEqual(doc.title, 'c2');

await router.load('c-one');
assert.html.textContent(host, 'c1');
assert.strictEqual(doc.title, 'c1');

await router.load('c-two');
assert.html.textContent(host, 'c2');
assert.strictEqual(doc.title, 'c2');

await au.stop();

});

it('explicitly defined paths always override CE name or aliases', async function () {

@route('c1')
@customElement({ name: 'c-1', template: 'c1', aliases: ['c-a'] })
class C1 { }

@customElement({ name: 'c-2', template: 'c2', aliases: ['c-b'] })
class C2 { }

@route({
routes: [C1, { path: 'c2', component: C2 }]
})
@customElement({ name: 'ro-ot', template: '<au-viewport></au-viewport>' })
class Root { }

const { au, container, host } = await start({ appRoot: Root });
const router = container.get(IRouter);

assert.html.textContent(host, '');

await router.load('c1');
assert.html.textContent(host, 'c1');

await router.load('c2');
assert.html.textContent(host, 'c2');

try {
await router.load('c-1');
assert.fail('expected error 1');
} catch (er) {
assert.match((er as Error).message, /'c-1' matched any configured route/);
}

try {
await router.load('c-a');
assert.fail('expected error 2');
} catch (er) {
assert.match((er as Error).message, /'c-a' matched any configured route/);
}

try {
await router.load('c-2');
assert.fail('expected error 3');
} catch (er) {
assert.match((er as Error).message, /'c-2' matched any configured route/);
}

try {
await router.load('c-b');
assert.fail('expected error 4');
} catch (er) {
assert.match((er as Error).message, /'c-b' matched any configured route/);
}

await au.stop();

});
});
});
7 changes: 4 additions & 3 deletions packages/router-lite/src/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ export class RouteConfig implements IRouteConfig, IChildRouteConfig {
public get path(): string[] {
const path = this._path;
if (path.length > 0) return path;
return this._path = [CustomElement.getDefinition(this.component as RouteType).name];
const ceDfn = CustomElement.getDefinition(this.component as RouteType);
return this._path = [ceDfn.name, ...ceDfn.aliases];
}
private constructor(
public readonly id: string,
Expand Down Expand Up @@ -165,7 +166,7 @@ export class RouteConfig implements IRouteConfig, IChildRouteConfig {
const redirectTo = config.redirectTo ?? Type?.redirectTo ?? null;
const caseSensitive = config.caseSensitive ?? Type?.caseSensitive ?? false;
const id = config.id ?? Type?.id ?? (path instanceof Array ? path[0] : path);
const reentryBehavior = config.transitionPlan ?? Type?.transitionPlan ?? /* parentConfig?.transitionPlan ?? */ null;
const reentryBehavior = config.transitionPlan ?? Type?.transitionPlan ?? null;
const viewport = config.viewport ?? Type?.viewport ?? defaultViewportName;
const data = {
...Type?.data,
Expand Down Expand Up @@ -309,7 +310,7 @@ export const Route = {
configOrPath: IRouteConfig | IChildRouteConfig | string | string[],
Type: T,
): T {
const config = RouteConfig._create(configOrPath, Type /* , isDefinedByType , null */);
const config = RouteConfig._create(configOrPath, Type);
Metadata.define(Route.name, config, Type);

return Type;
Expand Down

0 comments on commit 2b7f9fc

Please sign in to comment.