2

I'm currently trying to generate forms dynamically in Ember with Ember-data. The form fields required depend on the content type of the publishable being loaded when the route publishables/:publishable_id/edit is accessed.

Data sources:

models/settings.js:

import DS from 'ember-data';

var Settings = DS.Model.extend({
  type: DS.attr(),
  fields: DS.attr()
});

Settings.reopenClass({
  FIXTURES: [
    {
      id: 1,
      type: 'Gallery',
      fields: [
        {type: 'text', name: 'name', description: 'desc1'},
        {type: 'text', name: 'email', description: 'desc2'},
      ]
    },
    {
      id: 2,
      type: 'article',
      fields: [
        {type: 'text', name: 'name', description: 'desc1'},
        {type: 'textarea', name: 'notes', description: 'desc2'}
      ]
    }
  ]
});

export default Settings;

models/publishable.js:

import DS from 'ember-data';

var Publishable = DS.Model.extend({
  title: DS.attr(),
  description: DS.attr(),

  authors: DS.hasMany('author', { async: true }),
  category: DS.belongsTo('category', { async: true }),

  published: DS.attr(),
  publish_from: DS.attr(),
  slug: DS.attr(),

  name: DS.attr(),
  fields: DS.attr(),

  contentType: DS.attr()
});

Publishable.reopenClass({
  FIXTURES: [
    {
      id: 1,
      title: 'How do I feed hamsters?',
      description: 'description 1',
      slug: 'derp',
      author: [
        {name: 'Tom Dale'}
      ],
      publish_from: "2014-07-14T23:11:48Z",
      question: 'Tomster cant eat using knife and a fork because his hands are too small. We are looking for a way to feed him. Any ideas?',
      contentType: {
        name: 'Gallery'
      },
      name: 'somedumname',
      email: 'herp@derp.com',
      passwordConfirmation: 'lolololololol',
      fields: { name: 'somedumname', email: 'herp@derp.com', passwordConfirmation: 'lolololololol' }
    }, {
      id: 2,
      title: 'Are humans insane?',
      description: 'description 2',
      author: 'Tomster the Hamster',
      date: '2013-02-02T12:00:00',
      question: 'I mean are totaly nuts? Is there any hope left for them? Should we hamsters try to save them?',
      contentType: {
        name: 'article'
      },
      fields: {name: 'hehehe', notes: 'lolololol'}
    }
  ]
});

export default Publishable;

For example, when pubishables/1/edit is accessed, a form will generate based on App.Publishable.FIXTURE[:publishable_id].contentType.name === App.Settings.FIXTURE[:publishable_id].type. Or, since the current publishable's content type is 'Gallery', fields data from Settings based on Settings.type === 'Gallery' will be grabbed.

In the case of /1/, two inputs need to be generated:

{type: 'text', name: 'name', description: 'desc1'},
{type: 'text', name: 'email', description: 'desc2'}

Where the input type is type, the description is description, and the value is App.Publishable.FIXTURE[:publishable_id].field[App.Settings.FIXTURE[:publishable_id].fields[i].name]. Or in the case for the first input, it will need to be populated with App.Publishable.FIXTURE[:publishable_id].field.name. (or in the case of the second input App.Publishable.FIXTURE[:publishable_id].field.email).

This is the part that I've been struggling with. How to relate the fields getting auto generated based on the Settings model, and the corresponding value from the Publishable model.

Currently I am doing a bit of a hack via the PublishableController:

controllers/publishables.js:

import Ember from 'ember';

export default Ember.ObjectController.extend({
  needs: ['settings'],
  settings: Ember.computed.alias('controllers.settings.model'),
  formFields: function() {

    var modelFields = this.get('model.fields');
    var settingsFields = this.get('settings.content')[0].get('fields'); // a bit of a hack, unsure how to do this better.

    var inputArray = [];

    for(var i = 0; i < settingsFields.length; i++) {

      var tmpObj = {};

      for (var property in settingsFields[i]) {
        if (settingsFields[i].hasOwnProperty(property)) {
          tmpObj[property] = settingsFields[i][property]
          if(modelFields[settingsFields[i][property]]) {
            tmpObj['content'] = modelFields[settingsFields[i][property]];
          }
        }
      }

      inputArray.push(tmpObj);

    }

    return inputArray;

  }.property(this)
});

Where I:

  1. Create an array
  2. Create a temp object
  3. Iterate over the settings model and add all its properties to the temp object
  4. Find the relationship between Settings.fields.name and Publishable.fields[Settings.fields.name] and key it as 'content' in the temp object
  5. Push the temp object to the array
  6. Return the new array so I can loop over it in the view as {{#each formFields}}

This works wonders for generating the form with the appropriate value from the Publishable model. The only problem with this is I lose context of the Publishable model. I'm at a loss as how to proceed editing the input values and saving them back to the model.

Here is the template:

templates/publishable/edit.hbs:

<form>
{{#each formFields}}
  {{input name=name type=type value=content}}
  {{description}}
{{/each}}
</form>

I was thinking of doing a .set() the different input values based on name, but that seems very clunky.

Is there a better way to associate the auto generated inputs based on Settings and values from the Publishable model? Or is there some way I can observe the inputs so when I hit submit on the form that I can update the model?

tr3online
  • 1,429
  • 2
  • 24
  • 45

0 Answers0