I am currently rendering a list of views:
<ul>
{{#each newsItem in controller}}
{{view App.NewsItemView contentBinding="newsItem" class="news-item" }}
{{/each}}
</ul>
But I would like to inject a NewsItemController into each view.
I've tried using render, but this only seems to support a single view, giving the exception:
Uncaught Error: Handlebars error: Could not find property 'control'
on object .
I've found a brief mention of using control instead, but this no longer seems to be included.
So how can I render multiple versions of the same view, injecting a separate controller into each one?
{{render}} should be fixed in current master (if you build it from Github). You should be able to use it multiple times if you pass a model:
<ul>
{{#each controller}}
{{render "newsItem" this}}
{{/each}}
</ul>
{{control}} is still there but hidden behind a flag (because it's still experimental). To use it you need to do : ENV.EXPERIMENTAL_CONTROL_HELPER = true before including the ember.js file. If you can avoid using it, it would be better.
However I think the simplest approach would be to use itemController:
<ul>
{{#each controller itemController="newsItem"}}
{{view App.NewsItemView class="news-item" }}
{{/each}}
</ul>
I think you can combine them to make it simpler (I haven't tried it yet):
<ul>
{{each controller itemController="newsItem" itemViewClass="App.NewsItemView"}}
</ul>
Related
I have the following handlebars template:
<script type="text/x-handlebars" data-template-name="index">
{{log model}}
<button {{action 'getSuggestion'}}>Get suggestion</button>
{{log suggestion}}
{{#if suggestion}}
<p>There is a suggestion</p>
{{else}}
<p>NO suggestion</p>
{{/if}}
<ul>
{{#each item in model}}
<li>{{item}}</li>
{{/each}}
</ul>
</script>
Currently, the two log work as expected, but the button between them is not rendered.
A while ago I've added another <p>text</p> right in the beginning of the template and again, it didn't render.
Do you have any idea why? And is there a specific way to debug Ember applications? I find Handlebars extremely unpredictive, with elements being rendered or not after no specific reason, and with no errors shown...
The thing was pretty simple: I was using a somewhat older version of Ember.js. Updating to the latest one made everything work again.
I'm learning Ember right now and i'm beeing a bit confused because of the Docu of Ember and the getting started example.
In the Documentation it says:
In Ember.js, templates get their properties from controllers, which decorate a model.
And
Templates are always connected to controllers, not models.
But after doing the getting started guide i'm not sure if this is correct.
I've uploaded the finished TodoMVC app here: https://github.com/Yannic92/stackOverflowExamples/tree/master/Ember/TodoMVC
In the Index.html you'll find this template:
<script type="text/x-handlebars" data-template-name="todos/index">
<ul id="todo-list">
{{#each todo in model itemController="todo"}}
<li {{bind-attr class="todo.isCompleted:completed todo.isEditing:editing" }}>
{{#if todo.isEditing}}
{{edit-todo class="edit" value=todo.title focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
{{input type="checkbox" checked=todo.isCompleted class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{todo.title}}</label>
<button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
</script>
My question refers to the 3rd Line:
{{#each todo in model itemController="todo"}}
The Controller todo is only needed to provide the actions for the todos. The data is accessable even without this controller.
In my opinion there is the model directly connected with the template isn't it?
Or is there a default Controller like the docu mentioned here?
For convenience, Ember.js provides controllers that proxy properties from their models so that you can say {{name}} in your template rather than {{model.name}}.
As you can see in this line: <script type="text/x-handlebars" data-template-name="todos/index"> this is the template for / because the router has this line: this.route('todos', { path: '/'}). Which will have a controller named TodosController, even if you didn't write one ember will generate one for you. So when you delete it that's what happens.
In this template you loop through the todo's list. Each of these Todo models are decorated with a controller the TodoController. And with this line: {{#each todo in model itemController="todo"}} you tell ember to use this TodoController for every element in the list.
If you leave out the itemController ember assumes the todo's are part of the model for the IndexController provided by the IndexRoute.
By default ember has an empty controller which proxies everything to the underlying model. (Note: I believe this will change in ember 2.0). So it may look like it's directly coupled to the model. But you could write a controller that changes everything without changing the model.
I have successfully displayed JSON objects unto my template thanks the answer on my previous stackoverflow post setting data from route to controller error in Emberjs
Now, I am trying to display a nested JSON data objects to my template using the {{#each}} helper.
here is my code:
http://screencast.com/t/3fhpckr4E
It doesn't give me any errors on my dev console and also it just gives me blank text.
I've also wrote the code in different ways but still no luck..
any feedback would be appreciated
thanks,
You can do this in your template as follows:
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each item in model}}
<li>{{item.description}}</li>
<ul>
{{#each childItem in item.items}}
<li>{{childItem.title}}</li>
{{/each}}
</ul>
{{/each}}
</ul>
</script>
Working solution here
The problem with what you are doing is that there is no such thing as data.items.items. Each item in the data.items array has its own items property...
I've got a drag and drop setup in two views, currently. I am trying to pull those out and make reusable components out of them. At this point I'm not even worried about the actions and bringing that information back (that will be the next issue that I will look into). Right now I'm only worried about getting the proper data to display.
The templates for my current setup are:
The outside list view:
<ul class="sortable-list">
{{#each view.permission}}
{{ view App.GroupsPermissionView }}
{{/each}}
</ul>
The individual item view:
<li class="sortable-item">{{ this.displayName }}</li>
I have changed this into the following component templates:
drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{ drag-and-drop-item dadi=this.displayName }}
{{/each}}
</ul>
and drag-and-drop-item.handlebars:
<li class="sortable-item">{{ dadi }}</li>
I call this with {{ drag-and-drop dad=unselectedPermissions }} or {{ drag-and-drop dad=selectedPermissions }}
and this works fine.
Here is my issue. My other use of drag and drop does not use the field name of "displayName". The field is just "name". I'm sure other co-workers will need to also use other field names as well.
I've tried many different things to attempt to get it passed through to the inner component, but nothing has worked. I think it is a limitation in handlebars and that this will be impossible to do.
Any idea of what could be done here, if anything?
Edit: An update
I've got things somewhat closer...but now I've run into another related issue. Here's my current drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{ drag-and-drop-item self=this dadi=../field }}
{{/each}}
</ul>
Here's drag-and-drop-item.handlebars:
<li class="sortable-item">{{ dragAndDrop self dadi }}</li>
And here's drag_and_drop_helpers.js:
Ember.Handlebars.helper("dragAndDrop", function(context,value) {
return this.self.get(value);
});
I realize that context isn't being used above, I've got it in there because of testing I was doing.
Here's the thing...with the code above, I get the correct 'this'. If I return "this.self.get('displayName');" in the helper, it works. However, the ../field isn't being returned in the template. I so wish you could have nested {{}}'s...then this would work!
To get the ../field working, I found I could make the following change to drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{#if ../field}}
{{ drag-and-drop-item self=this dadi=../field }}
{{/if}}
{{/each}}
</ul>
But if I do this, 'this' isn't the right one, so I'm getting 'displayName' through, but the wrong context.
It seems I can have one, or the other, but not both.
I could really use some help here.
I got it figured out, after quite a few days of searching and trying lots of things.
I did not realize that you could use "view." to pull the information.
Here's the call to this:
{{ drag-and-drop dad=unselectedPermissions field="displayName" }}
Here's the working drag-and-drop.handlebars:
<ul class="sortable-list">
{{#each dad}}
{{ drag-and-drop-item self=this dadi=view.field }}
{{/each}}
</ul>
Here's the working drag-and-drop-item.handlebars:
<li class="sortable-item">{{ dragAndDrop dadi }}</li>
Here's the working drag_and_drop_helpers.js:
Ember.Handlebars.helper("dragAndDrop", function(value) {
return this.self.get(value);
});
I'm hoping this helps someone in the future so they don't repeat mistakes I've made.
Now, on to figuring out the coding for the component.js...
I have a container view which, among other things, displays a list of objects, like so:
{{#each}}
<div {{bind-attr class="author.first_name task"}}></div>
{{/each}}
I would like to hook a Javascript function everytime a DOM element is added to this list. I've tried doing:
didInsertElement: function() { ... }
But this hook apparently runs only the first time the view is initialized. I figured that maybe the hook doesn't run because the view is actually inserted once, and what's inserted more than once are just the nested element.
So should I use a nested view?
I tried something along these lines:
{{#each}}
{{#view App.SingleItemView}}
<div {{bind-attr class="author.first_name task"}}></div>
{{/view}}
{{/each}}
But in this case, though it works somehow, it doesn't get passed the necessary data that would render the properties such as author.first_name.
render will give you a new scope and is really easy to assign the content as well
<ul>
{{#each item in controller}}
{{render 'ind' item}}
{{/each}}
</ul>
http://emberjs.jsbin.com/alAKubo/1/edit