feat(field): align (pre)filled and empty, fix filled not working
BREAKING: _isPrefilled was removed in favor of _isEmpty. We used to have both, but we decided to align, because they basically do the same thing but opposite. If you were using _isPrefilled, switch to using _isEmpty and just use it in reverse. This change also makes _isEmpty available to all things that implement FormControlMixin. Lastly, filled is available now on all fields that implement InteractionStateMixin
This commit is contained in:
parent
10bac5672b
commit
e397f8d68b
12 changed files with 94 additions and 95 deletions
|
|
@ -95,15 +95,14 @@ export const ChoiceGroupMixin = dedupeMixin(
|
||||||
}
|
}
|
||||||
|
|
||||||
_isEmpty() {
|
_isEmpty() {
|
||||||
const value = this.modelValue;
|
|
||||||
if (this.multipleChoice) {
|
if (this.multipleChoice) {
|
||||||
return this.modelValue.length === 0;
|
return this.modelValue.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof value === 'string' && value === '') {
|
if (typeof this.modelValue === 'string' && this.modelValue === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (value === undefined || value === null) {
|
if (this.modelValue === undefined || this.modelValue === null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable class-methods-use-this */
|
/* eslint-disable class-methods-use-this */
|
||||||
|
|
||||||
import { html, css, nothing } from '@lion/core';
|
import { css, html, nothing } from '@lion/core';
|
||||||
import { FormatMixin } from '@lion/field';
|
import { FormatMixin } from '@lion/field';
|
||||||
|
|
||||||
export const ChoiceInputMixin = superclass =>
|
export const ChoiceInputMixin = superclass =>
|
||||||
|
|
@ -151,16 +151,6 @@ export const ChoiceInputMixin = superclass =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* Override InteractionStateMixin
|
|
||||||
* 'prefilled' should be false when modelValue is { checked: false }, which would return
|
|
||||||
* true in original method (since non-empty objects are considered prefilled by default).
|
|
||||||
*/
|
|
||||||
static _isPrefilled(modelValue) {
|
|
||||||
return modelValue.checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* This method is overridden from FormatMixin. It originally fired the normalizing
|
* This method is overridden from FormatMixin. It originally fired the normalizing
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { html, css, nothing, dedupeMixin, SlotMixin } from '@lion/core';
|
import { css, dedupeMixin, html, nothing, SlotMixin } from '@lion/core';
|
||||||
|
import { Unparseable } from '@lion/validate';
|
||||||
import { FormRegisteringMixin } from './registration/FormRegisteringMixin.js';
|
import { FormRegisteringMixin } from './registration/FormRegisteringMixin.js';
|
||||||
import { getAriaElementsInRightDomOrder } from './utils/getAriaElementsInRightDomOrder.js';
|
import { getAriaElementsInRightDomOrder } from './utils/getAriaElementsInRightDomOrder.js';
|
||||||
|
|
||||||
|
|
@ -392,6 +393,25 @@ export const FormControlMixin = dedupeMixin(
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isEmpty(modelValue = this.modelValue) {
|
||||||
|
let value = modelValue;
|
||||||
|
if (this.modelValue instanceof Unparseable) {
|
||||||
|
value = this.modelValue.viewValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for empty platform types: Objects, Arrays, Dates
|
||||||
|
if (typeof value === 'object' && value !== null && !(value instanceof Date)) {
|
||||||
|
return !Object.keys(value).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-mixed-operators
|
||||||
|
// Checks for empty platform types: Numbers, Booleans
|
||||||
|
const isNumberValue = typeof value === 'number' && (value === 0 || Number.isNaN(value));
|
||||||
|
const isBooleanValue = typeof value === 'boolean' && value === false;
|
||||||
|
|
||||||
|
return !value && !isNumberValue && !isBooleanValue;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
_feedbackTemplate() {
|
_feedbackTemplate() {
|
||||||
return html`
|
return html`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { dedupeMixin } from '@lion/core';
|
import { dedupeMixin } from '@lion/core';
|
||||||
import { Unparseable } from '@lion/validate';
|
import { FormControlMixin } from './FormControlMixin.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc `InteractionStateMixin` adds meta information about touched and dirty states, that can
|
* @desc `InteractionStateMixin` adds meta information about touched and dirty states, that can
|
||||||
|
|
@ -14,7 +14,7 @@ import { Unparseable } from '@lion/validate';
|
||||||
export const InteractionStateMixin = dedupeMixin(
|
export const InteractionStateMixin = dedupeMixin(
|
||||||
superclass =>
|
superclass =>
|
||||||
// eslint-disable-next-line no-unused-vars, no-shadow
|
// eslint-disable-next-line no-unused-vars, no-shadow
|
||||||
class InteractionStateMixin extends superclass {
|
class InteractionStateMixin extends FormControlMixin(superclass) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
|
|
@ -31,6 +31,13 @@ export const InteractionStateMixin = dedupeMixin(
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
reflect: true,
|
reflect: true,
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* True when the modelValue is non-empty (see _isEmpty in FormControlMixin)
|
||||||
|
*/
|
||||||
|
filled: {
|
||||||
|
type: Boolean,
|
||||||
|
reflect: true,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* True when user has left non-empty field or input is prefilled.
|
* True when user has left non-empty field or input is prefilled.
|
||||||
* The name must be seen from the point of view of the input field:
|
* The name must be seen from the point of view of the input field:
|
||||||
|
|
@ -55,36 +62,25 @@ export const InteractionStateMixin = dedupeMixin(
|
||||||
this._onTouchedChanged();
|
this._onTouchedChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name === 'modelValue') {
|
||||||
|
// We do this in _requestUpdate because we don't want to fire another re-render (e.g. when doing this in updated)
|
||||||
|
// Furthermore, we cannot do it on model-value-changed event because it isn't fired initially.
|
||||||
|
this.filled = !this._isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
if (name === 'dirty' && this.dirty !== oldVal) {
|
if (name === 'dirty' && this.dirty !== oldVal) {
|
||||||
this._onDirtyChanged();
|
this._onDirtyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static _isPrefilled(modelValue) {
|
|
||||||
let value = modelValue;
|
|
||||||
if (modelValue instanceof Unparseable) {
|
|
||||||
value = modelValue.viewValue;
|
|
||||||
}
|
|
||||||
// Checks for empty platform types: Objects, Arrays, Dates
|
|
||||||
if (typeof value === 'object' && value !== null && !(value instanceof Date)) {
|
|
||||||
return !!Object.keys(value).length;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-mixed-operators
|
|
||||||
// Checks for empty platform types: Numbers, Booleans
|
|
||||||
const isNumberValue = typeof value === 'number' && (value === 0 || Number.isNaN(value));
|
|
||||||
const isBooleanValue = typeof value === 'boolean' && value === false;
|
|
||||||
|
|
||||||
return !!value || isNumberValue || isBooleanValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.touched = false;
|
this.touched = false;
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
this.prefilled = false;
|
this.prefilled = false;
|
||||||
|
this.filled = false;
|
||||||
this._leaveEvent = 'blur';
|
this._leaveEvent = 'blur';
|
||||||
this._valueChangedEvent = 'model-value-changed';
|
this._valueChangedEvent = 'model-value-changed';
|
||||||
|
|
||||||
this._iStateOnLeave = this._iStateOnLeave.bind(this);
|
this._iStateOnLeave = this._iStateOnLeave.bind(this);
|
||||||
this._iStateOnValueChange = this._iStateOnValueChange.bind(this);
|
this._iStateOnValueChange = this._iStateOnValueChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
@ -118,23 +114,23 @@ export const InteractionStateMixin = dedupeMixin(
|
||||||
*/
|
*/
|
||||||
initInteractionState() {
|
initInteractionState() {
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
this.prefilled = this.constructor._isPrefilled(this.modelValue);
|
this.prefilled = !this._isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets touched value to true
|
* Sets touched value to true
|
||||||
* Reevaluates prefilled state.
|
* Reevaluates prefilled state.
|
||||||
* When false, on next interaction, user will start with a clean state.
|
* When false, on next interaction, user will start with a clean state.
|
||||||
* @private
|
* @protected
|
||||||
*/
|
*/
|
||||||
_iStateOnLeave() {
|
_iStateOnLeave() {
|
||||||
this.touched = true;
|
this.touched = true;
|
||||||
this.prefilled = this.constructor._isPrefilled(this.modelValue);
|
this.prefilled = !this._isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets dirty value and validates when already touched or invalid
|
* Sets dirty value and validates when already touched or invalid
|
||||||
* @private
|
* @protected
|
||||||
*/
|
*/
|
||||||
_iStateOnValueChange() {
|
_iStateOnValueChange() {
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
@ -146,7 +142,7 @@ export const InteractionStateMixin = dedupeMixin(
|
||||||
resetInteractionState() {
|
resetInteractionState() {
|
||||||
this.touched = false;
|
this.touched = false;
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
this.prefilled = this.constructor._isPrefilled(this.modelValue);
|
this.prefilled = !this._isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTouchedChanged() {
|
_onTouchedChanged() {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { SlotMixin, LitElement } from '@lion/core';
|
import { LitElement, SlotMixin } from '@lion/core';
|
||||||
import { DisabledMixin } from '@lion/core/src/DisabledMixin.js';
|
import { DisabledMixin } from '@lion/core/src/DisabledMixin.js';
|
||||||
import { ValidateMixin } from '@lion/validate';
|
import { ValidateMixin } from '@lion/validate';
|
||||||
|
import { FocusMixin } from './FocusMixin.js';
|
||||||
|
import { FormatMixin } from './FormatMixin.js';
|
||||||
import { FormControlMixin } from './FormControlMixin.js';
|
import { FormControlMixin } from './FormControlMixin.js';
|
||||||
import { InteractionStateMixin } from './InteractionStateMixin.js'; // applies FocusMixin
|
import { InteractionStateMixin } from './InteractionStateMixin.js'; // applies FocusMixin
|
||||||
import { FormatMixin } from './FormatMixin.js';
|
|
||||||
import { FocusMixin } from './FocusMixin.js';
|
|
||||||
|
|
||||||
/* eslint-disable wc/guard-super-call */
|
/* eslint-disable wc/guard-super-call */
|
||||||
|
|
||||||
|
|
@ -80,7 +80,6 @@ export class LionField extends FormControlMixin(
|
||||||
if (this._inputNode) {
|
if (this._inputNode) {
|
||||||
this._setValueAndPreserveCaret(value);
|
this._setValueAndPreserveCaret(value);
|
||||||
}
|
}
|
||||||
this._onValueChanged({ value });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get value() {
|
get value() {
|
||||||
|
|
@ -107,7 +106,6 @@ export class LionField extends FormControlMixin(
|
||||||
// FormatMixin
|
// FormatMixin
|
||||||
this._delegateInitialValueAttr();
|
this._delegateInitialValueAttr();
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
|
||||||
this._onChange = this._onChange.bind(this);
|
this._onChange = this._onChange.bind(this);
|
||||||
this._inputNode.addEventListener('change', this._onChange);
|
this._inputNode.addEventListener('change', this._onChange);
|
||||||
this.classList.add('form-field'); // eslint-disable-line
|
this.classList.add('form-field'); // eslint-disable-line
|
||||||
|
|
@ -178,16 +176,6 @@ export class LionField extends FormControlMixin(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onValueChanged({ value }) {
|
|
||||||
if (super._onValueChanged) {
|
|
||||||
super._onValueChanged();
|
|
||||||
}
|
|
||||||
// For styling purposes, make it known the input field is not empty
|
|
||||||
if (this._inputNode) {
|
|
||||||
this[value ? 'setAttribute' : 'removeAttribute']('filled', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the cursor to its original position after updating the value.
|
* Restores the cursor to its original position after updating the value.
|
||||||
* @param {string} newValue The value that should be saved.
|
* @param {string} newValue The value that should be saved.
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,8 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
|
|
||||||
set modelValue(v) {
|
set modelValue(v) {
|
||||||
this._modelValue = v;
|
this._modelValue = v;
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(new CustomEvent('model-value-changed', { bubbles: true }));
|
||||||
new CustomEvent('model-value-changed', { bubbles: true, composed: true }),
|
this.requestUpdate('modelValue');
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get modelValue() {
|
get modelValue() {
|
||||||
|
|
@ -80,6 +79,17 @@ export function runInteractionStateMixinSuite(customConfig) {
|
||||||
expect(el.hasAttribute('dirty')).to.be.true;
|
expect(el.hasAttribute('dirty')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets an attribute "filled" if the input has a non-empty modelValue', async () => {
|
||||||
|
const el = await fixture(html`<${tag} .modelValue=${'hello'}></${tag}>`);
|
||||||
|
expect(el.hasAttribute('filled')).to.equal(true);
|
||||||
|
el.modelValue = '';
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.hasAttribute('filled')).to.equal(false);
|
||||||
|
el.modelValue = 'foo';
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.hasAttribute('filled')).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
|
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
|
||||||
const touchedSpy = sinon.spy();
|
const touchedSpy = sinon.spy();
|
||||||
const dirtySpy = sinon.spy();
|
const dirtySpy = sinon.spy();
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
|
import { unsafeHTML } from '@lion/core';
|
||||||
|
import { localize } from '@lion/localize';
|
||||||
|
import { localizeTearDown } from '@lion/localize/test-helpers.js';
|
||||||
|
import { Required, Validator } from '@lion/validate';
|
||||||
import {
|
import {
|
||||||
|
aTimeout,
|
||||||
expect,
|
expect,
|
||||||
fixture,
|
fixture,
|
||||||
html,
|
html,
|
||||||
unsafeStatic,
|
|
||||||
triggerFocusFor,
|
|
||||||
triggerBlurFor,
|
triggerBlurFor,
|
||||||
aTimeout,
|
triggerFocusFor,
|
||||||
|
unsafeStatic,
|
||||||
} from '@open-wc/testing';
|
} from '@open-wc/testing';
|
||||||
import { unsafeHTML } from '@lion/core';
|
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { Validator, Required } from '@lion/validate';
|
|
||||||
import { localize } from '@lion/localize';
|
|
||||||
import { localizeTearDown } from '@lion/localize/test-helpers.js';
|
|
||||||
|
|
||||||
import '../lion-field.js';
|
import '../lion-field.js';
|
||||||
|
|
||||||
const tagString = 'lion-field';
|
const tagString = 'lion-field';
|
||||||
|
|
@ -153,17 +152,6 @@ describe('<lion-field>', () => {
|
||||||
expect(el._inputNode.getAttribute('autocomplete')).to.equal('off');
|
expect(el._inputNode.getAttribute('autocomplete')).to.equal('off');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has an attribute filled if this.value is filled', async () => {
|
|
||||||
const el = await fixture(html`<${tag} value="filled">${inputSlot}</${tag}>`);
|
|
||||||
expect(el.hasAttribute('filled')).to.equal(true);
|
|
||||||
el.value = '';
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.hasAttribute('filled')).to.equal(false);
|
|
||||||
el.value = 'bla';
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.hasAttribute('filled')).to.equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('preserves the caret position on value change for native text fields (input|textarea)', async () => {
|
it('preserves the caret position on value change for native text fields (input|textarea)', async () => {
|
||||||
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
const el = await fixture(html`<${tag}>${inputSlot}</${tag}>`);
|
||||||
await triggerFocusFor(el);
|
await triggerFocusFor(el);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { html, dedupeMixin, SlotMixin } from '@lion/core';
|
import { dedupeMixin, html, SlotMixin } from '@lion/core';
|
||||||
import { DisabledMixin } from '@lion/core/src/DisabledMixin.js';
|
import { DisabledMixin } from '@lion/core/src/DisabledMixin.js';
|
||||||
import { FormControlMixin, FormRegistrarMixin, FormControlsCollection } from '@lion/field';
|
import { FormControlMixin, FormControlsCollection, FormRegistrarMixin } from '@lion/field';
|
||||||
import { getAriaElementsInRightDomOrder } from '@lion/field/src/utils/getAriaElementsInRightDomOrder.js';
|
import { getAriaElementsInRightDomOrder } from '@lion/field/src/utils/getAriaElementsInRightDomOrder.js';
|
||||||
import { ValidateMixin } from '@lion/validate';
|
import { ValidateMixin } from '@lion/validate';
|
||||||
import { FormElementsHaveNoError } from './FormElementsHaveNoError.js';
|
import { FormElementsHaveNoError } from './FormElementsHaveNoError.js';
|
||||||
|
|
@ -361,7 +361,7 @@ export const FormGroupMixin = dedupeMixin(
|
||||||
}
|
}
|
||||||
// TODO: Unlink in removeFormElement
|
// TODO: Unlink in removeFormElement
|
||||||
this.__linkChildrenMessagesToParent(child);
|
this.__linkChildrenMessagesToParent(child);
|
||||||
this.validate();
|
this.validate({ clearCurrentResult: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -392,7 +392,7 @@ export const FormGroupMixin = dedupeMixin(
|
||||||
*/
|
*/
|
||||||
removeFormElement(...args) {
|
removeFormElement(...args) {
|
||||||
super.removeFormElement(...args);
|
super.removeFormElement(...args);
|
||||||
this.validate();
|
this.validate({ clearCurrentResult: true });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
|
import { LionField } from '@lion/field';
|
||||||
|
import '@lion/field/lion-field.js';
|
||||||
|
import { localizeTearDown } from '@lion/localize/test-helpers.js';
|
||||||
|
import { IsNumber, Validator } from '@lion/validate';
|
||||||
import {
|
import {
|
||||||
|
defineCE,
|
||||||
expect,
|
expect,
|
||||||
fixtureSync,
|
fixtureSync,
|
||||||
html,
|
html,
|
||||||
unsafeStatic,
|
|
||||||
triggerFocusFor,
|
|
||||||
nextFrame,
|
nextFrame,
|
||||||
defineCE,
|
triggerFocusFor,
|
||||||
|
unsafeStatic,
|
||||||
} from '@open-wc/testing';
|
} from '@open-wc/testing';
|
||||||
import { formFixture as fixture } from '@lion/field/test-helpers.js';
|
import { formFixture as fixture } from '@lion/field/test-helpers.js';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { Validator, IsNumber } from '@lion/validate';
|
|
||||||
import { localizeTearDown } from '@lion/localize/test-helpers.js';
|
|
||||||
import '../lion-fieldset.js';
|
import '../lion-fieldset.js';
|
||||||
import { LionField } from '@lion/field';
|
|
||||||
import '@lion/field/lion-field.js';
|
|
||||||
|
|
||||||
const childTagString = defineCE(
|
const childTagString = defineCE(
|
||||||
class extends LionField {
|
class extends LionField {
|
||||||
|
|
@ -434,6 +434,7 @@ describe('<lion-fieldset>', () => {
|
||||||
// Edge case: remove all children
|
// Edge case: remove all children
|
||||||
el.removeChild(el.querySelector('[id=c1]'));
|
el.removeChild(el.querySelector('[id=c1]'));
|
||||||
await nextFrame();
|
await nextFrame();
|
||||||
|
|
||||||
expect(el.validationStates.error.HasEvenNumberOfChildren).to.equal(undefined);
|
expect(el.validationStates.error.HasEvenNumberOfChildren).to.equal(undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ The example below shows how this is done for checkboxes/radio-inputs.
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
static _isPrefilled(modelValue) {
|
_isEmpty() {
|
||||||
return modelValue.checked;
|
return !this.checked;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable class-methods-use-this, camelcase, no-param-reassign, max-classes-per-file */
|
/* eslint-disable class-methods-use-this, camelcase, no-param-reassign, max-classes-per-file */
|
||||||
|
|
||||||
import { dedupeMixin, SlotMixin, ScopedElementsMixin } from '@lion/core';
|
import { dedupeMixin, ScopedElementsMixin, SlotMixin } from '@lion/core';
|
||||||
import { localize } from '@lion/localize';
|
import { localize } from '@lion/localize';
|
||||||
import { LionValidationFeedback } from './LionValidationFeedback.js';
|
import { LionValidationFeedback } from './LionValidationFeedback.js';
|
||||||
import { ResultValidator } from './ResultValidator.js';
|
import { ResultValidator } from './ResultValidator.js';
|
||||||
|
|
@ -307,10 +307,12 @@ export const ValidateMixin = dedupeMixin(
|
||||||
* - the validatity is dependent on the formControl type and therefore determined
|
* - the validatity is dependent on the formControl type and therefore determined
|
||||||
* by the formControl.__isEmpty method. Basically, the Required Validator is a means
|
* by the formControl.__isEmpty method. Basically, the Required Validator is a means
|
||||||
* to trigger formControl.__isEmpty.
|
* to trigger formControl.__isEmpty.
|
||||||
* - when __isEmpty returns false, the input was empty. This means we need to stop
|
* - when __isEmpty returns true, the input was empty. This means we need to stop
|
||||||
* validation here, because all other Validators' execute functions assume the
|
* validation here, because all other Validators' execute functions assume the
|
||||||
* value is not empty (there would be nothing to validate).
|
* value is not empty (there would be nothing to validate).
|
||||||
*/
|
*/
|
||||||
|
// TODO: Try to remove this when we have a single lion form core package, because then we can
|
||||||
|
// depend on FormControlMixin directly, and _isEmpty will always be an existing method on the prototype then
|
||||||
const isEmpty = this.__isEmpty(value);
|
const isEmpty = this.__isEmpty(value);
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
if (requiredValidator) {
|
if (requiredValidator) {
|
||||||
|
|
@ -423,6 +425,7 @@ export const ValidateMixin = dedupeMixin(
|
||||||
validationStates[v.type][v.constructor.name] = true;
|
validationStates[v.type][v.constructor.name] = true;
|
||||||
});
|
});
|
||||||
this.validationStates = validationStates;
|
this.validationStates = validationStates;
|
||||||
|
|
||||||
this.hasFeedbackFor = [...new Set(this.__validationResult.map(v => v.type))];
|
this.hasFeedbackFor = [...new Set(this.__validationResult.map(v => v.type))];
|
||||||
|
|
||||||
/** private event that should be listened to by LionFieldSet */
|
/** private event that should be listened to by LionFieldSet */
|
||||||
|
|
@ -485,7 +488,11 @@ export const ValidateMixin = dedupeMixin(
|
||||||
// if (typeof this.__isRequired === 'function') {
|
// if (typeof this.__isRequired === 'function') {
|
||||||
// return !this.__isRequired(v);
|
// return !this.__isRequired(v);
|
||||||
// }
|
// }
|
||||||
return v === null || typeof v === 'undefined' || v === '';
|
return (
|
||||||
|
this.modelValue === null ||
|
||||||
|
typeof this.modelValue === 'undefined' ||
|
||||||
|
this.modelValue === ''
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -665,8 +665,8 @@ export function runValidateMixinSuite(customConfig) {
|
||||||
it('calls "._isEmpty" when provided (useful for different modelValues)', async () => {
|
it('calls "._isEmpty" when provided (useful for different modelValues)', async () => {
|
||||||
const customRequiredTagString = defineCE(
|
const customRequiredTagString = defineCE(
|
||||||
class extends ValidateMixin(LitElement) {
|
class extends ValidateMixin(LitElement) {
|
||||||
_isEmpty(modelValue) {
|
_isEmpty() {
|
||||||
return modelValue.model === '';
|
return this.modelValue.model === '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue