diff --git a/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.js b/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.js index 1ff70c6c1..49a70d5ea 100644 --- a/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.js +++ b/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.js @@ -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(); diff --git a/Packages/ohif-core/both/schema.js b/Packages/ohif-core/both/schema.js index ca1d9776e..ea60afe58 100644 --- a/Packages/ohif-core/both/schema.js +++ b/Packages/ohif-core/both/schema.js @@ -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]"' +}); diff --git a/Packages/ohif-core/client/components/base/mixins/form.js b/Packages/ohif-core/client/components/base/mixins/form.js index 28d5eb64c..d25ada047 100644 --- a/Packages/ohif-core/client/components/base/mixins/form.js +++ b/Packages/ohif-core/client/components/base/mixins/form.js @@ -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, `${label}`); + result.push({ + key: item.name, + message: Spacebars.SafeString(message) + }); + }); + + // Return the resulting validation errors + return result; + } + } } } }); diff --git a/Packages/ohif-core/client/components/base/mixins/formItem.js b/Packages/ohif-core/client/components/base/mixins/formItem.js index 378b609dc..1580ebae9 100644 --- a/Packages/ohif-core/client/components/base/mixins/formItem.js +++ b/Packages/ohif-core/client/components/base/mixins/formItem.js @@ -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: { diff --git a/Packages/ohif-core/client/components/base/templates/div.html b/Packages/ohif-core/client/components/base/templates/div.html index b628f9c1e..a39733ce3 100644 --- a/Packages/ohif-core/client/components/base/templates/div.html +++ b/Packages/ohif-core/client/components/base/templates/div.html @@ -2,7 +2,6 @@
{{>UI.contentBlock}} diff --git a/Packages/ohif-core/client/components/base/templates/form.html b/Packages/ohif-core/client/components/base/templates/form.html index b198b345b..e5a4e0e4a 100644 --- a/Packages/ohif-core/client/components/base/templates/form.html +++ b/Packages/ohif-core/client/components/base/templates/form.html @@ -11,6 +11,13 @@ target="{{this.target}}" {{this.tagAttributes}} > + {{#if validationErrors}} + + {{/if}} {{>UI.contentBlock}} diff --git a/Packages/ohif-core/client/components/base/templates/input.html b/Packages/ohif-core/client/components/base/templates/input.html index 1c75a95c2..847826cef 100644 --- a/Packages/ohif-core/client/components/base/templates/input.html +++ b/Packages/ohif-core/client/components/base/templates/input.html @@ -6,7 +6,6 @@ name="{{this.name}}" value="{{reactive this.value}}" placeholder="{{this.placeholder}}" - data-key="{{this.pathKey}}" {{this.tagAttributes}} > {{>UI.contentBlock}} diff --git a/Packages/ohif-core/client/components/base/templates/select.html b/Packages/ohif-core/client/components/base/templates/select.html index 148827e2b..938b3d9be 100644 --- a/Packages/ohif-core/client/components/base/templates/select.html +++ b/Packages/ohif-core/client/components/base/templates/select.html @@ -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}} diff --git a/Packages/worklist/both/schema.js b/Packages/worklist/both/schema.js index 6443e3d7d..1ce640523 100644 --- a/Packages/worklist/both/schema.js +++ b/Packages/worklist/both/schema.js @@ -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,