Series: EmberSchool Samples: Intermediate Components
Yielding Data into Block Components
Published on Jul 29, 2016
Code
//templates/about.hbs
{{#email-status pageName="'Bout" as |word word2|}}
<p>{{word}}. This is only on the About page.</p>
{{word2}}
{{/email-status}}
//templates/components/email-status.hbs
{{yield 'hello' 'world'}}
//components/collapsible-component.js
import Ember from 'ember';
export default Ember.Component.extend({
isOpen: false,
actions: {
toggleOpen(){
this.toggleProperty('isOpen');
}
}
});
//templates/components/collapsible-component.hbs
{{yield isOpen this}}
//templates/food.hbs
{{#each model as |food|}}
{{#collapsible-component as |isOpen component|}}
<div class="food-item {{if food.isAvailable '' 'not-available'}}">
<div {{action 'toggleOpen' target=component}} class="title-bar">{{food.name}} <span class="pull-right">{{if isOpen 'V' '>'}}</span></div>
{{#if isOpen}}
{{icon-image food.imageUrl left=true}}
<div class="description">{{food.description}}</div>
{{#link-to 'foods.food' food.id}}
<button>Show</button>
{{/link-to}}
{{#link-to 'foods.food.edit' food.id}}<button>Edit</button>{{/link-to}}
<button {{action 'toggleAvailability' food}}>
{{if food.isAvailable 'Make Unavailable' 'Make Available'}}
</button>
{{/if}}
</div>
{{/collapsible-component}}
{{/each}}
//controllers/foods.js
//...
actions: {
//...
toggleAvailability(food){
food.toggleProperty('isAvailable');
food.save();
}
}
Transcript
In block components not only can you give it some HTML in handlebars to use within the component, you can feed it variables that come from the component. In this video, we’re going to learn how to do that.
We’ll start off with the simple example in the email-status
. So we’re going to yield
the word hello
. And then on the about
page, we’ll grab the word. The way we do it is we say as
and then we have these pipes, and between these pipes are where we put the variables, the data that we’re using. And now we can put our word here. We can see that it’s yielded our word, hello. Now let’s yield a second word, and we’ll go ahead and call that word2
, and we’ll see that also yields.
So you can put in as many things as you want into the yield
block and you grab them as arguments here after as
. And of course if you feed in anything to the component, it goes before the as
.
Now let’s tackle something a little bit more ambitious. So in the food-item
component, we have the isOpen
property and the toggleOpen
action. And those aren’t specific to it being food. Let’s go ahead and abstract those away from the food-item
component into a collapsible-component
component. Let’s create this step by step.
First we’ll create the component, collapsible-component
in the command line. Then we’ll take the isOpen
property and add it to the component, and we’ll put in the toggleOpen
action. Then in the collapsible-component
template, we’re going to yield isOpen
. In the foods
template, we’re going to put our collapsible-component
component, and then we’re going to get isOpen
from the component. And what we’re going to be putting within the block of collapsible-component
is what’s currently in the template of food-item
. So we’ll just grab all of this and paste it in there. And as you can see, it’s already using the isOpen
boolean, and it was previously getting it directly from the food-item
component, now it’s being passed through to the block.
Then we’ll see that everything is showing up like it was before. And to show that we’re getting this from the component, we’re going to set isOpen
to true by default. And there we go, they’re all open at the start.
Now we’ll want to pass in the action toggleOpen
so that we can use that in here. But that’s not quite as easy as just passing in a boolean in order to get at that action
. In the collapsible-component
we’re going to have to pass in the entire component, so we do that using this
. So we’re going to pass in the entire component and we’re going to name that component
. And then the action
will be still toggleOpen
because that’s what it’s called, but we’ll put the target
as the component
. So we’re not targeting foods
controller like we would otherwise. We’re targeting the component that’s being passed out here which is the collapsible-component
. Now we can click these and they are collapsible components. Awesome.
But there is one more problem to fix. If we hit 'Make Unavailable', we’ll get an error saying that nothing handled the action toggleAvailability
. This is because we have the action toggleAvailability
on the food-item
component, but toggleAvailability
when it’s called here is in the foods
controller, so its target will be not the food-item
component, not even the collapsible-component
component, but the foods
controller. So let’s go ahead and add that. And now it’s all working.
If you’re ever wondering which JavaScript file to put an action in, know that it will target the JavaScript file that matches up with the handlebars file that you’re in. So if we’re in the foods
template for the controller, it will go into the foods
controller. If we were in a component like we were with food-item
, then it will go into that component. If we’re within a block component, then in order to get it to target that component, we have to specify that, since by default it will target whatever handlebars template it’s in. So that’s how we make a generic collapsible component, and of course don’t forget what we originally came here to learn, how to yield variables to a block component.