Specifying which properties to use in a custom drop-down Ember component - ember.js

I've created a reusable drop-down component in Ember:
/app/components/dropdown/component.js
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'select',
classNames: ['form-control'],
placeholder: null,
items: null,
selected: null,
change: function(event) {
var items = this.get('items');
var index = event.target.selectedIndex;
var selected = items ? items[index - 1] : null;
this.sendAction('selectedChanged', selected);
}
});
/app/components/dropdown/template.js
{{#if placeholder}}
<option value="">{{placeholder}}</option>
{{/if}}
{{#each items as | item |}}
<option value="{{item.id}}" selected={{is-equal item selected}}>{{item.name}}</option>
{{/each}}
The component currently uses the 'name' property as the label for the option. However, I want the ability to specify what property to use, in order to make the component more flexible (so that I can sometimes use, for example, 'displayName').
With the old Ember Select component, you could do the following:
{{view "select"
content=programmers
optionValuePath="content.id"
optionLabelPath="content.firstName"
value=currentProgrammer.id
}}
...and tell it which properties to use for both the value and label. I'd like to do something similar, but I'm not sure how. (I tried reading through the source but it was a bit beyond me). Thanks in advance.

<option value="{{ember-get item optionValuePath}}" selected={{is-equal item selected}}>{{ember-get item optionLabelPath}}</option>
You will need to implement the ember-get helper, in Ember 2.0 there is a default heper called get which will make the following redundant.
import Ember from 'ember';
export function emberGet(params/*, hash*/) {
return Ember.get(params[0], params[1]);
}
export default Ember.HTMLBars.makeBoundHelper(emberGet);
Also take a look at this jsbin which has an example of what you are trying to achieve.

Related

How to remove class from other elements in emberjs

my functions toggles the class name on click to an element. But It's not remove the class names from other elements. so all elements are highliting now. But whenever user click on an element, it should have the classname rest of siblings has to removed the classname how do do this?
here is my try but not works:
import Ember from 'ember';
export default Ember.Component.extend({
isSelected : false,
deSelectOthers : function(){
this.set( "isSelected", false ); //deselecting all before add the class to clicked element
},
actions : {
selectCard : function(card) {
this.deSelectOthers(); //de select others not works
this.toggleProperty('isSelected'); // add class to this element only works. how to remove class from other element?
}
}
});
UPDATE
I am sorry for bad description about my requirement. I have created the requirement using jQuery - simply how to achive the same with emberjs?
Demo-Requirement
Here is the working twiddle
You need to maintain selectedIndex/value and use if check to update class based on the selectedIndex/value.
application.hbs
<div class="parent">
<ul>
{{#each model as | temp index|}}
<li class={{if (eq selectedIndex index) 'highlight' }} {{action 'changeSelectedIndex' index}}>{{temp}}</li>
{{/each}}
</ul>
</div>
routes/application.js
import Ember from 'ember';
export default Ember.Route.extend({
model(){
return [1,2,3,4];
}
});
controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
selectedIndex:undefined,
actions:{
changeSelectedIndex(index){
this.set('selectedIndex',index);
}
}
});
You need to install ember-truth-helpers addon by running ember install ember-truth-helpers

Ember model and route setup

Trying to learn Ember with a simple app, which is just a questionnaire. On the first page of the questionnaire (localhost:4200/animal) they choose their favourite animal from a select box (which is a component I made, that I would like to re-use on other questions). The select box is populated via a RESTful API.
//routes/animal.js
import Ember from 'ember';
export default Ember.Route.extend({
model(){
return this.get('store').findAll('animal');
}
});
//models/animal.js
export default Model.extend({
name: attr()
});
//templates/animal.hbs
Choose your favourite animal:
{{select-box
items=model
selectedValue=???
}}
{{#link-to "xyz"}}Go to next question{{/link-to}}
//components/select-box/template.hbs
<select {{action 'actionOnChange' on 'change'}} class='{{class}}'>
{{#each items as |item|}}
<option value='{{item.id}}' selected={{eq item.id selectedValue}}>{{item.name}}</option>
{{/each}}
</select>
//components/select-box/component.js
import Ember from 'ember';
export default Ember.Component.extend({
selectedValue: '',
//when load the page, prepopulate the value
init(){
this._super(...arguments);
//retrieve it from somewhere?
//this.get('selectedValue') is blank if come back to the page
},
actions: {
actionOnChange(){
//save it somewhere? where?
this.set('selectedValue', this.$('select').val());
}
}
});
If I choose an animal, then go onto the next page of the questionnaire, and then come back to the /animal page again, their selection is lost. How do I retain the value that they chose?
All the examples I have looked at show the value being saved in the animal model, but in Ember Inspector on the 'Data' tab for 'animal', it shows all 5 different animals retrieved from the API call. Should I have a second model?
Any help is appreciated.

Emberjs "eq" in component

Got a component that works just fine as follows (selectedId is definitely set):
export default Ember.Component.extend({
store: Ember.inject.service(),
items: [],
selectedId: 0,
result: '',
init () {
this._super(...arguments);
var store = this.get('store');
let items = store.findAll('dealtype');
this.set('items', items);
},
didInsertElement: function() {
// this.$().select2();
}
});
This render my component fine, but the part it never goes to true for the if statement (installed ember-truth-helpers for that)
<select style="width:100%">
<option value=""></option>
{{#each items as |item|}}
{{#if (eq selectedId item.id)}}
<option selected="selected" value="{{item.id}}">{{item.name}} YEAH</option>
{{else}}
<option value="{{item.id}}"> {{item.name}} </option>
{{/if}}
{{/each}}
</select>
Don't want to mix problems, but as you see i commented out the select2 init call. When doing that it make my select a select2 list, but the items are gone (thought still in the markup)
I would definitely recommend that you use Ember Power select component since they have solved everything you need for Select component
http://www.ember-power-select.com/
They have two component for single select entry and multiple. There is a good documentation and great support for ember cli projects
https://github.com/cibernox/ember-power-select
As for your problem I would try this - I have not tested itbut form top of my head this should solve your issue:
import Ember from 'ember';
export default Ember.Component.extend({
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent : function(){
var component = this;
Ember.run.later((function() {
Ember.$('select').select2({
minimumInputLength: 2,
delay: 250}).on('select2-open', function() {}
})
});
So what you need to use is aaferRenderEvent and run later to init your select 2 component. Please check aboe the code if all {} are properly closed. But this will get your select2 working insdie ember project.
Hope it helps.

Filtering an array in ember

Ok so I'm fairly new to programing, I know how to run a filter on a JSON Array but I cant seem to figure it out when I'm pulling the data from firebase and viewing it in an Ember app.
this is my route.js code:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('user');
}
});
This is my template.hbs code the href="#!" is the generic from materialize for the dropdown buttons:
<div class="list-wrapper col-xs-10 col-xs-offset-1">
<div class="col-xs-12 button-div">
{{#md-btn-dropdown text='Filter' class="col-xs-2" belowOrigin=true}}
<li>Female</li>
<li>Male</li>
<li>All</li>
{{/md-btn-dropdown}}
</div>
{{#each model as |info|}}
<div class="col-xs-3 user-card">
<div class="card-info">
<ul>
<li>Last Name- {{info.lastName}}</li>
<li>First Name- {{info.firstName}}</li>
<li>Gender- {{info.gender}}</li>
<li>{{info.email}} </li>
</ul>
</div>
</div>
{{/each}}
</div>
{{outlet}}
This is my controller.js code which I no is all wrong:
import Ember from 'ember';
export default Ember.Controller.extend({
customFilter: function(gender) {
return function(el) {
var r = el.user;
return r.gender === gender;
};
}
});
and this is my model:
import DS from 'ember-data';
import Ember from 'ember';
export default DS.Model.extend({
lastName: DS.attr('string'),
firstName: DS.attr('string'),
gender: DS.attr('string'),
email: DS.attr('string')
});
I've searched high and low and I'm sure I'm just missing something basic and stupid. What I want is for the dropdown menu to be able to filter and display only female, male or all. Again I'm new to this stuff so I apologize if this is a pretty basic thing. Thank You
What your missing is an action that updates your controller when an item in the dropdown is actually selected.
Some helpful reading:
Triggering changes with actions
Computed Properties
Here's how to put actions in your dropdown component
{{#md-btn-dropdown text='Filter' class="col-xs-2" belowOrigin=true}}
<li><a {{action "filterUpdated" "female"}}>Female</a></li>
<li><a {{action "filterUpdated" "male"}}>Male</a></li>
<li><a {{action "filterUpdated"}}>All</a></li>
{{/md-btn-dropdown}}
In your controller you then need to handle this action like so:
import Ember from 'ember';
export default Ember.Controller.extend({
// the people property is an alias of the model object
// which essentially makes people a synonym for model
// read more http://emberjs.com/api/classes/Ember.computed.html#method_alias
people: Ember.computed.alias('model'),
// holds the currently selected gender, e.g., "female". A null value indicates there is no filter.
currentFilter: null,
/*
filteredPeople is a computed array containing people models.
The array is recomputed every time the model changes or the currentFilter changes,
see the .property() bit at the end.
read more: http://emberjs.com/api/classes/Ember.computed.html#method_filter
*/
filteredPeople: Ember.computed.filter('people', function(person/*, index, array*/) {
// this function is passed each item in the model array, i.e., the person argument
// there's no need to use the index nor array arguments, so I've commented them out
if(this.get('currentFilter') === null) {
// when the filter is null, we don't filter any items from the array
return true;
} else {
// otherwise only return true if the gender matches the current filter
return person.gender === this.get('currentFilter');
}
}).property('people', 'currentFilter'),
actions: {
filterUpdated: function (value) {
if (Ember.isEmpty(value)) {
// an empty value means we should clear the filter
this.set('currentFilter', null);
}
else {
this.set('currentFilter', value);
}
}
}
});
Finally, edit your template to change
{{#each model as |info|}}
to
{{#each filteredPeople as |info|}}
Also at a meta level, don't apologize for asking questions! Everyone is new at something at somepoint, and often asking is the best way to learn. That's what stackoverflow is all about :)
Something like this would work:
gender: 'All',
filteredModel: Ember.computed.filter('model', function(person) {
return person.gender === this.get('gender');
}).property('gender'),
this assumes that it starts on all, and then when the dropdown changes the value of gender, then the filteredModel will get updated. You can then in your hbs file change the result to:
{{#each filteredModel as |info|}}

Set default (selected) option Ember 1.13.11

Sort version:
Why does this work: <option disabled={{option.isSelected}}>
But not this: <option selected={{option.isSelected}}>
Long version:
This is more about me learning how Ember works than about getting this working, since there are lots of working examples for this already.
I'm trying to set the default selected option in a select menu. It looks like there are different ways of doing this and that the recommended method is changing.
I'm working in Ember 1.13.11 but want to be Ember 2.0 compatible.
I haven't found a Ember 2.0 compatible method that didn't involve a template helper for the selected attribute. I can create a true/false value as a property on the controller. I know I'm doing it right because disabled works properly. Why does this fail only for select?
Template call:
{{version-details item=version status=version.status}}
Component controller:
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'select',
options: Ember.computed('status', function() {
var statusOptions = ['beta', 'current', 'future', 'retired-beta', 'retired', 'unknown'];
var selected = this.get('status');
var optionsData = [];
statusOptions.forEach( function(status){
var isSelected = (selected == status);
optionsData.push({ status: status, isSelected: isSelected });
})
return optionsData;
}),
setAction: '',
});
Component:
{{#each options as |option|}}
<option selected={{option.isSelected}}>{{option.status}}</option>
{{/each}}
As #blessenm points out. It does work.
I think couldn't tell it was working because the browser was remembering and selecting the value from the last time I visited the page.