Ember.js: yield specific object in layouts - ember.js

I would like to create a layout in which I iterate over a collection with #each and then pass that object to yield. Is that possible?
What I would like achieve is:
<!-- timeline_layout.hbs -->
<div id="timeline-container">
{{#each entry in controller}}
<div class='timeline-entry'>
{{yield entry}}
</div>
{{/each}}
</div>
<!-- timeline_instance.hbs (timeline with posts) -->
{{#view App.Timeline}} <!-- has layout set to timeline_layout -->
{{render 'post' entry}}
{{/view}}
If guess that is not possible, right? Since render 'post' can't know about the entry. So what is the ember way to encapsulate the general html structure of the timeline?

"A template used as a layout must contain a single use of the Handlebars {{yield}} helper. " ember.js views. Your approach essentially breaks this rule, as you're trying to create a new yield for each entry in your controller- you should look at refactoring your each into the template.

Related

Ember passing multiple list items in template

Is it possible to pass multiple list of items in template using {{each}}
Can someone guide me on what I am doing,
in my sales-orders.hbs below is my currenet code.
{{#each model as |detail|}}
<li>{{sales-orders-grid detail=detail}}</li>
{{else}}
Blank
{{/each}}
</ul>
Then calling the sales-orders-grid component
Shipping Method
<div class="col-xs-12 col-md-12 col-sm-12 products-item-products border-left padding10">
<ul>
{{#each shippingMethod as |sm|}}
{{sales-orders-grid-shipping-method sm=sm}}
{{/each}}
</ul>
</div>
In my sales-orders-grid-shipping-method component calling is this:
sm.shippingMethodName
What I'm trying to achieve here is to pass list of items in {{each}} in my main template. Is it possible?
To change scope you can use the "with" helper.
http://emberjs.com/api/classes/Ember.Templates.helpers.html#method_with
{{#with user.posts as |blogPosts|}}
<div class="notice">
There are {{blogPosts.length}} blog posts written by {{user.name}}.
</div>
{{#each blogPosts as |post|}}
<li>{{post.title}}</li>
{{/each}}
{{/with}}
I think you can nest multiple "with" helper.
I think the way to go is to restructure your data as:model.list1,model.list2,etc.
Then pass the model and use as necessary.And use nested each to acheive the grid.
Iam only posting this as an answer because I can't comment yet.
So, do get back to me for Clarifications.

Ember.js nested views get very slow

I have a two-level deep data model that I want to display with Ember.js as nested lists. If I do the simple version it performs quite well:
{{#each parent in content}}
<p>Table {{parent.id}}</p>
<ul>
{{#each item in parent.children}}
<ul>
<li>{{item.position}}</li>
<li>{{item.position}}</li>
<li>{{item.position}}</li>
</ul>
{{/each}}
</ul>
{{/each}}
http://jsfiddle.net/krumpi/TdZJG/
However if instead of displaying the model's properties as raw strings I use nested Ember.Select and Ember.TextArea views the performance suffers a lot, it takes quite a bit after the load button is pressed to display the controls in the page:
{{#each parent in content}}
<ul>
{{#each item in parent.children}}
<ul>
<li>pos: {{item.position}}</li>
<li>
{{view Ember.Select
class="input-small"
contentBinding="App.CheckValues"
selectionBinding="item.status"}}
</li>
<li>{{view Ember.TextArea class="textarea-animated" name="description" valueBinding="item.comment"}}</li>
</ul>
{{/each}}
</ul>
{{/each}}
http://jsfiddle.net/krumpi/wtwHN/
Would you have any suggestion on how to improve performance. This is done with ember-1.0.0-pre4
Instead of using Ember select and textarea views use normal html tags for them and bind only the attributes. Those views usually occupy more memory and writing them inside a nested structure will expectedly make your code run slow.

Ember.js: Passing model into view

I have a controller with data about user accounts (icon, name, provider, etc.). Within the output of the each loop I have a view that will build a CSS class dynamically based on the provider passed in via that specific model.
<script type="text/x-handlebars" data-template-name="accountItem">
{{#each account in controller}}
{{#view App.AccountView}}
<h4>{{account.name}}</h3>
<img {{bindAttr src="account.icon"}} />
<i {{bindAttr class="account.provider"}}></i>
{{/view}}
{{/each}}
</script>
App.AccountView = Ember.View.extend({
tagName: 'a',
classNames: ['avatar-image'],
providerClass: function(el) {
// do something
}
});
The question I have is two-fold.
How do you pass in "account", or the currently iterated item, into the view?
After you pass it in, how do you reference it?
I'm sure this is something that happens quite often but I can't seem to find any examples. Can anyone offer some input on this please?
Views has a special content property in a view which allows a more simple approach: you just use a name of the model's property without the view.content. part.
Also, when you're iterating over controller, you can omit the name of loop variable and use this instead, like in this guide. This is not necessary but can make the code a bit cleaner.
Also, from within view's template you generally don't need to reference the outside variables although you can if you like..
{{#each controller}}
{{#view App.IndexView contentBinding="this"}}
<h4>{{name}}</h4>
<img {{bindAttr src="icon"}} />
<i {{bindAttr class="provider"}}></i>
<i> {{icon}} </i>
<i>{{provider}}</i>
{{/view}}
{{/each}}
And you can always access the content property from within the view with:
this.get('content');
The currently iterated item can be passed into the view with the help of property bindings and it can be refered as "{{view.property}}" in the template. For example:
{{#each account in controller}}
{{#view App.IndexView itemBinding="account"}}
<h4>{{view.item.name}}</h3>
<img {{bindAttr src="account.icon"}} />
<i {{bindAttr class="account.provider"}}></i>
<i> {{view.item.icon}} </i>
<i>{{view.item.provider}}</i>
{{/view}}
{{/each}}
I have created a simple jsfiddle for the above case. Do check it and let me know if you were able to resolve the issues.
Fiddle url : http://jsfiddle.net/nCyn6/3/

Ember.js and handlebars each helper, with subviews

I'm triyng to use the view helper inside my {{#each}} template blocks without using global paths (my controllers create and destroy their own views).
Examples. Given a view with a myList array property, and an itemButton child view:
This will work
<script type="text/x-handlebars" name="my-list-view">
{{#each myList}} <!-- App.myListView.myList -->
{{view App.myListView.itemButton}} {{title}}
{{/each}}
</script>
This will not:
<script type="text/x-handlebars" name="my-list-view">
{{itemButton}} <!-- works fine outside the each -->
{{#each myList}}
{{view itemButton}} {{title}} <!-- itemButton view not found -->
{{/each}}
</script>
I do not appear to be able to access the parent view from the each view helper (or in fact access anything other than the properties of the objects being iterated).
The hacky workarounds I've come up with are:
Add the view I want to use to the items I'm iterating over.
or
Creating a collectionView in App.myListView
Create an itemViewClass view in that collection view class
Move the itemButton view inside the itemViewClass
Replace {{#each}} with {{#collection}}
or
Create a custom handlebars helper for iteration.
Both of these options seem horrible.
Surely there's a better alternative than creating 2 new classes (and nesting 4 views deep) just to iterate over a list, though. Is there a replacement handlebars helper I can use instead?
Workaround implementations
Option #1 : Modifing the content array
http://jsfiddle.net/FQEZq/3/
Disadvantages: Having to add the view to each model instance just for iteration.
Option #2 : Custom collection view
http://jsfiddle.net/ST24Y/1/
Disadvantages: Now you have two additional views that you do not need / want, and less control of markup. References from the child view to the parent instance now requires parentView.parentView.parentView.
#each is too limited for your requirements. You can make it work if you're willing to use a global path to the view you want to nest within the #each. Otherwise, your collection view approach is best. Adding the view to the model instance is likely to muddy your app design something fierce, so I would avoid that.
One idea to keep your templates clean is to take advantage of Ember.View properties like:
collectionView - Return the nearest ancestor that is an Ember.CollectionView
itemView - Return the nearest ancestor that is a direct child of an Ember.CollectionView
contentView - Return the nearest ancestor that has the property content.
The big thing here - options.
Hooks for how you wish to use a template are available. These are:
<-- render templates/name.js -->
{{partial 'name'}}
<-- render views/name.js -->
{{view 'name'}}
<-- render views/name1.js with controllers/name2.js -->
{{render 'name1' 'name2'}}
<!-- see also: -->
{{output}}
{{output 'named'}}
{{yield}}
An example variant of your initial template showing 4 different options:
<script type='text/x-handlebars' data-template-name='my-list-view'>
<h2>Option 1</h2>
{{#each myList}}
{{! the 2nd parameter will look for itemButtonController }}
{{render 'itembutton' itemButton}}
{{/each}}
<h2>Option 2</h2>
{{#each myList}}
{{! using an Ember Component }}
{{#item-button }}
some static text OR {{dynamic}}
{{/item-button}}
<!-- in component/item-button.hbs add {{yield}} for where you want the static content to output -->
{{/each}}
<h2>Option 3</h2>
{{#each myList}}
{{! if the button is to be a link }}
{{#link-to 'route' parameter tagName='button' classNames='btn'}}
{{title}}
{{/link-to}}
{{/each}}
<h2>Option 4</h2>
<p>Ludicrous example showing almost every reference option!</p>
{{! focus the context on subview data }}
{{#with someArrayOrCollectionOfView}}
{{! prepend type to add context - here returning back up to this view's properties }}
{{#each view.myList}}
{{! this is equivalent to someArrayOrCollectionOfView[x].name }}
{{name}}
{{! a button that hooks in route, model, and 2 controllers, and applies a target for the output when clicked }}
{{#link-to 'page' controllers.page.nextPage target='outlet' tagName='button' disabledWhen=controller.disableNext }}
{{model.buttonName}}
{{/link-to}}
{{/each}}
{{/with}}
{{! generic default target (automatic) }}
{{outlet}}
{{! example of a named target }}
{{outlet 'footerlinks'}}
</script>
Mmmm... reference for further reading:
Ember.Handlebars.helpers

Ember.js binding a css style in a template

This is solved since Ember 1.8 with the HTMLBars engine.
I would like to bind a css style in a template. What would be the
solution ?
I tried this:
<div class="bar" style="width:{{barWidth}}px"></div>
but DOM element look like this after its been rendered:
<div class="bar" style="width:<script id='metamorph-28-start' type='text/x-placeholder'></script>5.000000000000002<script
id='metamorph-28-end' type='text/x-placeholder'>px">
Obviously here we can see that the tag for metamorph was
added within the style attribute...
I'm wondering what is the best way to achieve such things with
Ember.js
There is something i don't get yet.
I have a template as follow:
<script type="text/x-handlebars" data-template-name="listTemplate">
<ul id="list">
{{#each App.list}}
<li {{bindAttr data-item-id="itemId"}}>
<div>
<span class="label">{{itemName}}</span>
<div class="barContainer">
<div class="bar" {{bindAttr style="barWidth"}}></div>
<div class="barCap"></div>
</div>
</div>
</li>
{{/each}}
</ul>
i'm in a for each loop that loops thru my ArrayProxy content... and the bar width vary depending of the value of each item in the list. Your solution here will not work as the view is the UL and i need a barWidth per model item. and I do not want to polute my Model with css related things like "width: ###px"
Is there any other elegant way to solve what i try to do ? maybe it would be radically different. I'm very new to ember.js and try to discover the best-practices yet:)
Set a string on your view that looks like "width: 100px" and then bind it to your div with the bind-attr helper like so: <div {{bind-attr style="divStyle"}}>Test</div>
http://jsfiddle.net/tomwhatmore/rearT/1/
To simplify all that, I created a tiny handlebars helper for emberjs that allows you to bind any style properties. You can look at https://github.com/yderidde/bindstyle-ember-helper
Add unbound:
<div class="bar" style="width:{{unbound barWidth}}px"></div>
In Ember 2.0:
<div class="bar" style="width:{{barWidth}}px"></div>
will just work.