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.
Related
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.
I have created the dropdown of country name and set country code as a value for each option .I want to set the default country name and also listen the selection change of the dropdown .I have tried the following code
HTML
<select class="left-float" onchange={{action selectionchange}} >
{{#each model.countries as |country|}}
<option value="{{country.code}}" selected={{eq country.code "IN"}} >{{country.name}}</option>
{{/each}}
</select>
Router
App.SignupRoute = Ember.Route.extend({
model: function () {
return Ember.RSVP.hash({
countries: Countries
});
},
actions:{
selectionchange:function(value){
}
}
});
Could please help me to resolve this
#Sindhu,
Another simple solution would be to create a custom helper eq. The custom helper would look like:
import Ember from 'ember';
export function eq(params) {
return params[0] === params[1];
}
export default Ember.Helper.helper(eq);
Working example: https://ember-twiddle.com/d4aaf5790e40b20ce492. You can change the emberjs version by clicking Dependencies -> Ember.js -> version. The code works with v2.0.2.
Let me know if this solution works for you.
Here is how you can implement the selectionChange:
HBS:
<select class="left-float" onchange={{action "selectionchange" value="target.value"}} >
{{#each countries as |country|}}
<option value="{{country.code}}" selected={{eq selectedCodecountry.code}}>
{{country.name}}
</option>
{{/each}}
</select>
Inside controller
countries: [
{code:"IN", name: "India"},
{code: "US", name: "USA"},
{code: "UK", name: "UK"}
],
selectedCode: "US",
actions: {
selectionchange(code) {
this.set('selectedCode', code);
}
Hope it helps.
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.
I was wondering if someone could give me brief direction. I'm making an app that I want to be able to take notes from anywhere I'm at in the app (CRUD). I'm rendering my presentations in my application controller using {{render}} but I'm not sure how to put the full crud operations there as well. This is what I have so far:
-- Presentation Controller
import Ember from 'ember';
var PresentationController = Ember.ObjectController.extend({
actions: {
edit: function () {
this.transitionToRoute('presentation.edit');
},
save: function () {
var presentation = this.get('model');
// this will tell Ember-Data to save/persist the new record
presentation.save();
// then transition to the current user
this.transitionToRoute('presentation', presentation);
},
delete: function () {
// this tells Ember-Data to delete the current user
this.get('model').deleteRecord();
this.get('model').save();
// then transition to the users route
this.transitionToRoute('presentations');
}
}
});
export default PresentationController;
-- Presentations Controller
import Ember from 'ember';
var PresentationsController = Ember.ArrayController.extend({
actions: {
sendMessage: function ( message ) {
if ( message !== '') {
console.log( message );
}
}
}
});
export default PresentationsController;
-- Model
import DS from 'ember-data';
var Presentation = DS.Model.extend({
title: DS.attr('string'),
note: DS.attr('string')
});
-- Presentations Route
import Ember from 'ember';
var PresentationsRoute = Ember.Route.extend({
model: function() {
return this.store.find('presentation');
}
});
export default PresentationsRoute;
-- Presentation Route
import Ember from 'ember';
var PresentationRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('presentation', params.id);
}
});
export default PresentationRoute;
-- Application Route
import Ember from 'ember';
export default Ember.Route.extend({
model: function () {
return this.store.find('category');
},
setupController: function (controller, model) {
this._super(controller, model);
controller.set('product', this.store.find('product'));
controller.set('presentation', this.store.find('presentation'));
}
});
-- Application HBS
<section class="main-section">
<div id="main-content">
{{#link-to "presentations.create" class="create-btn expand" tagName="button"}} Add presentation {{/link-to}}
{{render 'presentations' presentation}}
{{outlet}}
</div>
</section>
-- Presentations HBS
{{#each presentation in controller}}
{{#link-to 'presentation' presentation tagName='li'}}
{{presentation.title}}
{{/link-to}}
{{/each}}
{{outlet}}
-- Presentation HBS
{{outlet}}
<div class="user-profile">
<h2>{{title}}</h2>
<p>{{note}}</p>
<div class="btn-group">
<button {{action "edit" }}>Edit</button>
<button {{action "delete" }}>Delete</button>
</div>
</div>
Basically what you're describing is a modal of sorts. It'll be accessible no matter what page (route) you're viewing, and you will be able to perform actions within this modal (creating notes, editing notes, deleting notes, etc) without leaving or affecting the current page being displayed in the background. Essentially, what this means is that you should leave the router alone, since the router is what controls the current page, and you don't want to affect that. You're not going to want to have any {{#link-to}} or transitionTo or transitionToRoute calls, nor any presentation-related routes or outlets.
Instead, you're going to have to handle everything at the controller and view level. This is where components really come in handy, as they're great for encapsulation if you use them correctly. Inside of presentations.hbs, I'd use components to represent each of the presentations:
{{#each presentation in controller}}
{{individual-presentation presentationModelBinding="presentation"}}
{{/each}}
Note that you'll need a corresponding IndividualPresentationComponent object that extends Ember.Component. Going further, inside of individual-presentation.hbs, I'd have code similar to what you have now, but with allowances for various CRUD operations:
{{#if editing}}
{{input value=presentationModel.title}}
{{textarea value=presentationModel.note}}
{{else}}
<h2>{{title}}</h2>
<p>{{note}}</p>
{{/if}}
<div class="btn-group">
{{#if editing}}
<button {{action "save" }}>Save</button>
{{else}}
<button {{action "edit" }}>Edit</button>
{{/if}}
<button {{action "delete" }}>Delete</button>
</div>
Note that the context for a component's template is the component itself, not some other controller. Similarly, actions fired inside of a component's template are direct to the component's actions hash. So your IndividualPresentationComponent will need to look like this somewhat:
IndividualPresentationComponent = Ember.Component.extend({
classNames: ['user-profile'],
actions: {
save: function () {
this.sendAction('save', this.get('presentationModel'));
this.set('editing', false);
},
edit: function () {
this.set('editing', true);
},
delete: function () {
this.sendAction('delete', this.get('presentationModel'));
}
}
});
Notice I'm using sendAction here. This is how components communicate with the outside world. To get this to work, go back your presentations.hbs and intercept the actions like so:
{{#each presentation in controller}}
{{individual-presentation presentationModelBinding="presentation"
save="savePresentation"
delete="deletePresentation"}}
{{/each}}
Here you're basically saying that if the component sends the "save" action, you want to handle it with your controller's "savePresentation" action, and if the component sends the "delete" action, you want to handle it with your controller's "deletePresentation" action. So your presentations-controller.js will need to implement those actions:
var PresentationsController = Ember.ArrayController.extend({
actions: {
savePresentation: function (presentationModel) {
...
},
deletePresentation: function (presentationModel) {
...
},
}
});
And you can delete PresentationController, since all of its functionality is now handled directly by your IndividualPresentationComponent and your PresentationsController.
How can I fire a named action upon changing a checkbox in Ember.js? Any help will be greatly appreciated.
Here is what I have. Checking or unchecking the checkbox has no effect.
Template:
{{input type="checkbox" on="change" action="applyFilter"}}
Controller:
actions: {
applyFilter: function() {
console.log("applyFilter");
}
}
I'd like to post an update to this. In Ember 1.13.3+, you can use the following:
<input type="checkbox"
checked={{isChecked}}
onclick={{action "foo" value="target.checked"}} />
link to source
using an observer seems like the easiest way to watch a checkbox changing
Template
{{input type='checkbox' checked=foo}}
Code
foo:undefined,
watchFoo: function(){
console.log('foo changed');
}.observes('foo')
Example
http://emberjs.jsbin.com/kiyevomo/1/edit
Or you could create your own implementation of the checkbox that sends an action
Custom Checkbox
App.CoolCheck = Ember.Checkbox.extend({
hookup: function(){
var action = this.get('action');
if(action){
this.on('change', this, this.sendHookup);
}
}.on('init'),
sendHookup: function(ev){
var action = this.get('action'),
controller = this.get('controller');
controller.send(action, this.$().prop('checked'));
},
cleanup: function(){
this.off('change', this, this.sendHookup);
}.on('willDestroyElement')
});
Custom View
{{view App.CoolCheck action='cow' checked=foo}}
Example
http://emberjs.jsbin.com/kiyevomo/6/edit
Post Ember version >= 1.13 see Kori John Roys' answer.
This is for Ember versions before 1.13
This is a bug in ember's {{input type=checkbox}} helper.
see https://github.com/emberjs/ember.js/issues/5433
I like the idea of having a stand-in. #Kingpin2k's solution works, but accessing views globally is deprecated and using observers isn't great.
In the linked github ember issue, rwjblue suggests a component version:
App.BetterCheckboxComponent = Ember.Component.extend({
attributeBindings: ['type', 'value', 'checked', 'disabled'],
tagName: 'input',
type: 'checkbox',
checked: false,
disabled: false,
_updateElementValue: function() {
this.set('checked', this.$().prop('checked'));
}.on('didInsertElement'),
change: function(event){
this._updateElementValue();
this.sendAction('action', this.get('value'), this.get('checked'));
},
});
Example usage in a template ('checked' and 'disabled' are optional):
{{better-checkbox name=model.name checked=model.checked value=model.value disabled=model.disabled}}
For those using Ember > 2.x:
{{input
change=(action 'doSomething')
type='checkbox'}}
and the action:
actions: {
doSomething() {
console.warn('Done it!');
}
}
In Ember v1.13 it can be done simply by creating a component named j-check in my occasion(no layout content required):
import Ember from 'ember';
export default Ember.Checkbox.extend({
change(){
this._super(...arguments);
this.get('controller').send(this.get('action'));
}
});
And then you just call it from your template like this:
{{j-check checked=isOnline action="refreshModel" }}