Class Ember.Templates.helpers
publiccomponent public
Defined in packages/@ember/-internals/glimmer/lib/helpers/component.ts:5
Available since v1.11.0
The {{component}}
helper lets you add instances of Component
to a
template. See Component for
additional information on how a Component
functions.
{{component}}
's primary use is for cases where you want to dynamically
change which type of component is rendered as the state of your application
changes. This helper has three modes: inline, block, and nested.
Inline Form
Given the following template:
{{component this.infographicComponentName}}
And the following application code:
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
export default class ApplicationController extends Controller {
@tracked isMarketOpen = 'live-updating-chart'
get infographicComponentName() {
return this.isMarketOpen ? 'live-updating-chart' : 'market-close-summary';
}
}
The live-updating-chart
component will be appended when isMarketOpen
is
true
, and the market-close-summary
component will be appended when
isMarketOpen
is false
. If the value changes while the app is running,
the component will be automatically swapped out accordingly.
Note: You should not use this helper when you are consistently rendering the same
component. In that case, use standard component syntax, for example:
<LiveUpdatingChart />
or
{{live-updating-chart}}
Block Form
Using the block form of this helper is similar to using the block form of a component. Given the following application template:
{{#component this.infographicComponentName}}
Last update: {{this.lastUpdateTimestamp}}
{{/component}}
The following controller code:
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { tracked } from '@glimmer/tracking';
export default class ApplicationController extends Controller {
@tracked isMarketOpen = 'live-updating-chart'
get lastUpdateTimestamp() {
return new Date();
}
get infographicComponentName() {
return this.isMarketOpen ? 'live-updating-chart' : 'market-close-summary';
}
}
And the following component template:
{{! chart }}
{{yield}}
The Last Update: {{this.lastUpdateTimestamp}}
will be rendered in place of the {{yield}}
.
Nested Usage
The component
helper can be used to package a component path with initial attrs.
The included attrs can then be merged during the final invocation.
For example, given a person-form
component with the following template:
{{yield (hash
nameInput=(component "my-input-component" value=@model.name placeholder="First Name")
)}}
When yielding the component via the hash
helper, the component is invoked directly.
See the following snippet:
<PersonForm as |form|>
<form.nameInput @placeholder="Username" />
</PersonForm>
or
{{#person-form as |form|}}
{{form.nameInput placeholder="Username"}}
{{/person-form}}
Which outputs an input whose value is already bound to model.name
and placeholder
is "Username".
When yielding the component without the hash
helper use the component
helper.
For example, below is a full-name
component template:
{{yield (component "my-input-component" value=@model.name placeholder="Name")}}
<FullName as |field|>
{{component field placeholder="Full name"}}
</FullName>
or
{{#full-name as |field|}}
{{component field placeholder="Full name"}}
{{/full-name}}
debugger public
Defined in packages/@ember/-internals/glimmer/index.ts:403
Execute the debugger
statement in the current template's context.
{{debugger}}
When using the debugger helper you will have access to a get
function. This
function retrieves values available in the context of the template.
For example, if you're wondering why a value {{foo}}
isn't rendering as
expected within a template, you could place a {{debugger}}
statement and,
when the debugger;
breakpoint is hit, you can attempt to retrieve this value:
> get('foo')
get
is also aware of keywords. So in this situation
{{#each this.items as |item|}}
{{debugger}}
{{/each}}
You'll be able to get values from the current item:
> get('item.name')
You can also access the context of the view to make sure it is the object that you expect:
> context
each public
Defined in packages/@ember/-internals/glimmer/lib/helpers/each-in.ts:13
The {{#each}}
helper loops over elements in a collection. It is an extension
of the base Handlebars {{#each}}
helper.
The default behavior of {{#each}}
is to yield its inner block once for every
item in an array passing the item as the first block parameter.
Assuming the @developers
argument contains this array:
[{ name: 'Yehuda' },{ name: 'Tom' }, { name: 'Paul' }];
<ul>
{{#each @developers as |person|}}
<li>Hello, {{person.name}}!</li>
{{/each}}
</ul>
The same rules apply to arrays of primitives.
['Yehuda', 'Tom', 'Paul']
<ul>
{{#each @developerNames as |name|}}
<li>Hello, {{name}}!</li>
{{/each}}
</ul>
During iteration, the index of each item in the array is provided as a second block parameter.
<ul>
{{#each @developers as |person index|}}
<li>Hello, {{person.name}}! You're number {{index}} in line</li>
{{/each}}
</ul>
Specifying Keys
In order to improve rendering speed, Ember will try to reuse the DOM elements where possible. Specifically, if the same item is present in the array both before and after the change, its DOM output will be reused.
The key
option is used to tell Ember how to determine if the items in the
array being iterated over with {{#each}}
has changed between renders. By
default the item's object identity is used.
This is usually sufficient, so in most cases, the key
option is simply not
needed. However, in some rare cases, the objects' identities may change even
though they represent the same underlying data.
For example:
people.map(person => {
return { ...person, type: 'developer' };
});
In this case, each time the people
array is map
-ed over, it will produce
an new array with completely different objects between renders. In these cases,
you can help Ember determine how these objects related to each other with the
key
option:
<ul>
{{#each @developers key="name" as |person|}}
<li>Hello, {{person.name}}!</li>
{{/each}}
</ul>
By doing so, Ember will use the value of the property specified (person.name
in the example) to find a "match" from the previous render. That is, if Ember
has previously seen an object from the @developers
array with a matching
name, its DOM elements will be re-used.
There are two special values for key
:
@index
- The index of the item in the array.@identity
- The item in the array itself.
{{else}} condition
{{#each}}
can have a matching {{else}}
. The contents of this block will render
if the collection is empty.
<ul>
{{#each @developers as |person|}}
<li>{{person.name}} is available!</li>
{{else}}
<li>Sorry, nobody is available for this task.</li>
{{/each}}
</ul>
each-in public
Defined in packages/@ember/-internals/glimmer/lib/helpers/each-in.ts:124
Available since v2.1.0
The {{each-in}}
helper loops over properties on an object.
For example, given this component definition:
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
export default class extends Component {
@tracked developer = {
"name": "Shelly Sails",
"age": 42
};
}
This template would display all properties on the developer
object in a list:
<ul>
{{#each-in this.developer as |key value|}}
<li>{{key}}: {{value}}</li>
{{/each-in}}
</ul>
Outputting their name and age:
<ul>
<li>name: Shelly Sails</li>
<li>age: 42</li>
</ul>
has-block (the) Boolean public
Defined in packages/@ember/-internals/glimmer/index.ts:303
- the
- String
name of the block. The name (at the moment) is either "main" or "inverse" (though only curly components support inverse)
- returns
- Boolean
true
if the component was invoked with a block
{{(has-block)}}
indicates if the component was invoked with a block.
This component is invoked with a block:
{{#my-component}}
Hi Jen!
{{/my-component}}
This component is invoked without a block:
{{my-component}}
Using angle bracket invocation, this looks like:
<MyComponent>Hi Jen!</MyComponent> {{! with a block}}
<MyComponent/> {{! without a block}}
This is useful when you want to create a component that can optionally take a block and then render a default template when it is not invoked with a block.
{{#if (has-block)}}
Welcome {{yield}}, we are happy you're here!
{{else}}
Hey you! You're great!
{{/if}}
has-block-params (the) Boolean public
Defined in packages/@ember/-internals/glimmer/index.ts:348
- the
- String
name of the block. The name (at the moment) is either "main" or "inverse" (though only curly components support inverse)
- returns
- Boolean
true
if the component was invoked with block params
{{(has-block-params)}}
indicates if the component was invoked with block params.
This component is invoked with block params:
{{#my-component as |favoriteFlavor|}}
Hi Jen!
{{/my-component}}
This component is invoked without block params:
{{#my-component}}
Hi Jenn!
{{/my-component}}
With angle bracket syntax, block params look like this:
<MyComponent as |favoriteFlavor|>
Hi Jen!
</MyComponent>
And without block params:
<MyComponent>
Hi Jen!
</MyComponent>
This is useful when you want to create a component that can render itself differently when it is not invoked with block params.
{{#if (has-block-params)}}
Welcome {{yield this.favoriteFlavor}}, we're happy you're here and hope you
enjoy your favorite ice cream flavor.
{{else}}
Welcome {{yield}}, we're happy you're here, but we're unsure what
flavor ice cream you would enjoy.
{{/if}}
helper public
Defined in packages/@ember/-internals/glimmer/lib/helpers/helper.ts:5
Available since v3.27.0
Use the {{helper}}
helper to create contextual helper so
that it can be passed around as first-class values in templates.
{{#let (helper "join-words" "foo" "bar" separator=" ") as |foo-bar|}}
{{!-- this is equivalent to invoking `{{join-words "foo" "bar" separator=" "}}` --}}
{{foo-bar}}
{{!-- this will pass the helper itself into the component, instead of invoking it now --}}
<MyComponent @helper={{helper foo-bar "baz"}} />
{{!-- this will yield the helper itself ("contextual helper"), instead of invoking it now --}}
{{yield foo-bar}}
{{/let}}
Arguments
The {{helper}}
helper works similarly to the {{component}}
and
{{modifier}}
helper:
When passed a string (e.g.
(helper "foo")
) as the first argument, it will produce an opaque, internal "helper definition" object that can be passed around and invoked elsewhere.Any additional positional and/or named arguments (a.k.a. params and hash) will be stored ("curried") inside the definition object, such that, when invoked, these arguments will be passed along to the referenced helper.
if public
Defined in packages/@ember/-internals/glimmer/lib/helpers/if-unless.ts:5
The if
helper allows you to conditionally render one of two branches,
depending on the "truthiness" of a property.
For example the following values are all falsey: false
, undefined
, null
, ""
, 0
, NaN
or an empty array.
This helper has two forms, block and inline.
Block form
You can use the block form of if
to conditionally render a section of the template.
To use it, pass the conditional value to the if
helper,
using the block form to wrap the section of template you want to conditionally render.
Like so:
<Weather />
{{! will not render because greeting is undefined}}
{{#if @isRaining}}
Yes, grab an umbrella!
{{/if}}
You can also define what to show if the property is falsey by using
the else
helper.
{{#if @isRaining}}
Yes, grab an umbrella!
{{else}}
No, it's lovely outside!
{{/if}}
You are also able to combine else
and if
helpers to create more complex
conditional logic.
For the following template:
{{#if @isRaining}}
Yes, grab an umbrella!
{{else if @isCold}}
Grab a coat, it's chilly!
{{else}}
No, it's lovely outside!
{{/if}}
If you call it by saying isCold
is true:
<Weather @isCold={{true}} />
Then Grab a coat, it's chilly!
will be rendered.
Inline form
The inline if
helper conditionally renders a single property or string.
In this form, the if
helper receives three arguments, the conditional value,
the value to render when truthy, and the value to render when falsey.
For example, if useLongGreeting
is truthy, the following:
<Greeting @useLongGreeting={{true}} />
{{if @useLongGreeting "Hello" "Hi"}} Alex
Will render:
Hello Alex
One detail to keep in mind is that both branches of the if
helper will be evaluated,
so if you have {{if condition "foo" (expensive-operation "bar")
,
expensive-operation
will always calculate.
in-element public
Defined in packages/@ember/-internals/glimmer/lib/syntax/in-element.ts:5
The in-element
helper renders its block content outside of the regular flow,
into a DOM element given by its destinationElement
positional argument.
Common use cases - often referred to as "portals" or "wormholes" - are rendering dropdowns, modals or tooltips close to the root of the page to bypass CSS overflow rules, or to render content to parts of the page that are outside of the control of the Ember app itself (e.g. embedded into a static or server rendered HTML page).
{{#in-element this.destinationElement}}
<div>Some content</div>
{{/in-element}}
Arguments
{{in-element}}
requires a single positional argument:
destinationElement
-- the DOM element to render into. It must exist at the time of rendering.
It also supports an optional named argument:
insertBefore
-- by default the DOM element's content is replaced when used asdestinationElement
. Passingnull
toinsertBefore
changes the behaviour to append the block content to the end of any existing content. Any other value thannull
is currently not supported.For example:
{{#in-element this.destinationElement insertBefore=null}} <div>Some content</div> {{/in-element}}
input (options) public
Defined in packages/@ember/-internals/glimmer/lib/components/input.ts:46
- options
- Hash
let public
Defined in packages/@ember/-internals/glimmer/lib/syntax/let.ts:5
The let
helper receives one or more positional arguments and yields
them out as block params.
This allows the developer to introduce shorter names for certain computations in the template.
This is especially useful if you are passing properties to a component that receives a lot of options and you want to clean up the invocation.
For the following example, the template receives a post
object with
content
and title
properties.
We are going to call the my-post
component, passing a title which is
the title of the post suffixed with the name of the blog, the content
of the post, and a series of options defined in-place.
{{#let
(concat post.title ' | The Ember.js Blog')
post.content
(hash
theme="high-contrast"
enableComments=true
)
as |title content options|
}}
<MyPost @title={{title}} @content={{content}} @options={{options}} />
{{/let}}
or
{{#let
(concat post.title ' | The Ember.js Blog')
post.content
(hash
theme="high-contrast"
enableComments=true
)
as |title content options|
}}
{{my-post title=title content=content options=options}}
{{/let}}
link-to public
Defined in packages/@ember/-internals/glimmer/lib/components/link-to.ts:256
log (params) public
Defined in packages/@ember/-internals/glimmer/lib/helpers/log.ts:5
- params
- Array
log
allows you to output the value of variables in the current rendering
context. log
also accepts primitive types such as strings or numbers.
{{log "myVariable:" myVariable }}
modifier public
Defined in packages/@ember/-internals/glimmer/lib/helpers/modifier.ts:5
Available since v3.27.0
Use the {{modifier}}
helper to create contextual modifier so
that it can be passed around as first-class values in templates.
{{#let (modifier "click-outside" click=this.submit) as |on-click-outside|}}
{{!-- this is equivalent to `<MyComponent {{click-outside click=this.submit}} />` --}}
<MyComponent {{on-click-outside}} />
{{!-- this will pass the modifier itself into the component, instead of invoking it now --}}
<MyComponent @modifier={{modifier on-click-outside "extra" "args"}} />
{{!-- this will yield the modifier itself ("contextual modifier"), instead of invoking it now --}}
{{yield on-click-outside}}
{{/let}}
Arguments
The {{modifier}}
helper works similarly to the {{component}}
and
{{helper}}
helper:
When passed a string (e.g.
(modifier "foo")
) as the first argument, it will produce an opaque, internal "modifier definition" object that can be passed around and invoked elsewhere.Any additional positional and/or named arguments (a.k.a. params and hash) will be stored ("curried") inside the definition object, such that, when invoked, these arguments will be passed along to the referenced modifier.
mount (name, model) public
Defined in packages/@ember/-internals/glimmer/lib/syntax/mount.ts:17
- name
- String
Name of the engine to mount.
- model
- Object
Object that will be set as the model of the engine.
The {{mount}}
helper lets you embed a routeless engine in a template.
Mounting an engine will cause an instance to be booted and its application
template to be rendered.
For example, the following template mounts the ember-chat
engine:
{{! application.hbs }}
{{mount "ember-chat"}}
Additionally, you can also pass in a model
argument that will be
set as the engines model. This can be an existing object:
<div>
{{mount 'admin' model=userSettings}}
</div>
Or an inline hash
, and you can even pass components:
<div>
<h1>Application template!</h1>
{{mount 'admin' model=(hash
title='Secret Admin'
signInButton=(component 'sign-in-button')
)}}
</div>
mut (attr) public
Defined in packages/@ember/-internals/glimmer/lib/helpers/mut.ts:9
- attr
- Object
the "two-way" attribute that can be modified.
The mut
helper lets you clearly specify that a child Component
can update the
(mutable) value passed to it, which will change the value of the parent component.
To specify that a parameter is mutable, when invoking the child Component
:
<MyChild @childClickCount={{fn (mut totalClicks)}} />
or
{{my-child childClickCount=(mut totalClicks)}}
The child Component
can then modify the parent's value just by modifying its own
property:
// my-child.js
export default Component.extend({
click() {
this.incrementProperty('childClickCount');
}
});
Note that for curly components ({{my-component}}
) the bindings are already mutable,
making the mut
unnecessary.
Additionally, the mut
helper can be combined with the fn
helper to
mutate a value. For example:
<MyChild @childClickCount={{this.totalClicks}} @click-count-change={{fn (mut totalClicks))}} />
or
{{my-child childClickCount=totalClicks click-count-change=(fn (mut totalClicks))}}
The child Component
would invoke the function with the new click value:
// my-child.js
export default Component.extend({
click() {
this.get('click-count-change')(this.get('childClickCount') + 1);
}
});
The mut
helper changes the totalClicks
value to what was provided as the fn
argument.
The mut
helper, when used with fn
, will return a function that
sets the value passed to mut
to its first argument. As an example, we can create a
button that increments a value passing the value directly to the fn
:
{{! inc helper is not provided by Ember }}
<button onclick={{fn (mut count) (inc count)}}>
Increment count
</button>
on public
Defined in packages/@ember/-internals/glimmer/lib/modifiers/on.ts:5
Available since v3.11.0
The {{on}}
modifier lets you easily add event listeners (it uses
EventTarget.addEventListener
internally).
For example, if you'd like to run a function on your component when a <button>
in the components template is clicked you might do something like:
<button {{on 'click' this.saveLike}}>Like this post!</button>
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class LikePostComponent extends Component {
@action
saveLike() {
// someone likes your post!
// better send a request off to your server...
}
}
Arguments
{{on}}
accepts two positional arguments, and a few named arguments.
The positional arguments are:
event
-- the name to use when callingaddEventListener
callback
-- the function to be passed toaddEventListener
The named arguments are:
- capture -- a
true
value indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. - once -- indicates that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
- passive -- if
true
, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning. See Improving scrolling performance with passive listeners to learn more.
The callback function passed to {{on}}
will receive any arguments that are passed
to the event handler. Most commonly this would be the event
itself.
If you would like to pass additional arguments to the function you should use
the {{fn}}
helper.
For example, in our example case above if you'd like to pass in the post that was being liked when the button is clicked you could do something like:
<button {{on 'click' (fn this.saveLike @post)}}>Like this post!</button>
In this case, the saveLike
function will receive two arguments: the click event
and the value of @post
.
Function Context
In the example above, we used @action
to ensure that likePost
is
properly bound to the items-list
, but let's explore what happens if we
left out @action
:
import Component from '@glimmer/component';
export default class LikePostComponent extends Component {
saveLike() {
// ...snip...
}
}
In this example, when the button is clicked saveLike
will be invoked,
it will not have access to the component instance. In other
words, it will have no this
context, so please make sure your functions
are bound (via @action
or other means) before passing into on
!
outlet public
Defined in packages/@ember/-internals/glimmer/lib/syntax/outlet.ts:22
The {{outlet}}
helper lets you specify where a child route will render in
your template. An important use of the {{outlet}}
helper is in your
application's application.hbs
file:
<MyHeader />
<div class="my-dynamic-content">
<!-- this content will change based on the current route, which depends on the current URL -->
{{outlet}}
</div>
<MyFooter />
See the routing guide for more
information on how your route
interacts with the {{outlet}}
helper.
Note: Your content will not render if there isn't an {{outlet}}
for it.
page-title (param) public
Defined in packages/@ember/-internals/glimmer/lib/helpers/page-title.ts:5
- param
- String
page-title
allows you to set the title of any page in your application and
append additional titles for each route. For complete documentation, see
https://github.com/ember-cli/ember-page-title.
{{page-title "My Page Title" }}
textarea public
Defined in packages/@ember/-internals/glimmer/lib/components/textarea.ts:123
unbound public
Defined in packages/@ember/-internals/glimmer/lib/helpers/unbound.ts:10
The {{unbound}}
helper disconnects the one-way binding of a property,
essentially freezing its value at the moment of rendering. For example,
in this example the display of the variable name
will not change even
if it is set with a new value:
{{unbound this.name}}
Like any helper, the unbound
helper can accept a nested helper expression.
This allows for custom helpers to be rendered unbound:
{{unbound (some-custom-helper)}}
{{unbound (capitalize this.name)}}
{{! You can use any helper, including unbound, in a nested expression }}
{{capitalize (unbound this.name)}}
The unbound
helper only accepts a single argument, and it return an
unbound value.
unique-id public
Defined in packages/@ember/-internals/glimmer/lib/helpers/unique-id.ts:5
Available since v4.4.0
Use the {{unique-id}} helper to generate a unique ID string suitable for use as an ID attribute in the DOM.
<input id={{unique-id}} type="email" />
Each invocation of {{unique-id}} will return a new, unique ID string.
You can use the let
helper to create an ID that can be reused within a template.
{{#let (unique-id) as |emailId|}}
<label for={{emailId}}>Email address</label>
<input id={{emailId}} type="email" />
{{/let}}
unless public
Defined in packages/@ember/-internals/glimmer/lib/helpers/if-unless.ts:97
The unless
helper is the inverse of the if
helper. It displays if a value
is falsey ("not true" or "is false"). Example values that will display with
unless
: false
, undefined
, null
, ""
, 0
, NaN
or an empty array.
Inline form
The inline unless
helper conditionally renders a single property or string.
This helper acts like a ternary operator. If the first property is falsy,
the second argument will be displayed, otherwise, the third argument will be
displayed
For example, if you pass a falsey useLongGreeting
to the Greeting
component:
<Greeting @useLongGreeting={{false}} />
{{unless @useLongGreeting "Hi" "Hello"}} Ben
Then it will display:
Hi Ben
Block form
Like the if
helper, the unless
helper also has a block form.
The following will not render anything:
<Greeting />
{{#unless @greeting}}
No greeting was found. Why not set one?
{{/unless}}
You can also use an else
helper with the unless
block. The
else
will display if the value is truthy.
If you have the following component:
{{#unless @userData}}
Please login.
{{else}}
Welcome back!
{{/unless}}
Calling it with a truthy userData
:
<LoggedIn @userData={{hash username="Zoey"}} />
Will render:
Welcome back!
and calling it with a falsey userData
:
<LoggedIn @userData={{false}} />
Will render:
Please login.
yield (options) String public
Defined in packages/@ember/-internals/glimmer/index.ts:91
- options
- Hash
- returns
- String
HTML string
{{yield}}
denotes an area of a template that will be rendered inside
of another template.
Use with Component
When designing components {{yield}}
is used to denote where, inside the component's
template, an optional block passed to the component should render:
<LabeledTextfield @value={{@model.name}}>
First name:
</LabeledTextfield>
<label>
{{yield}} <Input @value={{@value}} />
</label>
Result:
<label>
First name: <input type="text" />
</label>
Additionally you can yield
properties into the context for use by the consumer:
<LabeledTextfield @value={{@model.validation}} @validator={{this.firstNameValidator}} as |validationError|>
{{#if validationError}}
<p class="error">{{validationError}}</p>
{{/if}}
First name:
</LabeledTextfield>
<label>
{{yield this.validationError}} <Input @value={{@value}} />
</label>
Result:
<label>
<p class="error">First Name must be at least 3 characters long.</p>
First name: <input type="text" />
</label>
yield
can also be used with the hash
helper:
<DateRanges @value={{@model.date}} as |range|>
Start date: {{range.start}}
End date: {{range.end}}
</DateRanges>
<div>
{{yield (hash start=@value.start end=@value.end)}}
</div>
Result:
<div>
Start date: July 1st
End date: July 30th
</div>
Multiple values can be yielded as block params:
<Banner @value={{@model}} as |title subtitle body|>
<h1>{{title}}</h1>
<h2>{{subtitle}}</h2>
{{body}}
</Banner>
<div>
{{yield "Hello title" "hello subtitle" "body text"}}
</div>
Result:
<div>
<h1>Hello title</h1>
<h2>hello subtitle</h2>
body text
</div>
However, it is preferred to use the hash helper, as this can prevent breaking changes to your component and also simplify the api for the component.
Multiple components can be yielded with the hash
and component
helper:
<Banner @value={{@model}} as |banner|>
<banner.Title>Banner title</banner.Title>
<banner.Subtitle>Banner subtitle</banner.Subtitle>
<banner.Body>A load of body text</banner.Body>
</Banner>
import Title from './banner/title';
import Subtitle from './banner/subtitle';
import Body from './banner/body';
export default class Banner extends Component {
Title = Title;
Subtitle = Subtitle;
Body = Body;
}
<div>
{{yield (hash
Title=this.Title
Subtitle=this.Subtitle
Body=(component this.Body defaultArg="some value")
)}}
</div>
Result:
<div>
<h1>Banner title</h1>
<h2>Banner subtitle</h2>
A load of body text
</div>
A benefit of using this pattern is that the user of the component can change the order the components are displayed.
<Banner @value={{@model}} as |banner|>
<banner.Subtitle>Banner subtitle</banner.Subtitle>
<banner.Title>Banner title</banner.Title>
<banner.Body>A load of body text</banner.Body>
</Banner>
Result:
<div>
<h2>Banner subtitle</h2>
<h1>Banner title</h1>
A load of body text
</div>
Another benefit to using yield
with the hash
and component
helper
is you can pass attributes and arguments to these components:
<Banner @value={{@model}} as |banner|>
<banner.Subtitle class="mb-1">Banner subtitle</banner.Subtitle>
<banner.Title @variant="loud">Banner title</banner.Title>
<banner.Body>A load of body text</banner.Body>
</Banner>
{{!-- note the use of ..attributes --}}
<h2 ...attributes>
{{yield}}
</h2>
{{#if (eq @variant "loud")}}
<h1 class="loud">{{yield}}</h1>
{{else}}
<h1 class="quiet">{{yield}}</h1>
{{/if}}
Result:
<div>
<h2 class="mb-1">Banner subtitle</h2>
<h1 class="loud">Banner title</h1>
A load of body text
</div>