Skip to content

Commit

Permalink
feat: RFC 459 compliance
Browse files Browse the repository at this point in the history
  • Loading branch information
buschtoens committed Mar 11, 2019
1 parent 415b25e commit 722bd89
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 33 deletions.
37 changes: 22 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ need to install

```hbs
<Link
@routeName="some.route"
@route="some.route"
@models={{array 123}}
@queryParams={{hash foo="bar"}}
@query={{hash foo="bar"}}
as |l|>
<a
href={{l.href}}
Expand All @@ -49,7 +49,7 @@ as |l|>

### Arguments

#### `@routeName`
#### `@route`

Required.

Expand All @@ -58,7 +58,7 @@ The target route name.
**Example**

```hbs
<Link @routeName="some.route" as |l|>
<Link @route="some.route" as |l|>
<a
href={{l.href}}
class={{if l.isActive "is-active"}}
Expand Down Expand Up @@ -86,7 +86,7 @@ An array of models / dynamic segments.
**Example**

```hbs
<Link @routeName="some.route" @models={{array someModel someNestedModel}} as |l|>
<Link @route="some.route" @models={{array someModel someNestedModel}} as |l|>
<a
href={{l.href}}
class={{if l.isActive "is-active"}}
Expand All @@ -105,7 +105,7 @@ An array of models / dynamic segments.
{{/link-to}}
```

#### `@queryParams`
#### `@query`

Optional.

Expand All @@ -114,7 +114,7 @@ Query Params object.
**Example**

```hbs
<Link @routeName="some.route" @queryParams={{hash foo="bar"}} as |l|>
<Link @route="some.route" @query={{hash foo="bar"}} as |l|>
<a
href={{l.href}}
class={{if l.isActive "is-active"}}
Expand Down Expand Up @@ -155,7 +155,7 @@ submission
The URL for this link that you can pass to an `<a>` tag as the `href` attribute.

```hbs
<Link @routeName="some.route" as |l|>
<Link @route="some.route" as |l|>
<a href={{l.href}} {{on "click" l.transitionTo}}>
Click me
</a>
Expand All @@ -172,7 +172,7 @@ and query params.
In the following example, only one link will be `is-active` at any time.

```hbs
<Link @routeName="some.route" @models={{array 123}} @queryParams={{hash foo="bar"}} as |l|>
<Link @route="some.route" @models={{array 123}} @query={{hash foo="bar"}} as |l|>
<a
href={{l.href}}
class={{if l.isActive "is-active"}}
Expand All @@ -182,7 +182,7 @@ In the following example, only one link will be `is-active` at any time.
</a>
</Link>
<Link @routeName="some.route" @models={{array 123}} @queryParams={{hash foo="quux"}} as |l|>
<Link @route="some.route" @models={{array 123}} @query={{hash foo="quux"}} as |l|>
<a
href={{l.href}}
class={{if l.isActive "is-active"}}
Expand All @@ -203,7 +203,7 @@ but ignoring query params.
In the following example, the first two links will be `is-active` simultaneously.

```hbs
<Link @routeName="some.route" @models={{array 123}} @queryParams={{hash foo="bar"}} as |l|>
<Link @route="some.route" @models={{array 123}} @query={{hash foo="bar"}} as |l|>
<a
href={{l.href}}
class={{if l.isActiveWithoutQueryParams "is-active"}}
Expand All @@ -213,7 +213,7 @@ In the following example, the first two links will be `is-active` simultaneously
</a>
</Link>
<Link @routeName="some.route" @models={{array 123}} @queryParams={{hash foo="quux"}} as |l|>
<Link @route="some.route" @models={{array 123}} @query={{hash foo="quux"}} as |l|>
<a
href={{l.href}}
class={{if l.isActiveWithoutQueryParams "is-active"}}
Expand All @@ -223,7 +223,7 @@ In the following example, the first two links will be `is-active` simultaneously
</a>
</Link>
<Link @routeName="some.route" @models={{array 456}} @queryParams={{hash foo="quux"}} as |l|>
<Link @route="some.route" @models={{array 456}} @query={{hash foo="quux"}} as |l|>
<a
href={{l.href}}
class={{if l.isActiveWithoutQueryParams "is-active"}}
Expand All @@ -243,7 +243,7 @@ Whether this route is currently active, but ignoring models and query params.
In the following example, both links will be `is-active` simultaneously.

