choosing a value from select - ember.js

using ember.js 1.0 and ember-data 1.0 beta2
I have a model (state) with the following properties
state: DS.attr('string'),
stateName: DS.attr('string'),
and a model (customer) with the following properties
name: DS.attr('string'),
stateID: DS.attr('string'),
state: DS.belongsTo("state")
I want to be able to edit the customer and choose the state from a drop-down (that has the stateID + name showing : eg "FL - Florida" and when selected, to store the state.stateID into the customer.stateID property
this is the first time I've tried something like this , and am slightly confused about the process.
In my customer route I've set up the following:
setupController: function(controller, model) {
this._super(controller, model);
this.controllerFor('state').set('content', this.store.find('state'));
}
and my select is this:
{{view Ember.Select
contentBinding="controllers.state.content"
optionValuePath="content.stateName"
optionLabelPath="content.stateName"
valueBinding="content.stateID"
selectionBinding="content.stateID"
prompt="Select a state"
}}
now I'm confused about where to go from here.
thanks
update
changed the view to say
{{view Ember.Select
contentBinding="controllers.state.content"
optionValuePath="content.stateID"
optionLabelPath="content.stateName"
valueBinding="customer.stateID"
}}
and I still don't get the stateid property to change . I've also tried
selectionBinding="customer"
to no avail.
update #2
I suspect that my problem may be linked to the property name. I changed the customer.stateID property to be customer.foobar and changed the select to read
{{view Ember.Select
contentBinding="controllers.state.content"
optionValuePath="content.stateName"
optionLabelPath="content.stateName"
valueBinding="foobar"
class="form-control"
}}
and now customer.foobar is updated with the value from the select.
Is there a problem with a property called stateID on customer ? I have a state model and state controller etc so is there a conflict ?

after all that - the problem was in the models themselves. The state model does not have a stateID field, it's state.state ...
My heartfelt apologies to all that wasted their time on this. Such a stupid error.

Okay, maybe not the best solution, but it works well:
App.ItemModalController = Ember.ObjectController.extend({
content: [],
availableCategories: function() {
return this.store.find('category');
}.property(),
//...
});
And the select:
{{view Ember.Select
contentBinding="availableCategories"
valueBinding="categorySelected"
optionLabelPath="content.title"
optionValuePath="content.id"
prompt="Please select a category"
class="form-control"
}}

Related

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

Update value when value is selected in Ember.Select

I have a Ember.Select in my template and an image:
Difficulty: {{view Ember.Select id="id_diff" contentBinding="difficulties" optionValuePath="content.id" optionLabelPath="content.title"}}
<img src="(path)" />
The Select is filled with values coming from server; in the controller:
difficulties: function() {
return this.get('store').find('difficulty');
}.property()
and the model:
Gmcontrolpanel.Difficulty = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
path: DS.attr('string')
});
And that's ok; but i would like that when a difficulty is selected from the Ember.Select, the corrispondent path property would be inserted in the img tag
Anyone knows how to get this result?
To accomplish this, I would set up a couple of things.
First, update your Ember.Select to include a valueBinding against the model with a new property:
{{view Ember.Select id="id_diff" contentBinding="difficulties" optionValuePath="content.id" optionLabelPath="content.title" valueBinding="selectedDificulty"}}
This will bind your select view to a model object. Which means, on the controller, we can now include a new function with a .observes on that field:
updateImage : function(){
this.set('fullPath', this.get('path') + this.get('selectedDificulty'));
}.observes('selectedDificulty');
And finally, change your image path to the newly created one:
<img src="(fullPath)"/>

Ember: How to set controller model for use in select view

See: http://jsfiddle.net/cyclomarc/VXT53/8/
I have a select view in which I simply want to list all the authors available in the fixtures data. I therefore try to use a separate controller in which I want to set the content = App.Author.find(), but that doesn't work ...
App.AuthorsController = Ember.ArrayController.extend({
//content: App.Store.findAll(App.Author)
//content: App.Author.find()
});
I then want to use the AuthorController for contentBinding in the selectView, but also this is not succsesful ...
{{view Ember.Select
contentBinding="App.AuthorsController"
optionValuePath="content.id"
optionLabelPath="content.name"
valueBinding="App.PublicationsEditController.author"
prompt="Select an author"
}}
The use case is that I have a publication in which an author is set (e.g. Marc) and I want to allow the user to change this to one of the available authors and then bind the new selected author to the publication model so that after a save the new author is saved.
I guess this what you are after: http://jsfiddle.net/VXT53/10/
I had to do a couple of changes, first your router map where slightly wrong, the edit segment had to go after the id to match your template name pulications/edit:
App.Router.map(function () {
this.resource('publications', { path: '/' }, function () {
this.route("edit", { path: "/edit/:publication_id" });
});
});
Your Ember.Select where binding to a class instead to some content, to set it up correctly I've defined a PublicationsEditControllet to requiere trough the needs API access to the AuthorsController's content:
App.PublicationsEditController = Ember.ObjectController.extend({
needs: ['authors'],
...
});
this is how you then use it for your select:
{{view Ember.Select
contentBinding="controllers.authors.content"
optionValuePath="content.id"
optionLabelPath="content.name"
valueBinding="content.name"
selectionBinding="selectedAuthor"
prompt="Select an author"
}}
Furthermore I've created a setupController hook which is used to set the AuthorsController's content to the list of authors:
App.PublicationsRoute = Ember.Route.extend({
model: function () {
return App.Publication.find();
},
setupController: function(controller, model) {
this._super(controller, model);
this.controllerFor('authors').set('content', App.Author.find());
}
});
And lastly on you PublicationsEditController is a new property attached selectedAuthor to hold the currently selected author for binding etc.
App.PublicationsEditController = Ember.ArrayController.extend({
needs: ['authors'],
selectedAuthor: null
});
I guess this should work now and brings you one step further.
Hope it helps.

