Introduces a new Link
primitive to pass around self-contained references to
routes, like URLs, but with state (isActive
, ...) and methods (transitionTo
,
...). Also brings along an accompanying template helper and component for easy
usage in templates.
ember-link
does to routing whatember-concurrency
did to asynchrony!
— /r/whatjawsdid
ember install ember-link
👉 This is an Ember Octane addon. For a version that is compatible with older versions of Ember check out the
0.x
series.
👉 You are viewing the docs for an improved & refactored release (
^1.1.0
), that is 100 % backwards compatible to the1.0.0
version you're used to. There's no reason not to upgrade. ✨
The {{link}}
helper returns a UILink
instance.
When passing a single model, you can use model
instead of models
:
You can also mix and match the parameter styles, however you like.
Instead of the positional & named link parameters described above, you can also
create a Link
instance from a serialized URL.
fromURL
is mutually exclusive with the other link parameters: route
, model
& models
, query
In addition to the parameters shown above, the {{link}}
helper also accepts a
preventDefault
default parameter. It defaults to true
and intelligently
prevents hard browser transitions when clicking <a>
elements.
See @preventDefault
and UILink
.
Instead of using the {{#let}}
helper, you can use the
<Link>
component to achieve the same scoping effect, with
subjectively nicer syntax.
Even better yet, make Link
/ UILink
a first-class
primitive in your app architecture! Instead of manually wiring up
Link#url
and Link#transitionTo()
every time, rather
create your own ready-to-use, style-guide-compliant link and button components
that accept @link
as an argument instead of @href
and @onClick
.
This is akin to the popular async task button component concept.
Similar to the the {{link}}
helper, the <Link>
component
yields a UILink
instance.
Required.
The target route name.
Example
{{link-to}}
equivalent
Optional. Mutually exclusive with @model
.
An array of models / dynamic segments.
Example
{{link-to}}
equivalent
Optional. Mutually exclusive with @models
.
Shorthand for providing a single model / dynamic segment. The following two invocations are equivalent:
Optional.
Query Params object.
Example
{{link-to}}
equivalent
Optional. Mutually exclusive with @route
, @model
/
@models
, @query
.
Example
Optional. Default: true
If enabled, the transitionTo
and
replaceWith
actions will try to call
event.preventDefault()
on the first argument, if it is an
event. This is an anti-foot-gun to make <Link>
just work™️ with <a>
and
<button>
, which would otherwise trigger a native browser navigation / form
submission.
The <Link>
component yields a UILink
instance.
string
The URL for this link that you can pass to an <a>
tag as the href
attribute.
boolean
Whether this route is currently active, including potentially supplied models and query params.
In the following example, only one link will be is-active
at any time.
boolean
Whether this route is currently active, including potentially supplied models, but ignoring query params.
In the following example, the first two links will be is-active
simultaneously.
boolean
Whether this route is currently active, but ignoring models and query params.
In the following example, both links will be is-active
simultaneously.
(event?: Event) => Transition
Transition into the target route.
If @preventDefault
is enabled, also calls event.preventDefault()
.
(event?: Event) => Transition
Transition into the target route while replacing the current URL, if possible.
If @preventDefault
is enabled, also calls event.preventDefault()
.
A Link
is a self-contained reference to a concrete route, including models and
query params. It's basically like a
<LinkTo>
/ {{link-to}}
component you can pass around.
You can create a Link
via the LinkManager
service.
UILink
extends Link
with some anti-foot-guns and conveniences. It
can also be created via the LinkManager
service, but also via
the {{link}}
helper and <Link>
component.
Type: boolean
Whether this route is currently active, including potentially supplied models and query params.
Type: boolean
Whether this route is currently active, including potentially supplied models, but ignoring query params.
Type: boolean
Whether this route is currently active, but ignoring models and query params.
Type: string
The URL for this link that you can pass to an <a>
tag as the href
attribute.
Type: string
The target route name of this link.
Type: RouteModel[]
The route models passed in this link.
Type: Record<string, unknown> | undefined
The query params for this link, if specified.
Returns: Transition
Transition into the target route.
Returns: Transition
Transition into the target route while replacing the current URL, if possible.
UILink
extends Link
with anti-foot-guns and conveniences. This
class is meant to be used in templates, primarily through <a>
& <button>
elements.
It wraps transitionTo()
and replaceWith()
to optionally accept an event
argument. It will intelligently
- call
event.preventDefault()
to prevent hard page reloads - open the page in a new tab, when
Cmd
/Ctrl
clicking
It can be created via the LinkManager
service, but also via
the {{link}}
helper and <Link>
component.
The LinkManager
service is used by the {{link}} helper
and
<Link>
component to create UILink
instances.
You can also use this service directly to programmatically create link references.
Returns: Link
interface LinkParams {
/**
* The target route name.
*/
route: string;
/**
* Optional array of models / dynamic segments.
*/
models?: RouteModel[];
/**
* Optional query params object.
*/
query?: QueryParams;
}
Returns: UILink
interface UILinkParams {
/**
* Whether or not to call `event.preventDefault()`, if the first parameter to
* the `transitionTo` or `replaceWith` action is an `Event`. This is useful to
* prevent links from accidentally triggering real browser navigation or
* buttons from submitting a form.
*
* Defaults to `true`.
*/
preventDefault?: boolean;
}
Returns: LinkParams
Use this method to derive LinkParams
from a serialized, recognizable URL, that
you can then pass into createLink
/ createUILink
.
In acceptance / application tests (setupApplicationTest(hooks)
)
your app boots with a fully-fledged router, so ember-link
just works normally.
In integration / render tests (setupRenderingTest(hooks)
) the
router is not initialized, so ember-link
can't operate normally. To still
support using {{link}}
& friends in render tests, you can use the
setupLink(hooks)
test helper.
import { click, render } from '@ember/test-helpers';
import { setupRenderingTest } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupLink, linkFor, TestLink } from 'ember-link/test-support';
import hbs from 'htmlbars-inline-precompile';
module('`setupLink` example', function (hooks) {
setupRenderingTest(hooks);
setupLink(hooks);
test('`<Link>` component works in render tests', async function (assert) {
await render(hbs`
<Link @route="some.route" as |l|>
<a
href={{l.url}}
class={{if l.isActive "is-active"}}
{{on "click" l.transitionTo}}
>
Click me
</a>
</Link>
`);
const link = linkFor('some.route');
link.onTransitionTo = assert.step('link clicked');
await click('a');
assert.verifySteps(['link clicked']);
});
});
ember-engine-router-service
: Allows you to useember-link
inside enginesember-router-helpers
- RFC 391 "Router Helpers"
- RFC 339 "Router link component and routing helpers"
- RFC 459 "Angle Bracket Invocations For Built-in Components"