```hbs
<Link @routeName="some.route" @models={{array 123}} @queryParams={{hash foo="bar"}} as |l|>
<Link @route="some.route" @models={{array 123}} @query={{hash foo="bar"}} as |l|>
<a
href={{l.href}}
class={{if l.isActiveWithoutModels "is-active"}}
Expand All @@ -253,7 +253,7 @@ In the following example, both links will be `is-active` simultaneously.
</a>
</Link>
<Link @routeName="some.route" @models={{array 456}} @queryParams={{hash foo="quux"}} as |l|>
<Link @route="some.route" @models={{array 456}} @query={{hash foo="quux"}} as |l|>
<a
href={{l.href}}
class={{if l.isActiveWithoutModels "is-active"}}
Expand All @@ -279,3 +279,10 @@ If [`@preventDefault`](#preventdefault) is enabled, also calls `event.preventDef
Transition into the target route while replacing the current URL, if possible.

If [`@preventDefault`](#preventdefault) is enabled, also calls `event.preventDefault()`.

## Related RFCs / Projects

- [`ember-router-helpers`](https://github.com/rwjblue/ember-router-helpers)
- [RFC 391 "Router Helpers"](https://github.com/emberjs/rfcs/blob/master/text/0391-router-helpers.md)
- [RFC 339 "Router link component and routing helpers"](https://github.com/emberjs/rfcs/pull/339)
- [RFC 459 "Angle Bracket Invocations For Built-in Components"](https://github.com/emberjs/rfcs/blob/angle-built-ins/text/0459-angle-bracket-built-in-components.md#linkto)
51 changes: 40 additions & 11 deletions addon/components/link/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { inject as service } from '@ember-decorators/service';
import { action } from '@ember-decorators/object';
import { reads } from '@ember-decorators/object/computed';
import SparklesComponent, { tracked } from 'sparkles-component';
import { assert } from '@ember/debug';

function isQueryParams(
maybeQueryParam: any
Expand All @@ -23,17 +24,22 @@ export default class LinkComponent extends SparklesComponent<{
/**
* The target route name.
*/
routeName: string;
route: string;

/**
* Optional array of models / dynamic segments.
*/
models?: RouteModel[];

/**
* Optional shortcut for `@models={{array model}}`.
*/
model?: RouteModel;

/**
* Optional query params object.
*/
queryParams?: QueryParams;
query?: QueryParams;

/**
* Whether or not to call `event.preventDefault()`, if the first parameter to
Expand All @@ -52,34 +58,57 @@ export default class LinkComponent extends SparklesComponent<{
// @ts-ignore
private currentURL!: string;

didUpdate() {
super.didUpdate();

assert(
`You provided '@queryParams', but the argument you mean is just '@query'.`,
!('queryParams' in this.args)
);
assert(
`You provided '@routeName', but the argument you mean is just '@route'.`,
!('routeName' in this.args)
);
assert(
`'@route' needs to be a valid route name.`,
typeof this.args.route === 'string'
);
assert(
`You cannot use both '@model' ('${this.args.model}') and '@models' ('${
this.args.models
}') at the same time.`,
!(this.args.model && this.args.models)
);
}

@tracked('args')
private get modelsAndQueryParams(): [RouteModel[], null | QueryParams] {
const { models, queryParams } = this.args;
const { model, models, query } = this.args;
if (models) {
const lastModel = models[models.length - 1];

if (isQueryParams(lastModel)) {
if (queryParams) {
return [models.slice(0, -1), { ...lastModel.values, ...queryParams }];
if (query) {
return [models.slice(0, -1), { ...lastModel.values, ...query }];
}
return [models.slice(0, -1), { ...lastModel.values }];
}

return [models, queryParams ? { ...queryParams } : null];
return [models, query ? { ...query } : null];
}

return [[], queryParams ? { ...queryParams } : null];
return [model ? [model] : [], query ? { ...query } : null];
}

@tracked
private get routeArgs() {
const [models, queryParams] = this.modelsAndQueryParams;

if (queryParams) {
return [this.args.routeName, ...models, { queryParams }];
return [this.args.route, ...models, { queryParams }];
}

return [this.args.routeName, ...models];
return [this.args.route, ...models];
}

/**
Expand Down Expand Up @@ -109,7 +138,7 @@ export default class LinkComponent extends SparklesComponent<{
@tracked('args', 'currentURL')
get isActiveWithoutQueryParams() {
return this.router.isActive(
this.args.routeName,
this.args.route,
// @ts-ignore
...this.modelsAndQueryParams[0]
);
Expand All @@ -121,7 +150,7 @@ export default class LinkComponent extends SparklesComponent<{
*/
@tracked('args', 'currentURL')
get isActiveWithoutModels() {
return this.router.isActive(this.args.routeName);
return this.router.isActive(this.args.route);
}

/**
Expand Down
46 changes: 39 additions & 7 deletions tests/acceptance/link-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module('Acceptance | link', function(hooks) {
this.owner.register(
'template:application',
hbs`
<Link @routeName="foo" as |l|>
<Link @route="foo" as |l|>
<a
data-test-link
href={{l.href}}
Expand Down Expand Up @@ -77,7 +77,39 @@ module('Acceptance | link', function(hooks) {
this.owner.register(
'template:application',
hbs`
<Link @routeName="with-model" @models={{array 123}} as |l|>
<Link @route="with-model" @models={{array 123}} as |l|>
<a
data-test-link
href={{l.href}}
class={{if l.isActive "is-active"}}
{{on "click" l.transitionTo}}
>
Link
</a>
</Link>
`
);

await visit('/');
assert.equal(currentURL(), '/');

assert.dom('[data-test-link]').hasAttribute('href', '/with-model/123');
assert.dom('[data-test-link]').hasNoClass('is-active');

await click('[data-test-link]');
assert.equal(currentURL(), '/with-model/123');
assert.dom('[data-test-link]').hasClass('is-active');
});

test('@model shorthand', async function(this: TestContext, assert) {
this.Router.map(function() {
this.route('with-model', { path: 'with-model/:id' });
});

this.owner.register(
'template:application',
hbs`
<Link @route="with-model" @model="123" as |l|>
<a
data-test-link
href={{l.href}}
Expand Down Expand Up @@ -111,7 +143,7 @@ module('Acceptance | link', function(hooks) {
this.owner.register(
'template:application',
hbs`
<Link @routeName="with-model.nested-model" @models={{array 123 456}} as |l|>
<Link @route="with-model.nested-model" @models={{array 123 456}} as |l|>
<a
data-test-link
href={{l.href}}
Expand Down Expand Up @@ -145,7 +177,7 @@ module('Acceptance | link', function(hooks) {
this.owner.register(
'template:application',
hbs`
<Link @routeName="with-model" @models={{array 123}} as |l|>
<Link @route="with-model" @models={{array 123}} as |l|>
<a
data-test-123
href={{l.href}}
Expand All @@ -155,7 +187,7 @@ module('Acceptance | link', function(hooks) {
Link
</a>
</Link>
<Link @routeName="with-model" @models={{array 456}} as |l|>
<Link @route="with-model" @models={{array 456}} as |l|>
<a
data-test-456
href={{l.href}}
Expand Down Expand Up @@ -213,7 +245,7 @@ module('Acceptance | link', function(hooks) {
this.owner.register(
'template:application',
hbs`
<Link @routeName="foo" @queryParams={{hash qp=123}} as |l|>
<Link @route="foo" @query={{hash qp=123}} as |l|>
<a
data-test-123
href={{l.href}}
Expand All @@ -223,7 +255,7 @@ module('Acceptance | link', function(hooks) {
Link
</a>
</Link>
<Link @routeName="foo" @queryParams={{hash qp=456}} as |l|>
<Link @route="foo" @query={{hash qp=456}} as |l|>
<a
data-test-456
href={{l.href}}
Expand Down

0 comments on commit 722bd89

Please sign in to comment.