LT-67: Displaying the validation error messages inside the form

This commit is contained in:
Bruno Alves de Faria 2016-08-31 19:17:00 -03:00
parent a47ecf0aac
commit 33e7297064
9 changed files with 84 additions and 8 deletions

View File

@ -19,7 +19,7 @@ Template.serverInformationForm.onRendered(() => {
// Handle the server type
instance.autorun(() => {
// Get the server type component
const typeComponent = instance.$('[data-key=type]').data('component');
const typeComponent = instance.$('[data-key=type] :input').data('component');
// Run this computation every time the user change the server type
typeComponent.depend();

View File

@ -25,3 +25,10 @@ SimpleSchema.addValidator(function() {
return 'required';
}
});
// Including [label] for some messages
SimpleSchema.messages({
maxCount: '[label] can not have more than [maxCount] values',
minCount: '[label] must have at least [minCount] values',
notAllowed: '[label] has an invalid value: "[value]"'
});

View File

@ -1,6 +1,8 @@
import { OHIF } from 'meteor/ohif:core';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';
/*
* form: controls a form and its registered inputs
@ -15,8 +17,16 @@ OHIF.mixins.form = new OHIF.Mixin({
// Set the form identifier flag
component.isForm = true;
component.validationObserver = new Tracker.Dependency();
// Reset the pathKey
instance.data.pathKey = '';
// Debound the observer call to prevent tons of re-rendering
component.validationRan = _.debounce(() => {
// Enable reactivity by changing a Tracker.Dependency observer
component.validationObserver.changed();
}, 200);
},
onRendered() {
@ -25,6 +35,50 @@ OHIF.mixins.form = new OHIF.Mixin({
// Set the component main and style elements
component.$style = component.$element = instance.$('form:first');
},
events: {
'click .validation-error-container a'(event, instance) {
// Get the target key
const targetKey = $(event.currentTarget).attr('data-target');
// Focus the first input inside the element with error state
instance.$(`.state-error[data-key="${targetKey}"] :input:first`).focus();
}
},
helpers: {
validationErrors() {
const instance = Template.instance();
const component = instance.component;
// Create a dependency on child components validation
component.validationObserver.depend();
// Stop here if no schema was defined for the form
if (!component.schema) {
return;
}
// Check if there were some validation errors
if (component.schema._invalidKeys.length) {
const result = [];
// Iterate over each validation error and add to result
component.schema._invalidKeys.forEach(item => {
const label = component.schema._schema[item.name].label;
let message = component.schema.keyErrorMessage(item.name);
message = message.replace(label, `<strong>${label}</strong>`);
result.push({
key: item.name,
message: Spacebars.SafeString(message)
});
});
// Return the resulting validation errors
return result;
}
}
}
}
});

View File

@ -105,8 +105,14 @@ OHIF.mixins.formItem = new OHIF.Mixin({
[key]: component.value()
});
// Get the validation result
const validationResult = schema.validateOne(document, key);
// Notify the form that the validation ran
form.validationRan();
// Check if the document validation failed
if (!schema.validateOne(document, key)) {
if (!validationResult) {
// Set the component in error state and display the message
component.error(schema.keyErrorMessage(key));
@ -136,6 +142,9 @@ OHIF.mixins.formItem = new OHIF.Mixin({
// Set the most outer wrapper element
component.$wrapper = instance.wrapper.$('*').first();
// Add the pathKey to the wrapper element
component.$wrapper.attr('data-key', instance.data.pathKey);
},
onDestroyed() {
@ -154,8 +163,9 @@ OHIF.mixins.formItem = new OHIF.Mixin({
component.$style = component.$element;
}
// Set the component in jQuery data after all mixins are rendered
// Set the component in element and wrapper jQuery data
component.$element.data('component', component);
component.$wrapper.data('component', component);
},
events: {

View File

@ -2,7 +2,6 @@
<div
id="{{this.id}}"
class="{{this.class}}"
data-key="{{this.pathKey}}"
{{this.tagAttributes}}
>
{{>UI.contentBlock}}

View File

@ -11,6 +11,13 @@
target="{{this.target}}"
{{this.tagAttributes}}
>
{{#if validationErrors}}
<div class="validation-error-container alert alert-danger" role="alert">
{{#each error in validationErrors}}
<p><a href="#" class="text-danger" data-target="{{error.key}}">{{error.message}}</a></p>
{{/each}}
</div>
{{/if}}
{{>UI.contentBlock}}
</form>
</template>

View File

@ -6,7 +6,6 @@
name="{{this.name}}"
value="{{reactive this.value}}"
placeholder="{{this.placeholder}}"
data-key="{{this.pathKey}}"
{{this.tagAttributes}}
>
{{>UI.contentBlock}}

View File

@ -5,7 +5,6 @@
name="{{this.name}}"
multiple="{{#if this.multiple}}multiple{{/if}}"
disabled="{{#if this.disabled}}disabled{{/if}}"
data-key="{{this.pathKey}}"
{{this.tagAttributes}}
>
{{>UI.contentBlock}}

View File

@ -90,7 +90,8 @@ export const DIMSEPeer = new SimpleSchema({
},
host: {
type: String,
label: 'Host Domain/IP'
label: 'Host Domain/IP',
regEx: SimpleSchema.RegEx.WeakDomain
},
port: {
type: Number,