Search code examples
ember.jsember-dataemberfire

ember firebase pass models to action handler


I have ember data models hooked with firebase, characters and spells. I can create new models and save them to firebase. Now I wanted to add spells to character. I defined that character has many spells:

export default DS.Model.extend({
  chClass: DS.attr(),
  chName: DS.attr(),
  chImage: DS.attr(), 
  chSpells: DS.hasMany('spell', {async: true}),
});

In my hbs I listed spells in <select> element, there is also input fields and add button.

Add new character <br>
name {{input value=mchName }}<br>
class {{input value=mchClass }}<br>
image {{input value=mchImage }}<br>

<br>
Choose Spells:<br>
<select name="spellslist" multiple>
{{#each spells as |spell index|}}
 <option value="{{index}}">{{spell.spName}}</option>
{{/each}}
</select>

<button {{action 'addChar' spells}}>add</button><br>

So when user types in character name, level and picks some spells I want to call addChar action function on add button and pass this data.

export default Ember.Controller.extend({
mchName:'',
mchClass:'',
mchImage:'',
store: Ember.inject.service(),

actions: {
addChar: function(spells) {
  var newChar = this.store.createRecord('character');
  newChar.set("chName", this.mchName);
  newChar.set("chClass", this.mchClass);
  newChar.set("chImage", this.mchImage);
  newChar.get("chSpells").addObject(?????? how to get spell here ?????);

  newChar.save();

I know how to pass string from inputs, but I dont know how to pass selected spells to this function, its killing me.


Solution

  • I'm assuming that you (as admin) are going to populate the spells table. Now ... assuming that a character can have many spells and a spell can have many characters, here's how one can approach this (note that I'm using a controller ... you should ideally be doing this in a component):

    Character model is simplified:

    //app/models/character.js
    import DS from 'ember-data';
    
    export default DS.Model.extend({
      chName: DS.attr(),
      chSpells: DS.hasMany('spell', {async: true})
    });
    

    Spells model is also simplified for this example:

    //app/models/spell.js
    import DS from 'ember-data';
    
    export default DS.Model.extend({
      spName: DS.attr(),
      spellChar: DS.hasMany('character', {async: true})
    });
    

    We need an include helper for the multiline select. Review this article for details:

    //app/helpers/include.js
     import Ember from 'ember';
      export function include(params/*, hash*/) {
      const [items, value] = params;
      return items.indexOf(value) > -1;
       } 
      export default Ember.Helper.helper(include);
    

    Here's the application route:

    app/routes/application.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
      model: function(){
        var spells = this.store.findAll('spell');
        return spells;
      }
    });
    

    And the application controller:

    //app/controllers/application.js
    import Ember from 'ember';
    
    export default Ember.Controller.extend({
      selectedSpellIds: [],
      actions: {
        selectSpell(event){
          const selectedSpellIds = Ember.$(event.target).val();
          this.set('selectedSpellIds', selectedSpellIds || []);
        },
        addChar: function(){
          var charName = this.get('mchName');
          var _this = this;
          var spells = this.get('selectedSpellIds');
          var spellObjArray = spells.map(function(spellId){
            return _this.store.peekRecord('spell', spellId );
          });
          var charToSave = this.store.createRecord('character', {
              chName: charName,
              chSpells: spellObjArray
          });
          charToSave.save();
        },
      }
    });
    

    And the application template:

    //app/templates/application.hbs
    Add new character <br>
    name {{input value=mchName }}<br>
    
    <br>
    Choose Spells:<br>
    <select multiple onchange={{action "selectSpell"}}>
    {{#each model as |spell|}}
     <option value={{spell.id}} selected={{include selectedSpellIds spell.id}}>{{spell.spName}}</option>
    {{/each}}
    </select>
    
    <button {{action 'addChar'}}>add</button><br>