Last Updated: July 02, 2018
·
3.167K
· aceofspades

Components with structured markup in ember.js v1.10

The addition of block params to ember.js v1.10 means you can now pass parameters when yielding a component to a block. This opens the door for the placement of multiple pieces of content in structured markup defined in the component's template...where it belongs.

Let's say you want a simple header/body/footer structure, such as:

<div>
  <header>My header</header>
  <div class="body">My body</div>
  <footer>My footer</footer>
</div>

Previously, you might compose three sub-components with the top-level component:

{{#my-comp}}
  {{#my-comp-header}}My header{{/my-comp-header}}
  {{#my-comp-body}}My body{{/my-comp-body}}
  {{#my-comp-footer}}My footer{{/my-comp-footer}}
{{/my-comp}}

And the corresponding three templates (and maybe even a fourth if you have structure at the top level, which I'll leave out).

<header>{{yield}}</header>
<footer>{{yield}}</footer>
<div class="body">{{yield}}</div>

This time around, let's use a top-level template like this:

<header>{{yield header}}</header>
<div class="body">{{yield body}}</div>
<footer>{{yield footer}}</footer>

With just a little bit of magic in the component definition:

App.MyCompComponent = Ember.Component.extend({
  // homework: meta-programmed version
  header: {isHeader: true},
  footer: {isFooter: true},
  body:   {isBody: true}
});

And now we can instantiate the component and define its sections using if/else:

{{#my-comp as |section|}}
  {{#if section.isHeader}}
    My header
  {{else if section.isBody}}
    My body
  {{else if section.isFooter}}
    My footer
  {{/if}}
{{/my-comp}}

And that's it!

I've yet to investigate whether the conditional markup from multiple yields leaves any redundancies, but in any event it is fairly contained. Hopefully it is, or can be, optimized out by the framework.

JSBin: http://jsbin.com/ketahe/1

2 Responses
Add your response

Epic solution

over 1 year ago ·

You can just yield a hash of components. Every time the component is null, it's not rendered:
hbs <header>{{yield (hash header=(component 'some-header-container'))}}</header> <div class="body">{{yield (hash body=(component 'some-body-container')}}</div> <footer>{{yield (hash footer=(component 'some-footer-container')}}</footer>

{{#my-comp as |section|}}
  {{#section.header}}
    My header
  {{/section.header}}
  {{#section.body}}
    My body
  {{/section.body}}
  {{#section.footer}}
    My footer
  {{/section.footer}}
{{/my-comp}}

If a bit longer, it's much cleaner.

over 1 year ago ·