Reputation: 41
I am working on chat app. I have template of component - rooms
<div class='border rooms'>
<button class="add-room-container">
<div >Add room</div>
</button>
{{#each model as |room|}}
<button class="room-container"
{{action "onRoomClicked" room.id}}
{{bind-attr class="currentRoomId===room.id:currentRoom"}}>
<div class="deleteRoom" {{action "deleteRoom" room.id bubbles=false}}>
X
</div>
<div>{{room.name}}</div>
<div>{{room.createdAt}}</div>
</button>
{{/each}}
</div>
and component js file import Ember from 'ember';
export default Ember.Component.extend({
actions: {
onRoomClicked(roomId) {
this.set('currentRoomId', roomId);
},
deleteRoom(room) {
console.log('room removed');
}
} });
and I have problem with the line
{{bind-attr class="currentRoomId===room.id:currentRoom"}}
I would like to check if current button is the last which was clicked (it is set in onRoomClicked) and if it is then add currentRoom class to button
I was trying to set dynamic property but I don't know how can I access current model (room) id from component and then compare it like I do in template
Upvotes: 0
Views: 624
Reputation: 18240
You have many different ways to do this. But first the question is a bit what ember version you are using. In current ember versions bind-attr
should not be used anymore!
So first I assume you call your component like this:
{{my-component model=rooms}}
I would strongly recommend to not call your data model
! Give them a speaking name. Do something like rooms=rooms
!
So now you are in your component. What you probably figured out is that the problem is your {{#each}}
loop, which results in a situation that you have no .js
file for the context inside the {{#each}}
loop.
The maybe best way to work around is to use a second component, which you call inside your each loop:
{{#each model as |room|}}
{{room-line room=room currentRoomId=currentRoomId}}
{{/each}}
Then you can place your {{#each}}
body inside your room-line.hbs
:
<button class={{if isCurrentRoom "currentRoom"}}>
....
And you have a backing room-line.js
where you can calculate the isCurrentRoom
:
isCurrentRoom: Ember.computed('currentRoomId', 'room.id', {
get() {
return get(this, 'currentRoomId')===get(this, 'room.id');
}
})
Another way to handle this is to inject a isCurrentRoom
into your room
. This can be done with .map()
, or with an ArrayProxy
and/or ObjectProxy
.
Something like this in your components .js
file:
calculatedRooms: Ember.computed('[email protected]', 'currentRoomId', {
get() {
return get(this, 'rooms').map(room => ({
room,
isCurrentRoom:get(room, 'id') === get(this, 'currentRoomId')
}));
}
}),
Then you can just use it in your {{#each}}
helper:
{{#each calculatedRooms as |line|}}
<button class="room-container {{if line.isCurrentRoom 'currentRoom'}}"
{{action "onRoomClicked" line.room.id}}>
...
{{/each}}
The third approach is to use a custom helper for this. This is maybe the easiest way to do it, but maybe also the ugliest, because you put logic in your templates.
A simple is-equal
helper can help you:
export function isEqual(a, b) {
return a === b;
}
export default Ember.Helper.helper(=);
Then you can just use it in your template:
{{#each calculatedRooms as |room|}}
<button class="room-container {{if (is-equal currentRoomId room.id) 'currentRoom'}}"
{{action "onRoomClicked" room.id}}>
...
{{/each}}
If you choose this approch you can use ember-truth-helper which provides that helper, but you can also just write it yourself.
I would strongly recommend the first approach, its the far most elegant way to handle this.
Upvotes: 3
Reputation: 368
The easiest way to do this is using ember-truth-helpers, which gives you the incredibly useful eq
helper in templates. Then you can write:
{{#each model as |room|}}
<button
class="room-container {{if (eq room.id currentRoomId) "currentRoom"}}"
{{action "onRoomClicked" room.id}}>
</button>
{{/each}}
This is using an embedded if
helper in your class attribute instead of bind-attr
(which is deprecated and you should avoid).
Upvotes: 0