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

<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

Related

Ember Error while processing route: index Assertion Failed: Unable to find fixtures for model

I have my index page where i show a list of invoices where the user can click to create and edit them, i am using DS.FixtureAdapter in my adapter
The problem is that i get this error
Error while processing route: index Assertion Failed: Unable to find fixtures for model
If in my model i reopen the class like this, everything works fine
Invoice.reopenClass({
FIXTURES: [
{
id : '1',
name : 'Invoice num 1',
transactions: [1]
}
]
});
So i assume that i am doing something wrong in my template where i am saying if there are not invoices show me "no invoices..."
<div class="row">
<div class="large-6 columns">
<h3>View Invoices</h3>
<ul class="invoices-listing">
{{#each invoice in model}}
<li>
{{#link-to "invoices.show" invoice}}
{{invoice.name}}
{{/link-to}}
</li>
{{else}}
<li>no invoices… :(</li>
{{/each}}
</ul>
</div>
<div class="large-6 columns">
<h3>Edit Invoices</h3>
<ul class="invoices-listing">
{{#each invoice in model}}
<li>
{{#link-to "invoices.edit" invoice}}
{{invoice.name}}
{{/link-to}}
</li>
{{else}}
<li>no invoices… :(</li>
{{/each}}
</ul>
</div>
<div class="large-12 columns">
Invoices: {{InvoicesCount}}
</div>
<div class="large-12 columns">
{{#link-to "Invoices.create" class="create-btn"}} Add Invoice {{/link-to}}
</div>
</div>
Routes Index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.find('fattura');
}
});
This looks like a problem only when i start the ember server because for instance if i start creating and deleting invoices and i want to delete all of them the index page shows correctly "no invoices..."
You'll always need to set up fixtures even if you want to start with no records. Ember still needs somewhere to go look for them and will error if you don't at least have a fixture with an empty array.
So you can just start your project with this in your model:
Invoice.reopenClass({
FIXTURES: []
});

each vs each foo in model, differences and issue with link-to undefined

I'm trying to do a list of product items and make them so when you click the image or title it will show a single page/template with the more info, etc.
But, when ever I use {{#each product in model}} the link-to just returns an undefined.
Heres what I have
App.Router.map(function(){
this.route('about', { path: '/aboutus' } );
this.resource('products');
this.resource('product', { path: '/products/:title' } );
this.resource('contacts');
});
App.ProductsRoute = Ember.Route.extend ({
model: function(){
return App.PRODUCTS;
}
});
// Logging out Params from the Route
App.ProductRoute = Ember.Route.extend ({
model: function(params){
return App.PRODUCTS.findBy('title', params.title);
}
});
App.PRODUCTS = [
{
title: 'Flint',
price: 99,
description: 'Flint is a hard, sedimentary cryptocrystalline form of the mineral quartz, categorized as a variety of chert.',
isOnSale: true,
image: 'images/flint.png'
},
{
title: 'Kindling',
price: 249,
description: 'Easily combustible small sticks or twigs used for starting a fire.',
isOnSale: false,
image: 'images/kindling.png'
}
];
when I use this method {{#each product in model}} i get undefined
<script type='text/x-handlebars' data-template-name='products'>
<h1>Products</h1>
<ul class="list-unstyled col-md-8">
{{#each product in model}}
<li class='row m-b'>
{{#link-to 'product' this }}<img {{bind-attr src='product.image'}} class='img-thumbnail col-md-5' alt='product-image' />{{/link-to}}
<div class="col-md-7">
<h2>{{product.title}}</h2>
<p class="product-description">{{product.description}}</p>
<p><button class="btn btn-success">Buy for ${{product.price}}</button></p>
</div>
</li>
{{/each}}
</ul>
</script>
<script type='text/x-handlebars' data-template-name='product'>
<div class="row">
<div class="col-md-7">
<h2>{{title}}</h2>
<p>{{description}}</p>
<p>Buy for ${{price}}</p>
</div>
<div class="col-md-5">
<img {{bind-attr src='image'}} class='img-thumbnail img-rounded' />
</div>
</div>
</script>
but when I use just {{#each}} it returns normally BUT it warns me this: DEPRECATION: Using the context switching form of {{each}} is deprecated. Please use the keyword form ({{#each foo in bar}}) instead.
<script type='text/x-handlebars' data-template-name='products'>
<h1>Products</h1>
<ul class="list-unstyled col-md-8">
{{#each}}
<li class='row m-b'>
{{#link-to 'product' this }}<img {{bind-attr src='image'}} class='img-thumbnail col-md-5' alt='product-image' />{{/link-to}}
<div class="col-md-7">
<h2>{{title}}</h2>
<p class="product-description">{{description}}</p>
<p><button class="btn btn-success">Buy for ${{price}}</button></p>
</div>
</li>
{{/each}}
</ul>
</script>
which one should I use and how do I fix the undefined error? I'm guessing it has to do with the App.ProductRoute but can't figure it out, still new to ember :l
You should use
{{#each product in model}}
and to fix your undefined use the following:
{{#link-to 'product' product }} ...title... {{/link-to}}
When you use {{#each}} the context of this gets switched to each item in the loop, which is sometimes confusing and is being deprecated. When you use the {{#each product in model}} version, the context of each item through the loop is product and this remains whatever it was you entered each

Why didInsertElement hook trigger before elements rendered inside {{#each}} block?

I'm new to Ember, I want to add some query DOM manipulation code to the element in the {{#each}} block. So I google it up and found the solution from this guide:
views/products/index.js
import Spinner from 'appkit/utils/someJqueryCode';
Ember.View.reopen({
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent : function(){
// implement this hook in your own subclasses and run your jQuery logic there
}
});
export default Ember.View.extend({
afterRenderEvent: function() {
Spinner();
}
});
templates/products/index.hbs
<div class='panel panel-default products'>
<div class='panel-heading'>
<h2 class='panel-title'>Our Prodcuts</h2>
</div>
<div class='panel-body'>
<ul class='row'>
{{#each}}
<li class='col-md-4'>
<div class='thumbnail'>
<img {{bind-attr src=url alt=alt}} />
</div>
<div class='caption'>
<h3 class='name-me'>{{name}}</h3>
<p>{{description}}</p>
<div class='row no-gutter'>
<div class='col-xs-3'>
<button class='btn btn-primary'>Buy</button>
</div>
</div>
</div>
</li>
{{/each}}
</li>
</div>
</div>
But I seems after the point when afterRenderEvent() is triggered, all the elements in the {{#each}} block hasn't been rendered to the DOM yet, thus, the jQuery code return undefined
What's the right way to do it?
Your view's didInsertElement hook will fire as soon as the application route is rendered, which happens before the index route. You might think that putting it in the index.js file will work, but it's going to just extend the default application view behavior.
You need to create a more focused view that lives within your index.hbs file. One that is only concerned with your spinner jQuery doohickey. That, and an each/else conditional could work nicely here. For example:
{{#each}}
{{#view App.SpinnerDoohickeyView}}
<li class='col-md-4'>
<div class='thumbnail'>
<img {{bind-attr src=url alt=alt}} />
</div>
<div class='caption'>
<h3 class='name-me'>{{name}}</h3>
<p>{{description}}</p>
<div class='row no-gutter'>
<div class='col-xs-3'>
<button class='btn btn-primary'>Buy</button>
</div>
</div>
</div>
</li>
{{/view}}
{{else}}
<li>Empty collection!</li>
{{/each}}
Notice that I've wrapped each list item in its own view. You could wrap the whole ul if you wanted... this is just an example. The idea is that you are only creating views when you have a model.
And now you can define the view, and simply use the didInsertElement hook to work with jQuery:
App.SpinnerDoohickeyView = Ember.View.extend({
didInsertElement: function () {
this.$('li').css('background', 'blue');
}
});
If you have a model to render, jQuery should be able to safely access it this way. Good luck!
Here's some further reading and some code from the Ember folks that looks like what I've shown you here: http://emberjs.com/guides/views/handling-events/

How to pass a route to #link-to inside a component

I have a component that lists countries. It is used in several places, the only difference being the place where the link-to is pointing.
How is this best achieved? Are components the way to go?
{{country-list countries=model route="someroutehere"}}
in the component i have a simple #each
<ul class="nav nav-stacked"
{{#each countries}}
<li class="brd-b-g">{{#link-to routepassedtothecomponent this}}{{name}}{{/link-to}}</li>
{{/each}}
</ul>
You're on the right track. You just need to reference the property that you used to pass the route. Eg:
Template:
{{country-list countries=model myProperty="someroutehere"}}
Component:
<ul class="nav nav-stacked">
{{#each countries}}
<li class="brd-b-g">{{#link-to myProperty this}}{{name}}{{/link-to}}</li>
{{/each}}
</ul>
Working example.

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

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.