How to add multiple selection into a many-to-many model in Ember.js?

I have this small app where I'm trying to add the fruits selections of a multiple Ember.Select into an attribute of a model, "myfruits" of Person Alice. However, things are broken.
Perhaps my model is set up incorrectly.
This is the Ember.Select handlebars in the html:
{{view Ember.Select
multiple="true"
contentBinding="App.fruits"
valueBinding="pickedFruits"
}}
This is the model:
App.Person = DS.Model.extend({
name: DS.attr('string'),
myfruits: DS.hasMany('App.Fruit')
});
App.Fruit = DS.Model.extend({
kind: DS.attr('string'),
likedBy: DS.hasMany('App.Person')
});
This is the function that tries to save the multiple selection:
pickThem: function(){
var input_fruits = this.get('pickedFruits');
// should I create a Fruit object for each input_fruits?
var aperson = App.Person.createRecord({
name: "Alice",
myfruits: input_fruits
});
aperson.save();
}
I feel like the problem might be I'm not creating the Fruit objects. But I'm not sure how to make it work with the many-to-many relationship between Person and Fruit.
I guess what you need to do is as you already mentioned to create a App.Fruit record for every selected fruit and add it to the newly created App.Person.
Basically the important bit is:
App.PersonController = Ember.ArrayController.extend({
pickThem: function(){
var aperson = App.Person.createRecord({name: "Alice", myfruits: []});
this.get('pickedFruits').forEach(function(item){
aperson.get('myfruits').pushObject(App.Fruit.createRecord({kind:item, likedBy:[aperson.get('id')]}));
});
aperson.save();
}
});
Then provide a model for your person template:
App.PersonRoute = Ember.Route.extend({
model: function() {
return App.Person.find();
}
});
and in your template you can loop over the person records and inside that loop over their respective fruits:
{{#each model}}
{{name}} likes are:
{{#each myfruits}}
{{kind}}
{{/each}}
{{/each}}
Have a look at this updated jsbin.
You should however reset your local store adapter's data to avoid multiple entries after each application initialization. I've done it by creating a pseudo random suffix for the namespace of the LSAdapter, but this could be anything you find more convenient.
App.LSAdapter = DS.LSAdapter.create({
namespace: 'app-emberjs-'+Math.floor(Math.random()*1000)
});
Hope it helps.
Edit
After reading your last comment and just to show how it looks like in the chrome debugger tools that the LSAdapter stores the data. Have a look at the below screenshot. Here I've reloaded 2 times the app, and as expected two namespaces are created. If you have the same namespace every time thing are going to overlap resulting in some unexpected behavior.

Selected select on default ember js

I have a model Currencies. Fields in the model are name:string and default:boolean.
On the backend only one of records in database can have default:true. I want it to be selected by default in select in Ember js.
Please give me an example how to make such select and use it
Example:
name: type1 default: false
name: type2 default: true
name: type3 default: false
I want to generate such select :
<selected>
<option>type1</option
<option selected=selected>type2</option
<option>type3</option
</selected>
Route.js
#route 'addincome', { path: 'operations/addincome' }
EmberMoney.AddincomeRoute = Ember.Route.extend
model: ->
EmberMoney.IncomeOperation.createRecord()
setupController: (controller, model) ->
controller.set('currencies', EmberMoney.Currency.find())
controller.set('content', model)
addincome.handlebars
// Some output with Incomes records
{{view EmberMoney.Select viewName="select"
contentBinding="controller.currencies"
optionLabelPath="content.name"
optionValuePath="content.id"
selectionBinding="controller.defaultType"}}
addincome_controller.js
EmberMoney.AddincomeController = Ember.ObjectController.extend({
setDefaultCurrency: function(){
if(this.get('currencies.isLoaded')){
this.set('defaultType', this.get('currencies').findProperty('default'));
}
}.observes('currencies.isLoaded')
})
My answer builds upon that one already posted. The answer is to use the selectionBinding and a clever way to set it up:
{{view Ember.Select
contentBinding="controller.types"
optionLabelPath="content.name"
optionValuePath="content.id"
selectionBinding="controller.selectedCurrency"
}}
EmberMoney.IncomesController = Ember.ArrayController.extend({
selectedCurrency : null,
currenciesObserver: function(){
var currencies = this.get("currencies");
var default = currencies.findProperty("default");
if(default)
this.set("selectedCurrency", default);
}.observes('currencies.#each')
});
How does the solution work?
We set up a selectionBinding (two way) between the Select control and your controller. If you set a currency in your controller in the property 'selectedCurrency', it will be the selected value in the Select control. Vice versa if you select a currency in the Select Box, it will be set in your controller.
I am doing the initial setup with the helper of an observer. The observer is called each time the watched currencies array changes.
Every time it is called, it tries to find a default currency. If it finds one, it sets it in your selectedCurrency property. Now the selectionBinding kicks and does its magic for you.
An additional advantage of this solution is, that you can grab the selected value easily from the property, if the user chooses another currency.
Use selectionBinding for the selection, and ComputedProperty to find the appropriate item
Update
EmberMoney.AddincomeController = Ember.ObjectController.extend({
setDefaultCurrency: function(){
if(this.get('currencies.isLoaded')){
this.set('defaultType', this.get('currencies').findProperty('default'));
}
}.observes('currencies.isLoaded')
})
The advantage of using isLoaded over #each for the observer is that the observer wont get fired everytime a currency is added instead it makes sure to set the value once the entire collection is loaded, Again it is upto the use case to determine which to use when
Details about findProperty
Hope this helps
Screenshot