diff --git a/addon/components/bs-form/element.js b/addon/components/bs-form/element.js
index 675ce97..d7c3339 100755
--- a/addon/components/bs-form/element.js
+++ b/addon/components/bs-form/element.js
@@ -1,14 +1,38 @@
import BsFormElement from 'ember-bootstrap/components/bs-form/element';
import { action, get } from '@ember/object';
import { dependentKeyCompat } from '@ember/object/compat';
+import { isNone, typeOf } from '@ember/utils';
export default class BsFormElementWithChangesetValidationsSupport extends BsFormElement {
'__ember-bootstrap_subclass' = true;
+ // We convert
+ //
+ // `model.error.${this.property}.validation` which could be either a string or an array
+ // see https://github.com/validated-changeset/validated-changeset/#error
+ //
+ // into
+ //
+ // Ember Bootstrap expects errors property of FormElement to be an array of validation messages:
+ // see https://www.ember-bootstrap.com/api/classes/Components.FormElement.html#property_errors
+ //
+ // If the if the property is valid but no validation is present `model.error.[this.property] could also be undefined.
@dependentKeyCompat
get errors() {
- let error = get(this, `model.error.${this.property}.validation`);
- return error ? [error] : [];
+ let errors = get(this, `model.error.${this.property}.validation`);
+
+ // no messages
+ if (isNone(errors)) {
+ return [];
+ }
+
+ // a single messages
+ if (typeOf(errors) === 'string') {
+ return [errors];
+ }
+
+ // assume it's an array of messages
+ return errors;
}
get hasValidator() {
diff --git a/tests/integration/components/bs-form-element-test.js b/tests/integration/components/bs-form-element-test.js
index 9637a95..f859ba2 100755
--- a/tests/integration/components/bs-form-element-test.js
+++ b/tests/integration/components/bs-form-element-test.js
@@ -1,6 +1,6 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
-import { render, triggerEvent, fillIn, focus, blur } from '@ember/test-helpers';
+import { render, triggerEvent, fillIn, focus, blur, findAll } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import {
validatePresence,
@@ -213,8 +213,110 @@ module('Integration | Component | bs form element', function(hooks) {
assert.dom('input').doesNotHaveClass('is-invalid');
await triggerEvent('form', 'submit');
- assert.dom('input').doesNotHaveClass('is-valid');
- assert.dom('input').doesNotHaveClass('is-invalid');
+ assert.dom('input')
+ .doesNotHaveClass('is-valid');
+ assert.dom('input')
+ .doesNotHaveClass('is-invalid');
assert.verifySteps(['submit action has been called']);
});
+
+ test('invalid-feedback is shown from single validation', async function (assert) {
+ let model = {
+ name: '',
+ };
+
+ this.set('model', model);
+ this.set('validation', {
+ name: validatePresence(true)
+ });
+
+ await render(hbs`
+
+
+
+ `);
+
+ await triggerEvent('form', 'submit');
+ assert.dom('.invalid-feedback')
+ .hasText('Name can\'t be blank');
+ });
+
+ test('invalid-feedback is shown in order from multiple validations', async function (assert) {
+ let model = {
+ name: '',
+ };
+
+ this.set('model', model);
+ this.set('validation', {
+ name: [
+ validatePresence(true),
+ validateLength({ min: 4 })
+ ]
+ });
+
+ await render(hbs`
+
+
+
+ `);
+
+ await triggerEvent('form', 'submit');
+ assert.dom('.invalid-feedback')
+ .hasText('Name can\'t be blank');
+
+ await fillIn('input', 'R');
+ await triggerEvent('form', 'submit');
+ assert.dom('.invalid-feedback')
+ .hasText('Name is too short (minimum is 4 characters)');
+ });
+
+ test('invalid-feedback is shown (multiple messages) in order from multiple validations', async function (assert) {
+ let model = {
+ name: '',
+ };
+
+ this.set('model', model);
+ this.set('validation', {
+ name: [
+ validatePresence(true),
+ validateLength({ min: 4 })
+ ]
+ });
+
+ await render(hbs`
+
+
+
+ `);
+
+ await triggerEvent('form', 'submit');
+
+ let feedbackElements = findAll('.invalid-feedback');
+ let results = Array.from(feedbackElements, element => element.textContent.trim())
+ let expected = ["Name can't be blank", "Name is too short (minimum is 4 characters)"];
+
+ expected.forEach((message) => {
+ assert.ok(results.includes(message))
+ })
+ });
+
+ test('no feedback is shown for nonexistant validations', async function (assert) {
+ let model = {
+ name: '',
+ };
+
+ this.set('model', model);
+ this.set('validation', {
+ nombre: validatePresence(true)
+ });
+
+ await render(hbs`
+
+
+
+ `);
+
+ await triggerEvent('form', 'submit');
+ assert.dom('.invalid-feedback').doesNotExist();
+ });
});