-
Notifications
You must be signed in to change notification settings - Fork 84
Bootstrap 3 and Ember Data With Server Side Validations
Here are the steps currently required to get ember-easyForm working with Bootstrap 3 and Ember-Data (with server side validations). In this application I've used Ember-CLI with a Rails backend and the ActiveModelAdapter, so your situation might be different.
There are some issues getting it to work with Ember-Validation to have Client and Server side validations: https://github.com/dockyard/ember-validations/issues/122
I'm not sure if the pattern is the same for other build systems, but Ember-CLI has an initializers directory where I've added some "modifications" (aka hacks) to ember easyForm.
// app/initializers/easy-form.js
export default {
name: 'easyForm',
initialize: function(container) {
Ember.EasyForm.Input.reopen({
errorsChanged: function() {
this.set('hasFocusedOut', true);
this.showValidationError();
},
classNameBindings: ['wrapperConfig.inputClass', 'wrapperErrorClass'],
didInsertElement: function() {
this.addObserver('context.errors.' + this.property + '.@each', this, 'errorsChanged');
},
isCheckbox: function() {
if (this.get('inputOptionsValues.as') === 'checkbox') {
return true;
}
else {
return false;
}
}.property('inputOptionsValues'),
divWrapperClass: function() {
if (this.get('inputOptionsValues.as') === 'checkbox') {
return 'checkbox';
}
else {
return '';
}
}.property('inputOptionsValues')
});
Ember.EasyForm.Error.reopen({
errorText: function() {
var message = this.get('errors.firstObject.message');
if (message === undefined) {
return this.get('errors.firstObject');
} else {
return message;
}
}.property('errors.firstObject').cacheable(),
updateParentView: function() {
var parentView = this.get('parentView');
if(this.get('errors.length') > 0) {
parentView.set('wrapperErrorClass', 'has-error');
}else{
parentView.set('wrapperErrorClass', false);
}
}.observes('errors.firstObject')
});
Ember.EasyForm.Submit.reopen({
disabled: function() {
return this.get('formForModel.disableSubmit');
}.property('formForModel.disableSubmit')
});
//-- Bootstrap 3 Class Names --------------------------------------------
//-- https://github.com/dockyard/ember-easyForm/issues/47
Ember.TextSupport.reopen({
classNames: ['form-control']
});
// And add the same classes to Select inputs
Ember.Select.reopen({
classNames: ['form-control']
});
Ember.EasyForm.Config.registerTemplate('form-fields/input', container.lookup('template:form-fields/input'));
Ember.EasyForm.Config.registerWrapper('default', {
inputTemplate: 'form-fields/input',
labelClass: 'control-label',
inputClass: 'form-group',
buttonClass: 'btn btn-primary',
fieldErrorClass: 'has-error',
errorClass: 'help-block'
});
}
};
In the initializer, you'll notice that we are pointing to a custom template for the input class. This template will allow us to use less verbose markup while maintaining the conventions expected by bootstrap.
// app/templates/form-fields/input.hbs
{{#unless view.isCheckbox}}
{{label-field propertyBinding="view.property" textBinding="view.label"}}
{{/unless}}
<div {{bind-attr class=view.divWrapperClass}}>
{{#unless view.isCheckbox}}
{{input-field propertyBinding='view.property' inputOptionsBinding='view.inputOptionsValues'}}
{{/unless}}
{{#if view.isCheckbox}}
<label>
{{input-field propertyBinding='view.property' inputOptionsBinding='view.inputOptionsValues'}}
{{view.label}}
</label>
{{/if}}
{{#if view.hint}}
{{hint-field propertyBinding="view.property" textBinding="view.hint"}}
{{/if}}
{{#if view.showError}}
{{error-field propertyBinding="view.property"}}
{{/if}}
</div>
Because we've altered the default form wrapper, we should be able to write standard forms.
<h3>New Thing</h3>
{{#form-for model}}
{{input title}}
{{input shortDescription}}
{{input longDescription}}
{{submit}}
{{/form-for}}