Reputation: 3624
I am relatively new to Ember.js, so I am giving myself a project to figure things out.
I believe I understand the very basics. Controllers contain state-logic
, while models contain model attribute-logic
.
In my example, I have a collection of models. These models contain an attribute that represents an id of another model:
App.Pokeball = DS.Model.extend({
name: DS.attr('string'),
rate: DS.attr('number'),
pokemon: DS.belongsTo('pokemon')
});
I have a Controller that contains selectedPokemonId
and selectedPokemon
attributes. When selectedPokemonId
changes, I want to automatically update all the Pokeball models.
I know its awful, but here is the function I am using to update the Models:
selectedPokemon: function(selectedPokemonId) {
var pokemonId = this.get('selectedPokemonId'),
store = this.store,
id = 1,
max = App.Pokeball.FIXTURES.length;
for (id,max; id<= max;id++) {
store.update('pokeball', {
id: id,
pokemon: pokemonId
});
}
return store.find('pokemon', this.get('selectedPokemonId'));
}.property('selectedPokemonId'),
Technically, this does what I need it to... but I am certain I am not doing this the "ember way", there has to be a cleaner way to bind the relationship between controller state and models.
Upvotes: 0
Views: 63
Reputation: 160
I like to work directly with models as objects instead of managing record ids. Doing this greatly simplifies your code. Here's how I would accomplish this.
First, your route should return all the models you want to work with using the model hook.
The route's model hook should look something like:
model: function()
{
return Ember.RSVP.hash ({
pokeballs: this.store.find('pokeball'),
pokemon: this.store.find('pokemon')
});
}
In general you want to do store.find calls in the route model hook because they can be asynchronous (return a Promise) and the model hooks waits for promises to resolve before proceeding. This ensures your data will always be ready for your controller to work with it. More here: http://emberjs.com/guides/models/finding-records/. Note that the model we'll be working with is an object with two properties, pokeballs and pokemon, which are both collections representing all the respective objects in the store.
In your controller, instead of a selectedPokemonId, you can reference a selectedPokemon model object directly. You can then observe the change to the selectedPokemon using 'observes' and then simply set the selectedPokemon on each pokeball and save each pokeball model to persist it back to the store. If you're just using fixtures you could get away without even saving each pokeball because 'set'-ing a property on the model object is enough to change it in the store.
selectedPokemonObserver: function()
{
var thePokemonToSet = this.get('selectedPokemon');
this.get('pokeballs').forEach( function( aPokeball ) { // note you can also do this.get('model.pokeballs') since the model is an object with two properties, pokeballs and pokemon
aPokeball.set('pokemon', thePokemonToSet); //note that instead of an id, i'm setting the pokemon model object here to satisfy the belongsTo relationship
aPokeball.save(); // you might not need this if using only fixtures and not persisting to db.
});
}.observes('selectedPokemon')
Anything referencing these model objects in your templates will automatically be updated.
Upvotes: 1
Reputation: 104040
I think the "Ember way" to do what you want to accomplish is to use an observer instead of a property:
...
selectedPokemonObserver: function() {
var pokemonId = this.get('selectedPokemonId'),
store = this.store,
id = 1,
max = App.Pokeball.FIXTURES.length;
for (id, max; id <= max; id++) {
store.update('pokeball', {
id: id,
pokemon: pokemonId
});
}
}.observes('selectedPokemonId'),
selectedPokemon: function() {
return this.store.find('pokemon', selectedPokemonId);
}.property('selectedPokemonId'),
...
Upvotes: 1