Binding Em.Select selection value to object from store - ember.js

I can't figure out how to use the valueBinding property of Ember.Select to bind the selected value directly to a object from Ember.Data's store.
Fiddle: http://emberjs.jsbin.com/jipamiro/14/edit
The problem I'm facing is that the model returns DS.RecordArray object and I just need the selection value. I tried "firstObject", computed properties and so on to no avail and running out of ideas....

Here is a working bin.
I modified the model hook in the route and the valueBinding property in the template. In the model hook, I am specifying which item to find instead of returning the whole array.
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('setup', 0);
}
});
{{view Ember.Select class="form-control"
viewName="channel"
content=channelOptions
optionValuePath="content.id"
optionLabelPath="content.name"
valueBinding="selectedChannel"}}

Related

emberjs itemcontroller property scope

I need an explanation for the usage of an itemcontroller in emberJS.
I created a handlebars template that looks like this:
{{#each thing in controller itemController="itemController"}}
{{view "testview" contentBinding="thing"}}
{{/each}}
The testview creates a html table and within the testview I use a second view in a each loop which creates several tr:
{{each item in view.content.thing}}
{{view 'trview' contentBinding="item"}}
{{/each}}
In addition to that I added a property "listOfProperties" (Ember.A()) to the itemController.
I use the click function of the trview to add a value to the "listOfProperties" array of the itemController.
And here I receive an error: If I click on a tr, the value is added to each itemControllers "listOfProperties" array and not only to one "things" itemController.
I'm going to guess since you didn't include your item controller, but it's likely you're running into a reference issue. Array's are a reference and as such are shared across instances of item controllers.
App.ItemController = Em.ObjectController.extend({
setup: function(){
this.set('listOfProperties', []);
}.on('init'),
listOfProperties: null,
});

Creating a new record not pulling data from template fields

I am attempting to create a new record, however none of the data from the fields is being passed automatically, as I expected Ember to (from what I've read).
My template:
<form {{action save content on="submit"}}>
{{input value=name}}
<button type="submit"}}>Next</a>
From what I've read content is an alias for model and interchanging these makes no difference.
My route:
App.CampaignsNewRoute = Ember.Route.extend({
actions: {
save: function(campaign) {
console.log(campaign.name);
}
},
model: function(controller) {
return this.store.createRecord('campaign');
}
});
And my controller:
App.CampaignsNewController = Ember.ObjectController.extend({
pageTitle: 'New Campaign Setup'
});
When I hit 'Next' it logs undefined. Logging just the campaign shows it's an Ember model, but without the name attribute. name is defined on the campaign model. Setting the input to {{input value=content.name}} places the name attribute within the model returned, but it's still undefined. Am I missing anything in this process? The EmberJS site doesn't show how to do this, from what I can find.
--
As a side note: I was originally using App.CampaignsNewController = Ember.Controller.extend as my model was returning a hash of promises, one of which is an array and Ember didn't like me using either array or object controller. I simplified it to the above to verify it wasn't that which was causing the issue. So any solution taking this into account would be wonderful.
Edit: I can access the template fields by doing this.get('controller').get('name') but surely that is not necessary? Changing my controller to a Ember.Controller.extend also stops that from working, would love to know why. Clarification on best practice here would still be wonderful!
Edit2: this.get('controller.content').get('name') works if the controller is simply an Ember.Controller as opposed to Ember.ObjectController and the template has {{input value=content.name}}. I'll work with but hopefully someone can clarify this is the correct way.
ObjectController is the way to go here. You would have it backed by one particular model, your new model, and you would add additional properties to the controller for use in the template.
Code
App.IndexRoute = Ember.Route.extend({
actions: {
save: function(campaign) {
console.log(campaign.get('color'));
}
},
model: function() {
return Ember.RSVP.hash({
record: this.store.createRecord('color'),
all: this.store.find('color')
});
},
setupController: function(controller, model){
this._super(controller, model.record);
controller.set('allColors', model.all);
}
});
App.IndexController = Em.ObjectController.extend({
});
Template
In the template any time you want to access anything on the model backing the template, you can just access it as if the model is the current scope.
{{name}}
if you want to access any of the properties that exist on the controller you would use the property name that it is on the controller.
{{allColors.length}}
Here's an example:
<form {{action save model on="submit"}}>
Color:{{input value=color}}<br/>
<button type="submit">Next</button>
</form>
<ul>
{{#each item in allColors}}
{{#unless item.isNew}}
<li>{{item.color}}</li>
{{/unless}}
{{/each}}
</ul>
One last tip, always use getters and setters ;)
Ember Data hides the properties, they don't live right on the object, so campaign.name will return undefined forever and ever. If you do campaign.get('name') you'll get a real response.
With the example: http://emberjs.jsbin.com/OxIDiVU/792/edit

Ember, how to copy value/label of selected item of Ember.Select to next TextField?

I have a simple construction Ember.Select holding some predefined strings and Ember.TextField next to it:
{{view Ember.Select
prompt="Choose..."
contentBinding="predefinedLabels"
optionValuePath="content.value"
optionLabelPath="content.label"
}}
{{view Ember.TextField valueBinding='view.newLabel' action='saveNewLabel'}}
I need to on select change get it's current value (if not prompt) and set it to the TextField and then reset the select to the prompt state - sounds trivial, but I have no idea how to do that :( I tried by using selectionBinding but problem is that these sets Select+ TextField are created dynamically. with common jQuery I would do it with common change listener added to the all select tags with some specified class, what is equivalent of the similar behavior in the Ember? (or what is proper way to do what I need?
You can still do just that with jQuery. Just put the relevant code (attaching change listeners) into the didInsertElement method of your current view.
See this working jsFiddle.
App.ApplicationView = Ember.View.extend({
didInsertElement: function() {
var self = this;
this.$('select').change(function() {
self.$('input').val(self.$('option:selected').text());
self.$("option:selected").removeAttr("selected");
});
}
});
Do I understand you correctly?
Is this the behaviour you are looking for: http://jsbin.com/aqaYEgo/3/edit
Basically:
App.ApplicationController = Ember.ObjectController.extend({
selectedLabel: null,
actions: {
saveNewLabel: function() {
console.log('Saving label: ' + this.get('selectedLabel.value'));
}
}
});
{{view Ember.Select
prompt="Choose..."
contentBinding="model"
optionValuePath="content.value"
optionLabelPath="content.label"
selectionBinding="selectedLabel"
}}
{{view Ember.TextField valueBinding="controller.selectedLabel.value" action='saveNewLabel'}}
Hope it helps.

Populating contents of Ember.Select view from RecordArray retrieved using Ember-data

I have a select list that is created using this code:
{{view Ember.Select
contentBinding="App.riskCategories"
optionValuePath="content.id"
optionLabelPath="content.name"
selectionBinding="riskCategory"
class="input-medium"}}
riskCategory is a property of the App.Facility model loaded for the template and the list of App.RiskCategory is populated with this code:
App.ready = function() {
App.riskCategories = App.RiskCategory.all()
}
This works fine and populates the select list but only with the sub-set of Risk Categories already loaded into the browser. If I call App.RiskCategory.find() from the browser console then the rest are loaded and the select list updates however I can't get the code working to do this for me.
So I tried:
App.ready = function() {
App.riskCategories = App.RiskCategory.find()
}
or:
App.ready = function() {
App.RiskCategory.find()
App.riskCategories = App.RiskCategory.all()
}
But both of these result in the following error:
Uncaught Error: Attempted to handle event `loadedData` on <App.Facility:ember417:1> while in state rootState.loaded.updated.uncommitted. Called with undefined
I'd appreciate any help or suggestions on a better way to populate the select list. These App.RiskCategory objects should be considered an immutable collection of constants stored in the db. Each of the App.Facility objects is associated with one of these App.RiskCategories
Thanks!
Try instead to set the categories in your route and access it in your template through the controller
APP.YourRoute = Ember.Route.extend({
setupController:function(controller,model) {
this._super(controller,model);
controller.set('riskCategories',App.RiskCategory.find());
},
});
Assuming your select view is within the same context as the controller, You get access to categories in your template this way:
{{view Ember.Select
contentBinding="controller.riskCategories"
optionValuePath="content.id"
optionLabelPath="content.name"
selectionBinding="riskCategory"
class="input-medium"}}
I solved this problem by wrapping the rendering of each App.Facility in a {{#if isLoaded}}
So the code looked somthing like:
{{#each client.facilities}}
{{#if isLoaded}}
{{view Ember.Select
contentBinding="App.riskCategories"
optionValuePath="content.id"
optionLabelPath="content.name"
selectionBinding="riskCategory"
class="input-medium"}}
{{/if}}
{{/each}}
It appears that the App.Facility object that setting the App.RiskCategory hadn't finished loading yet, so the default App.RiskCategory was being set and then when the dataLoaded event was fired, the exception was being thrown because the object had already been modified.
I had a similar problem and the solution using #isLoaded did not work for me. However, what did was to add a prompt property to the Ember.Selectelement. I suspect that that has to do with the asynchronicity of rendering the view and loading the data (in my case from FIXTURES, but as as far as I know DS.FixtureAdapter simulates time-lags in loading data).

How to use Ember.Select to set association IDs

I am trying to use the Ember.Select control to set an association id on a model. However, I can't seem to get the control to bind it's selection to an id attribute instead of the entire model object. Is this by design in the Ember.Select control? I have the following in my template:
{{view Ember.Select
contentBinding="App.peopleController.content"
selectionBinding="App.selectedPersonController.personId"
optionLabelPath="content.fullName"
optionValuePath="content.id"}}
Yet even with explicitly setting selectionBinding to the personId attribute it still seems to be binding to the person object. Full jsfiddle here: http://jsfiddle.net/PXVZb/10/
I would suggest to bind the selected person to your App.selectedPersonController and create a property personId which binds to the persons id, see http://jsfiddle.net/PXVZb/11/
JS:
App.selectedPersonController = Ember.Object.create({
personIdBinding: 'person.id'
});
Handlebars:
{{view Ember.Select
contentBinding="App.peopleController.content"
selectionBinding="App.selectedPersonController.person"
optionLabelPath="content.fullName" }}