Ember-Component how to add border to only on `click` component? - ember.js

I would like to highlight the component on click event.( need to add a class name as addBorder) how to do that? while user clicks on other component, I would require to remove addBorder from other components.
so only the click componet will be highlighted at once.
I can do using jQuery very easily but I am looking for ember way!!
here is my demo: Live Demo Link

You can add property like selectedItemTitle which will be changed on click to item.title. Then you can pass this selectedItemTitle down to components. Component can check if its item.title === selectedItemTitle. If yes then property like isSelected can be set to true. Then you bind isSelected to a class using classNameBindings.
Parent component template:
{{#each model as |item|}}
{{my-child item=item.title info=item.info tagName="li" selectedItemTitle=selectedItemTitle click=(action 'selectItem' item.title)
}}
{{/each}}
See working demo.

Related

Render sidebar based on model in EmberJS

I started with learning EmberJS and maybe the answer is trivial, but after some researching, I still can't find a solution.
In my model template, I have some buttons(each for the different object) which after click should expand sidebar with its details.
What do I want to reach is something like this:
Could someone provide me with some simple twiddle?
There are two ways to achieve this effect.
Using controller's variable
{{#foreach model as |obj|}}
<button onclick={{action (mut activeModel) obj}}>{{obj.name}}</button>
{{/foreach}}
<!--Somewhere later in template-->
{{#if activeModel}}
<!--Code of overlay and sidebar, close button sets activeModel to undefined-->
{{/if}}
Using child (nested) route
Parent template:
{{#foreach model as |obj|}}
{{#link-to 'parentRoute.childRoute' obj tagName="button"}}
{{obj.name}}
{{/link-to}}
{{/foreach}}
<!--Somewhere later in template-->
{{outlet}}
Child template should contain code of overlay and sidebar, close button redirects back to parent route
well, one of the options is that you can create components and pass the modified model(modify the model using onclick function) as the data to that component.
for example,
let us just say that this is your main template
<button onclick="changeSideBar()">click</button>
<div style="display:none; //render it in the left-half(using bootstrap models)">
{{sidebar-component model=model.modified}}
</div>
in the javascript code (component.js),
function changeSideBar()
{
var modified= ;//set as per your convienince by iterating actual models or by any means
this.set('model.modified',modified);
//make display of sidebar div "block"
}
sidebar-component is your component. make the component as per your wish.
hope it helps.
I can't help much without your templates or codes. It would be great if you provide some of your works.

How to set specific view in emberJS with itemcontroller

I have the following code:
{{#each categories.items itemController="item"}}
When I open the Ember inspector, it shows the view to be "virtual". I want to set the view to be "item" so that it follows the ember view I set out called itemView. I know we can set an itemController: is it possible to set an item view?
Yes it is possible using the optional 'itemViewClass' parameter.
{{#each categories.items itemController="item" itemViewClass="otherView"}}
Though I would recommend discontinuing using that and itemController as the latest Best Practice is to use a component within the each block.
So for your example:
// Ember 1.10+
{{#each categories.items as |item|}}
{{some-component item=item}}
{{/each}}
// Ember 1.9-
{{#each item in categories.items}}
{{some-component item=item}}
{{/each}}
Then you put your logic needed in the component object instead of the item controller.

how to set an itemView for an itemController in Ember?

I have successfully implemented an ArrayController an defined an ItemController for it like this:
export default Ember.ArrayController.extend(InboxTab, {
itemController: 'messages.message-list-item'
});
then in the template for the array controller I just do
{{#each}}
<li {{action 'someActionFromItemController'}}>{{someComputedPropertyFromItemController}}</li>
{{/each}}
This works great and I can handle a lot of actions and computed for each item, but I'm running into difficulties associating a view to each item. The docs are not helpful. The only instance of itemView is in this article:
http://emberjs.com/api/classes/Ember.CollectionView.html#sts=Specifying itemViewClass
and here the example seems to revolve around adding the view to the template and specifying the content from there and I'm not sure how that applies to the way I'm doing it.
A different way you could do it:
{{#each itemController='messages.message-list-item'}}
{{#view your-view}}
{{action}}{{computed property from view/controller}}
{{/view}}
{{/each}}
specify the item controller in the loop and wrap the actions and properties in the view - which means either of these could also be called or set in the view.
I think way to do this best is with itemViewClass, see the api for the full details.
{{#each message itemController='messageListItem' itemViewClass='messageListItem'}}
{{! Assumes you have view defined in an App.MessageListItemView defined in your JavaScript}}
{{action}}
{{/each}}

Ember.checkbox nested in action doesn't change value

Template:
{{#each document in documents}}
<div class="col-md-6" {{action "selectDocument" document}}>{{view Ember.Checkbox checked=document.isSelected}} {{document.name}}</div>
{{/each}}
Controller:
App.IndexDocumentsController = Ember.ArrayController.extend({
actions: {
selectDocument: function(document){
document.set('isSelected', !document.get('isSelected'));
}
}
});
When I click on the div, the checkbox toggles 'checked' property. But when I click on the ckeckbox - nothing happens. What can be the reason?
UPDATED
Link to jsbin: http://emberjs.jsbin.com/nuvocumuteto/1/edit?html,css,js,output
The issue is that when you click on the checkbox 2 things happen.
the checkbox toggles the isActive property, then
the selectRow action is ran which again toggles the isActive property
So the isActive property ends up staying in the same state that it was.
In your case I would get rid of the action, wrap the checkbox in a <label> and set the label to display: block.
The template would look like
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each item in model}}
<li {{bind-attr class="item.isActive:active"}}><label>{{input type="checkbox" checked=item.isActive}}{{item.name}}</label></li>
{{/each}}
</ul>
</script>
and the css would look like
label {
display: block;
}
you would then be able to get rid of the selectRow action completely because clicking on the label will trigger the checkbox.
You can see a working bin here: http://emberjs.jsbin.com/nuvocumuteto/3/edit
I would argue that you are not following "The Ember Way" in two different ways here.
First, Ember.Checkbox is an internal Ember class (http://emberjs.com/api/classes/Ember.Checkbox.html). The recommended way to render a checkbox is to use the Handlebars input helpers (http://emberjs.com/guides/templates/input-helpers/#toc_checkboxes). This is just wrapping Ember.Checkbox anyway.
Second, if you want to update the value of isSelected, the "Ember Way" is to use two-way data bindings. Your code uses one-way data-binding when it reads document.isSelected and then tries to manually re-create the the data-binding in the other direction when the user clicks by manually writing a selectDocument action and calling it from an {{action}}.
Instead, simply bind the Ember Handlebars Input Helper directly to your value like this:
{{#each document in documents}}
<div class="col-md-6">{{input type="checkbox" checked=document.isSelected}} {{document.name}}</div>
{{/each}}

View click action not returning correct object

I'm having trouble with a click handler in a view. It's not returning the expected member of the collection, but the collection as a whole.
I've created a jsfiddle to demonstrate the issue. I have an ArrayController, whose content I pre-populate. The view for this controller then uses the #each helper for the controller with another view:
{{#each controller}}
{{view App.ActivityListItemView}}
{{/each}}
This works, in that I see the name of the item on the page, and can click it.
The problem is in the click handler - if I #get('content'), the content for the parent controller is returned. How do I get the item that was clicked on? If you have a look at the console output in the jsfiddle you'll see the issue. I assume this is a context issue?
I've tried adding contentBinding="this" to the view:
{{#each controller}}
{{view App.ActivityListItemView contentBinding="this"}}
{{/each}}
but that makes no difference.
thanks,
Martin
How do I get the item that was clicked on? If you have a look at the console output in the jsfiddle you'll see the issue. I assume this is a context issue?
Exactly. You want the view's context instead of it's controller's content. So:
click: (data)->
console.log 'clicked on an activity'
selected = #get('context')
#get('controller').set('selectedActivity', selected)
console.log(#get('controller').get('selectedActivity.name'))
Why?
By default the {{#each}} helper does not create a new controller instance for items in the array. So when you#get('controller')` from the view helper it searches up the view heirarchy until a controller is found - in this case that is the array controller.
If you want to have a separate controller for each item you could provide an itemController attribute to the each helper - see http://emberjs.com/api/classes/Ember.Handlebars.helpers.html#method_each
Right, I've got this working, I think the issue sprang for a lack of understanding of the contentBinding argument. Basically I've changed to using a specific name of 'activityBinding' within the #each block, and then referring explicitly to the activity in the click handler. See jsfiddle for a working demo.
{{#each controller}}
{{view App.ActivityListItemView activityBinding="this"}}
{{/each}}
and
click: ->
console.log 'clicked on an activity'
console.log #get('activity.name')
content = #get('activity')
#get('controller').set('selectedActivity', content)