Commit 6ba1c321 authored by Dheeraj Joshi's avatar Dheeraj Joshi

Add support for nested elements to Validation directive

Validation directive can now be used with GlInputGroup
and similar other grouped components
parent 5885a1c4
...@@ -33,6 +33,10 @@ const focusFirstInvalidInput = (e) => { ...@@ -33,6 +33,10 @@ const focusFirstInvalidInput = (e) => {
} }
}; };
const getInputElement = (el) => {
return el.querySelector('input') || el;
};
const isEveryFieldValid = (form) => Object.values(form.fields).every(({ state }) => state === true); const isEveryFieldValid = (form) => Object.values(form.fields).every(({ state }) => state === true);
const createValidator = (context, feedbackMap) => ({ el, reportInvalidInput = false }) => { const createValidator = (context, feedbackMap) => ({ el, reportInvalidInput = false }) => {
...@@ -91,8 +95,9 @@ export default function initValidation(customFeedbackMap = {}) { ...@@ -91,8 +95,9 @@ export default function initValidation(customFeedbackMap = {}) {
const elDataMap = new WeakMap(); const elDataMap = new WeakMap();
return { return {
inserted(el, binding, { context }) { inserted(element, binding, { context }) {
const { arg: showGlobalValidation } = binding; const { arg: showGlobalValidation } = binding;
const el = getInputElement(element);
const { form: formEl } = el; const { form: formEl } = el;
const validate = createValidator(context, feedbackMap); const validate = createValidator(context, feedbackMap);
...@@ -121,7 +126,8 @@ export default function initValidation(customFeedbackMap = {}) { ...@@ -121,7 +126,8 @@ export default function initValidation(customFeedbackMap = {}) {
validate({ el, reportInvalidInput: showGlobalValidation }); validate({ el, reportInvalidInput: showGlobalValidation });
}, },
update(el, binding) { update(element, binding) {
const el = getInputElement(element);
const { arg: showGlobalValidation } = binding; const { arg: showGlobalValidation } = binding;
const { validate, isTouched, isBlurred } = elDataMap.get(el); const { validate, isTouched, isBlurred } = elDataMap.get(el);
const showValidationFeedback = showGlobalValidation || (isTouched && isBlurred); const showValidationFeedback = showGlobalValidation || (isTouched && isBlurred);
......
...@@ -4,12 +4,18 @@ import validation from '~/vue_shared/directives/validation'; ...@@ -4,12 +4,18 @@ import validation from '~/vue_shared/directives/validation';
describe('validation directive', () => { describe('validation directive', () => {
let wrapper; let wrapper;
const createComponent = ({ inputAttributes, showValidation } = {}) => { const createComponent = ({ inputAttributes, showValidation, template } = {}) => {
const defaultInputAttributes = { const defaultInputAttributes = {
type: 'text', type: 'text',
required: true, required: true,
}; };
const defaultTemplate = `
<form>
<input v-validation:[showValidation] name="exampleField" v-bind="attributes" />
</form>
`;
const component = { const component = {
directives: { directives: {
validation: validation(), validation: validation(),
...@@ -29,11 +35,7 @@ describe('validation directive', () => { ...@@ -29,11 +35,7 @@ describe('validation directive', () => {
}, },
}; };
}, },
template: ` template: template || defaultTemplate,
<form>
<input v-validation:[showValidation] name="exampleField" v-bind="attributes" />
</form>
`,
}; };
wrapper = shallowMount(component, { attachTo: document.body }); wrapper = shallowMount(component, { attachTo: document.body });
...@@ -48,6 +50,12 @@ describe('validation directive', () => { ...@@ -48,6 +50,12 @@ describe('validation directive', () => {
const findForm = () => wrapper.find('form'); const findForm = () => wrapper.find('form');
const findInput = () => wrapper.find('input'); const findInput = () => wrapper.find('input');
const setValueAndTriggerValidation = (value) => {
const input = findInput();
input.setValue(value);
input.trigger('blur');
};
describe.each([true, false])( describe.each([true, false])(
'with fields untouched and "showValidation" set to "%s"', 'with fields untouched and "showValidation" set to "%s"',
(showValidation) => { (showValidation) => {
...@@ -78,12 +86,6 @@ describe('validation directive', () => { ...@@ -78,12 +86,6 @@ describe('validation directive', () => {
`( `(
'with input-attributes set to $inputAttributes', 'with input-attributes set to $inputAttributes',
({ inputAttributes, validValue, invalidValue }) => { ({ inputAttributes, validValue, invalidValue }) => {
const setValueAndTriggerValidation = (value) => {
const input = findInput();
input.setValue(value);
input.trigger('blur');
};
beforeEach(() => { beforeEach(() => {
createComponent({ inputAttributes }); createComponent({ inputAttributes });
}); });
...@@ -129,4 +131,52 @@ describe('validation directive', () => { ...@@ -129,4 +131,52 @@ describe('validation directive', () => {
}); });
}, },
); );
describe('with group elements', () => {
const template = `
<form>
<div v-validation:[showValidation]>
<input name="exampleField" v-bind="attributes" />
</div>
</form>
`;
beforeEach(() => {
createComponent({
template,
inputAttributes: {
required: true,
},
});
});
describe('with invalid value', () => {
beforeEach(() => {
setValueAndTriggerValidation('');
});
it('should set correct field state', () => {
expect(getFormData().fields.exampleField).toEqual({
state: false,
feedback: expect.any(String),
});
});
it('should set correct feedback', () => {
expect(getFormData().fields.exampleField.feedback).toBe('Please fill out this field.');
});
});
describe('with valid value', () => {
beforeEach(() => {
setValueAndTriggerValidation('hello');
});
it('set the correct state', () => {
expect(getFormData().fields.exampleField).toEqual({
state: true,
feedback: '',
});
});
});
});
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment