mercredi 16 décembre 2015

How to correctly do a form with relationships and server side validations

In an ember app, using JSON Api adapter, I have those models :

# subscription.js
import DS from 'ember-data';

export default DS.Model.extend({
  userId: DS.attr(),
  user: DS.belongsTo('user'),
  courseId: DS.attr(),
  course: DS.belongsTo('course')
});

#contact.js
import DS from 'ember-data';

export default DS.Model.extend({
  fullname: DS.attr(),
  phone: DS.attr(),
  email: DS.attr(),
  user: DS.belongsTo('user'),
});

#user.js
import DS from 'ember-data';

export default DS.Model.extend({
  email: DS.attr(),
  subscriptions: DS.hasMany('subscription'),
  course: DS.hasMany('course'),
  contacts: DS.hasMany('contact')
});

Using ember-rapid-form, I have this template :

{{#em-form model=model}}
  {{em-input model=model.user label="Email" property="email" canShowErrors=true}}
  {{em-select label="Course" property="course" content=courses canShowErrors=true prompt=" " propertyIsModel=true optionLabelPath="name"}}
  {{#each model.user.contacts as |contact|}}
    <div class='row'>
      <div class='col-md-4'>
        {{em-input model=contact label="Name" property="fullname" canShowErrors=true}}
      </div>
      <div class='col-md-4'>
        {{em-input model=contact label="Email" property="email" canShowErrors=true}}
      </div>
      <div class='col-md-4'>
        {{em-input model=contact label="Phone" property="phone" canShowErrors=true}}
      </div>
    </div>
  {{/each}}
  <a {{action 'addContact' }}>Add contact</a>
{{/em-form}}

And this route :

import Ember from 'ember';

export default Ember.Route.extend({
  model() {
    var subscription = this.store.createRecord('subscription');
    var user = this.store.createRecord('user');
    subscription.set('user', user);
    return subscription;
  },
  actions: {
    submit: function(token) {
      var subscription = this.controller.model;
      subscription.get('user').then((user) => {
        user.save().then(() => {
          subscription.save().then(() => {
            user.get('contacts').invoke('save');
            this.transitionTo('subscriptions.success');
          }, function() {} );
        })
      })
    },
    addContact: function() {
      var subscription = this.controller.model;
      subscription.get('user').then((user) => {
        var contact = this.store.createRecord('contact');
        user.get('contacts').pushObject(contact);
      })
    },
  }
});

It works but I have problems with my submit method. First, I think it's ugly, I don't like nested then. Secondly, if there is a failure with a server side validation, it will not continue and trigger other validations. If some models fail, others can be created on the server side.

I did not found any clean solution on the Internet. The best way can be to pass all data in a single xhr call. I tried without success to pass nested attributes on models.

What's the best way to do this kind of forms?




Aucun commentaire:

Enregistrer un commentaire