Second argument (controller) to handlebars each helper. What does it mean? - ember.js

I'm trying to analyse TodoMVC's Ember example. What does the second argument to the #each helper mean?
<ul id="todo-list">
{{#each filteredTodos itemController="todo"}}
<li {{bindAttr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
{{view Todos.EditTodoView todoBinding="this"}}
{{else}}
{{view Ember.Checkbox checkedBinding="isCompleted" class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label>
<button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
It's supposed to be an option hash but I'm not sure.

It sets the itemController property of the current controller (TodosController I presume) to todo i.e the instance of the TodoController.
That means that every item (<li> element) will be binded not to the TodosController but to a TodoController instance.
isEditing looks for the property on the instance of TodoController and {{ action "removeTodo" }} will call removeTodo function on TodoController.

Related

How do I pass a value from one .hbs file to another

I am trying to pass the index value from posts.hbs to the delete-post.hbs and then from delete-post.hbs to my delete-post.js function.
posts.hbs
<br>
<h2> Blog Posts </h2>
<ul>
{{#each model as |onePost index|}}
<li id = {{index}}>{{onePost.title}} {{delete-post}}
</li><br>
{{/each}}
</ul>
{{add-new-post}}
delete-post.hbs
<a class="ui red button" {{action 'deletePost' parentNode.id `}}>Delete</a>`
delete-post.js
import Component from '#ember/component';
export default Component.extend
({
actions:
{
deletePost(input)
{
alert(input);
}
}
});
You can pass the parameter by = operator like {{component-name componentProperty=outerProperty. In your case:
{{#each model as |onePost index|}}
<li id = {{index}}>{{onePost.title}} {{delete-post parentNodeId=index}}
</li><br>
{{/each}}
Also, you should change parentNode.id to parentNodeId in your delete-post.hbs

How to set itemController for instance variable in ember.js indexController?

I have a Ember.js page that displays a table of items and shows details of one of the items when it is selected. The controller looks like this:
CV.IndexController = Ember.ArrayController.extend({
itemController: "CurrVitae",
selectedCurrVitae: false,
actions: {
selectCurrVitae: function(currVitae) {
this.set('selectedCurrVitae', currVitae)
}
}
});
And the index controller is used in a template like this:
<div class="container">
<div class="curr-vitae-list">
{{#each curr_vitae in controller}}
<div class="curr-vitae-item row">
<div class="col-sm-2" {{action selectCurrVitae curr_vitae}}>
{{curr_vitae.name}}
</div>
<div class="col-sm-2">
<!-- NOTE: This method is defined on the item
controller (not the model) so the itemController is
available at this point. -->
{{curr_vitae.createdAtDisplay}}
</div>
<div class="col-sm-7">
<div class="embedded-cell">
{{curr_vitae.summary}}
</div>
<div class="embedded-cell">
{{curr_vitae.objective}}
</div>
</div>
</div>
{{/each}}
</div>
<div class="curr-vitae-view">
<h2>Details</h2>
<!-- EDIT: I have tried setting this
as {{#if selectedCurrVitae itemController="currVitae" }}
to match the way the #each handles item controllers but that did
not seem to work -->
{{#if selectedCurrVitae }}
<!-- NOTE: Down here, however, the item controller is not available
so I can't use methods defined on the item controller for the
currently selected instance. -->
{{ partial "cv_index_details" }}
{{/if}}
</div>
</div>
Question: The problem I'm running in to is that the itemController I've set in the index controller is not available when rendering the selectedCurrVitae in the cv_index_details.
More details:
Specifically, in the partial I want to reuse a editor component (taken from Noel Rappin's Ember.js book). So if the cv_index_details partial looks like this:
<h3 class="selected_cv">{{selectedCurrVitae.name}}</h3>
<div class="row selected_cv_summary">
<h4>Summary</h4>
{{block-editor emberObject=selectedCurrVitae propName="summary" action="itemChanged"}}
</div>
<div class="row selected_cv_experiences">
<h4>Experiences</h4>
{{#each experience in selectedCurrVitae.experiences itemController="experience"}}
{{ partial "experience_detail" }}
{{/each}}
</div>
So in this template, the itemChanged action is not found for the selectedCurrVitae instance. However, I use the same block-editor component for the experience instance and that works correctly; the itemChanged action defined on the ExperienceController is found.
selectedCurrVitae is outside of the itemController, the itemController is only applied inside the each (on each item, hence the name).
Probably the easiest way to accomplish this will be to reuse the item controller and use render.
Template
{{#if selectedCurrVitae }}
{{ render "cv_index_details" }}
{{/if}}
Controller
CV.CvIndexDetailsController = CV.CurrVitaeController.extend();
Or
Template
{{#if selectedCurrVitae }}
{{ render "currVitae" }}
{{/if}}
View
CV.CurrVitaeView = Ember.View.extend({
templateName: 'cv_index_details'
});

Pass variable to #each in handlebars?

I have template that looks like this:
calling it:
{{Gd-text-input label="Specify" name="Specify" key="entry.810220554" hideIf=true}}
The template:
<script type="text/x-handlebars" data-template-name='components/Gd-radio-input'>
{{log key}}
{{#each content}}
{{log key}}
<div class="radiobutton">
{{radio-button id=label value=label name=key }}
<label {{bind-attr for="label"}}>{{label}}</label>
</div>
{{/each}}
</script>
The first log key outputs asdf. The one inside the #each – loop is undefined. How can I tell the Each-loop about the variable or access it from outside the loop?
view.key is what is needed, so
{{log view.key}}
will output the variable-name

I can't loop an Object-Array with ember #each

<div class="nav-menu clearfix">
<ul class="list-unstyled list-inline">
{{#each MI in MB}}
<li id=""><span>{{ MI.MText }}</span></li>
{{else}}
{{MB}}
{{/each}}
</ul>
</div>
I want loop the MB with each.
but it dose not work and return the MB is empty.
but I get this for else.
[object Object],[object Object],[object Object],[object
Object],[object Object]
this is my route define
//application路由
App.ApplicationRoute = Ember.Route.extend(App.LazyLoadTemplate, {
model : function() {
return Ember.$.getJSON("/index/indexjson");
}
});
and get a json data is
{
'UIB':{...},
'MB':[{...},{...},...,{...}]
}
My English is not well ,Thanks for help!
As you already found, your scope of your property was incorrect. Just to set the record straight, Ember-Handlebars will not iterate over an object like it will over an Array. Additionally the else statement is totally legit, it will be triggered when the array being iterated across is empty (null/undefined/no elements)
{{#each item in model}}
{{item}}
{{else}}
No Items
{{/each}}
http://emberjs.jsbin.com/iWohUlE/1/edit
Edit as kingpin pointed out in his answer, this response is referencing the wrong version of handlebars.
Your misusing the block helper each in your template. Handlebars each will work similarly with objects and arrays. In addition you had an else outside of an if block. Rewrite your template as follows:
<div class="nav-menu clearfix">
<ul class="list-unstyled list-inline">
{{#each MB}}
<li id=""><span>{{ MText }}</span></li>
{{/each}}
</ul>
</div>
Fiddle example

How can I click to edit on a text field with ArrayController?

I was following the tutorial but the tutorial is for the object controller. In an Array controller how do I properly pass in the object for the text field so it triggers the update for that model object?
Right now I can double click, and then type in some value, and if I hit enter I get the value plus undefined method set.
Uncaught TypeError: Object asdasdasdasdasd has no method 'set'
I guess it's passing the raw value into the controller and then trying to run methods off of that. How do I get it to pass the actual model?
View:
<ul>
{{#each}}
<li {{bind-attr class="isEditing:editing"}} {{action "editWorkout" this on="doubleClick"}}>
{{#if isEditing}}
{{view Ember.TextField class='edit' action="updateWorkout"}}
{{else}}
{{#link-to 'workout' this}} {{title}} {{/link-to}}
{{/if}}
</li>
{{/each}}
<li>
{{newWorkoutName}}
</li>
</ul>
Controller:
EmberWorkouts.WorkoutsController = Ember.ArrayController.extend
actions:
editWorkout: (workout) ->
workout.set('isEditing', true)
createWorkout: ->
title = #get('newWorkoutName')
workout = #store.createRecord('workout', title: title)
#set('newWorkoutName', '')
workout.save()
updateWorkout: (workout) ->
workout.set('isEditing', false)
workout.save()
isEditing: false
Repo here if you want to investigate: https://github.com/ecl1pse/ember-workouts/tree/master/app
You can specify an itemController in your each and then use an ObjectController for each item in your list.
{{#each itemController="workout"}}
<li {{action editWorkout on="doubleClick"}}>
<!-- Other stuff goes here -->
</li>
{{/each}}
EmberWorkouts.WorkoutsController = Ember.ObjectController.extend({
editWorkout : function(){
this.set('isEditing', true);
}
});
Here's a JSBin of the general idea : http://jsbin.com/ucanam/1038/edit