How to make a conditional link-to in Ember.js? - ember.js

I am using Ember.js version 2.8.2.
I want to wrap things inside link-to only if condition is true.
First try:
{{#if isAdmin}}
{{#link-to admin}}
contents here
{{/link-to}}
{{else}}
contents here
{{/if}}
Problem: the code is not dry, because content repeats twice.
How should I do this? Thanks.

First option:
If you want to remove it from your dom, wrap your "link-to" component as a component (my-admin-link.hbs):
{{#if isAdmin}}
{{#link-to admin}}
{{yield}}
{{/link-to}}
{{else}}
{{yield}}
{{/if}}
Than use it as:
{{#my-admin-link}}
your content
{{/my-admin-link}}
Second option:
Use disabled and disabledClass of link-to:
{{#link-to admin disabled=isNotAdmin disabledClass='showastext'}}
your content
{{/link-to}}
In your app.css showastext can be defined as:
.showastext{
text-decoration: none;
cursor: text;
color: black;
}

Related

In a handlebars template, get the Ember controller from an each loop

I have an each loop that looks something like this:
{{#each controller}}
{{#link-to 'searches.show' this}}
<span>{{name}}</span>
{{/link-to}}
{{/each}}
At the moment, the this in {{#link-to 'searches.show' this}} seems to refer to the content of the controller, rather than to the controller itself. Is there a way to pass in the controller here, rather than its model?
{{#each}}
{{#link-to 'searches.show' controller}}
<span>{{name}}</span>
{{/link-to}}
{{/each}}
This will work fine.

Ember markup breaks bootstrap CSS

I am generating a button group with a template:
<div class="btn-group">
{{#if allowNew}}
{{#link-to newRoute type="button" class="btn btn-primary"}}<i class="fa fa-plus"></i> {{t generic.add}} {{capitalize singularHuman}}{{/link-to}}
{{/if}}
{{#if allowDeleteAll}}
<button type="button" {{action "destroyAllRecords"}} class="btn btn-danger"><i class="fa fa-trash-o fa-lg"></i> {{t generic.delete_all}} {{capitalize pluralHuman}}</button>
{{/if}}
</div>
Ember is placing <script> nodes inside the button group, I imagine to handle binding, view updates or whatever.
The problem is that bootstrap is relying on CSS rules like
.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle)
to finetune the styles. Since the <script> tag is placed before the first <button> or <a> tag, and after the last one, those CSS rules are getting applied where they should not, and instead of having something like this:
I get something like this:
As you can see the stock bootstrap style has rounded corners for the first and last button (the external corners), but my implementation has no such rounded corners.
Is it possible to somehow overcome this problem?
Use an ember view. See https://coderwall.com/p/f1npbg
App.MyView = Ember.CollectionView.extend({
classNames: ['btn-group'],
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile("{{view.content.name}}"),
tagName: 'button',
classNames: ['btn']
}),
attributeBindings: ['data-toggle'],
'data-toggle': 'buttons-radio'
});

View inside each with itemController

I've created view App.TestView which works fine outside following each loop. The code is displaying properly test loop_element.
App.TestView = Ember.View.extend({});
{{#view App.TestView}}
test
{{/view}}
{{#each controller.positions itemController='url'}}
loop_element
{{/each}}
On the other hand, when I put child view inside each loop
{{#each controller.positions itemController='url'}}
loop_element
{{#view App.TestView}}
test
{{/view}}
{{/each}}
is not displaying anything. There isn't any error message. What can be wrong? Why can't I use views inside loop?
It looks like it's working to me. Are you sure you're looping the same thing? You wrote two different items that you were iterating. controller.positions is probably empty
App.TestView = Em.View.extend({
});
App.UrlController = Em.ObjectController.extend({
});
<script type="text/x-handlebars" data-template-name="index">
{{#each controller.positions itemController='url'}}
loop_element
{{#view App.TestView}}
test2
{{/view}}
{{/each}}
</script>
http://emberjs.jsbin.com/bapugowi/1/edit
The thing was that the loop was inside <tbody> tag. View was rendered in other tag than <tr> and it was breaking my web browser.

inline / inplace editing for different form inputs in Ember

Views in the app we're developing are already written in Handlebars / Emblem and data is already taken from models.
I'm trying to figure out what's the best approach for inline / inplace in Ember. Problem: when nothing is clicked, the data is just a text. When you click the text depending on its type (date, plain text, list of items) the corresponding input field (date field, text field or select) is replaced and you can edit it.
Have you had experience with this issue? If so, please share your thoughts!
Here is one solution using an Ember.Component:
App.InlineEditComponent = Ember.Component.extend({
actions: {
toggleEditing: function() {
this.toggleProperty('isEditing');
}
}
});
With the template:
<script type="text/x-handlebars" id="components/inline-edit">
{{#if isEditing}}
<form {{action "toggleEditing" on="submit"}}>
{{yield}}
</form>
{{else}}
<span {{action "toggleEditing"}}>
{{value}}
</span>
{{/if}}
</script>
Usage:
<script type="text/x-handlebars" data-template-name="index">
{{#inline-edit value=someProperty}}
{{input value=someProperty type="date"}}
{{/inline-edit}}
</script>
Demo: http://emberjs.jsbin.com/OGEnOdA/2/edit
You can add more features (for example, end editing on focus-out the form element, etc.) but I think you get the basic idea.

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/