Using multiple yields in Ember to display header, body, footer in different places

Viewed 822

How to use multiple yields in Ember to display header, body, footer in different places? Added below a sample code for reference. But not working and throws the error saying,

Assertion Failed: A helper named "ib.footer" could not be found

components/common/info-bar-footer.hbs:

{{yield}}

components/common/info-bar-header.hbs:

{{yield}}

components/common/info-bar.hbs:

<div class="info-bar" style="display: {{if isopen 'block' 'none'}}">
    <div class="info-bar-header">
        <button class="btn-close" data-dismiss="info-bar" {{action "handleCloseInfoBar"}}>x</button>
        {{yield (hash header=(component "common/info-bar-header"))}}
    </div>
    <div class="info-bar-footer">
        {{yield (hash footer=(component "common/info-bar-footer"))}}
    </div>
</div>

templates/home.hbs:

{{#common/info-bar isopen=true as |ib|}}
    {{#ib.header}}
        <p class="info-content">
            Hello, nice to see you again
        </p>
    {{/ib.header}}
    {{#ib.footer}}
        <button class="btn-default">Ok</button>
    {{/ib.footer}}
{{/common/info-bar}}
1 Answers

Let me explain why you are getting error and how to solve it. You have the following template:

{{#common/info-bar isopen=true as |ib|}}
    {{#ib.header}}
        <p class="info-content">
            Hello, nice to see you again
        </p>
    {{/ib.header}}
    {{#ib.footer}}
        <button class="btn-default">Ok</button>
    {{/ib.footer}}
{{/common/info-bar}}

When this piece of code is run; the code block you provided in between #common/info-bar - /common/info-bar will be tried to be run for every piece of yield within the common/info-bar component. So for the first yield; common/info-bar yields the following json object which you named as ib in your block form usage: { header:(component "common/info-bar-header") }. That means; the execution of your block for the first yield has an ib object that simply does not contain any footer property. So; when you try to render the footer component with ib.footer; an error is raised which indicates ib.footer is not defined.

In order to fix that, you can yield additional properties to identify individual yields within common/info-bar. Let the code talk:

<div class="info-bar" style="display: {{if isopen 'block' 'none'}}">
    <div class="info-bar-header">
        <button class="btn-close" data-dismiss="info-bar" {{action "handleCloseInfoBar"}}>x</button>
        {{yield (hash header=(component "common/info-bar-header") isHeader=true)}}
    </div>
    <div class="info-bar-footer">
        {{yield (hash footer=(component "common/info-bar-footer") isFooter=true)}}
    </div>
</div>

now you can use these markers within home.hbs and perform condition checks as:

{{#common/info-bar isopen=true as |ib|}}
    {{#if ib.isHeader}}
        {{#ib.header}}
            <p class="info-content">
                Hello, nice to see you again
            </p>
        {{/ib.header}}
    {{/if}}
    {{#if ib.isFooter}}
        {{#ib.footer}}
            <button class="btn-default">Ok</button>
        {{/ib.footer}}
    {{/if}}
{{/common/info-bar}}

Those if checks within the code block will make sure that; you are placing the correct content to the correct yield place. I hope this clarifies the issue for you.

Related