Skip to content

Commit 33138c7

Browse files
committed
refactor(input): Made validation constraints synchronous
Fixed unit tests
1 parent c90e21a commit 33138c7

File tree

5 files changed

+91
-58
lines changed

5 files changed

+91
-58
lines changed

src/components/common/mixins/forms/associated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ function BaseFormAssociated<T extends Constructor<LitElement>>(base: T) {
145145

146146
protected _restoreDefaultValue(): void {
147147
this._formValue.setValueAndFormState(this._formValue.defaultValue);
148+
this.requestUpdate();
148149
}
149150

150151
protected _validate(message?: string): void {

src/components/input/input.spec.ts

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,16 @@ describe('Input component', () => {
140140
await createFixture(
141141
html`<igc-input type="number" min="3" max="6"></igc-input>`
142142
);
143+
expect([element.min, element.max]).to.eql([3, 6]);
144+
expect([input.min, input.max]).to.eql(['3', '6']);
143145

144-
expect(element.min).to.equal('3');
145-
expect(element.max).to.equal('6');
146-
expect(input.min).to.equal('3');
147-
expect(input.max).to.equal('6');
148-
149-
expect(element.checkValidity()).to.be.false;
146+
expect(element.checkValidity()).to.be.true;
150147

151-
Object.assign(element, { min: '1', max: '2' });
148+
Object.assign(element, { min: 1, max: 2, value: 8 });
152149
await elementUpdated(element);
153150

154-
expect(element.min).to.equal('1');
155-
expect(element.max).to.equal('2');
156-
expect(input.min).to.equal('1');
157-
expect(input.max).to.equal('2');
151+
expect([element.min, element.max]).to.eql([1, 2]);
152+
expect([input.min, input.max]).to.eql(['1', '2']);
158153

159154
expect(element.checkValidity()).to.be.false;
160155
});
@@ -164,26 +159,22 @@ describe('Input component', () => {
164159
html`<igc-input minlength="2" maxlength="4"></igc-input>`
165160
);
166161

167-
expect(element.minLength).to.equal(2);
168-
expect(element.maxLength).to.equal(4);
169-
expect(input.minLength).to.equal(2);
170-
expect(input.maxLength).to.equal(4);
171-
172-
expect(element.checkValidity()).to.be.false;
162+
expect([element.minLength, element.maxLength]).to.eql([2, 4]);
163+
expect([input.minLength, input.maxLength]).to.eql([2, 4]);
164+
expect(element.checkValidity()).to.be.true;
173165

174-
Object.assign(element, { minLength: 1, maxLength: 2 });
166+
Object.assign(element, { minLength: 2, maxLength: 2, value: 'a' });
175167
await elementUpdated(element);
176168

177-
expect(element.minLength).to.equal(1);
178-
expect(element.maxLength).to.equal(2);
179-
expect(input.minLength).to.equal(1);
180-
expect(input.maxLength).to.equal(2);
181-
169+
expect([element.minLength, element.maxLength]).to.eql([2, 2]);
170+
expect([input.minLength, input.maxLength]).to.eql([2, 2]);
182171
expect(element.checkValidity()).to.be.false;
183172
});
184173

185174
it('sets the pattern property', async () => {
186-
await createFixture(html`<igc-input pattern="d{3}"></igc-input>`);
175+
await createFixture(
176+
html`<igc-input pattern="d{3}" value="a"></igc-input>`
177+
);
187178

188179
expect(element.pattern).to.equal('d{3}');
189180
expect(input.pattern).to.equal('d{3}');
@@ -420,7 +411,7 @@ describe('Input component', () => {
420411
});
421412

422413
it('fulfils min value constraint', () => {
423-
spec.setProperties({ type: 'number', min: 3 });
414+
spec.setProperties({ type: 'number', min: 3, value: '2' });
424415
spec.assertSubmitFails();
425416

426417
spec.setProperties({ value: '5' });
@@ -444,7 +435,7 @@ describe('Input component', () => {
444435
});
445436

446437
it('fulfils minimum length constraint', () => {
447-
spec.setProperties({ minLength: 3 });
438+
spec.setProperties({ minLength: 3, value: 'a' });
448439
spec.assertSubmitFails();
449440

450441
spec.setProperties({ value: 'abc' });
@@ -667,15 +658,21 @@ describe('Input component', () => {
667658
const testParameters: ValidationContainerTestsParams<IgcInputComponent>[] =
668659
[
669660
{ slots: ['valueMissing'], props: { required: true } }, // value-missing slot
670-
{ slots: ['typeMismatch'], props: { type: 'email' } }, // type-mismatch slot
671-
{ slots: ['patternMismatch'], props: { pattern: 'd{3}' } }, // pattern-mismatch slot
661+
{ slots: ['typeMismatch'], props: { type: 'email', value: 'a' } }, // type-mismatch slot
662+
{
663+
slots: ['patternMismatch'],
664+
props: { pattern: 'd{3}', value: 'a' },
665+
}, // pattern-mismatch slot
672666
{ slots: ['tooLong'], props: { maxLength: 3, value: '123123' } }, // too-long slot
673-
{ slots: ['tooShort'], props: { minLength: 3 } }, // too-short slot
667+
{ slots: ['tooShort'], props: { minLength: 3, value: 'a' } }, // too-short slot
674668
{
675669
slots: ['rangeOverflow'],
676670
props: { type: 'number', max: 3, value: '5' }, // range-overflow slot
677671
},
678-
{ slots: ['rangeUnderflow'], props: { type: 'number', min: 3 } }, // range-underflow
672+
{
673+
slots: ['rangeUnderflow'],
674+
props: { type: 'number', min: 3, value: '-3' },
675+
}, // range-underflow
679676
{
680677
slots: ['stepMismatch'],
681678
props: { type: 'number', step: 2, value: '3' }, // step-mismatch slot
@@ -684,7 +681,7 @@ describe('Input component', () => {
684681
{ slots: ['invalid'], props: { required: true } }, // invalid slot
685682
{
686683
slots: ['typeMismatch', 'tooShort'],
687-
props: { type: 'email', minLength: 8 }, // multiple validation slots
684+
props: { type: 'email', minLength: 8, value: 'a' }, // multiple validation slots
688685
},
689686
];
690687

src/components/input/input.ts

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { property } from 'lit/decorators.js';
33
import { ifDefined } from 'lit/directives/if-defined.js';
44
import { live } from 'lit/directives/live.js';
55

6-
import { watch } from '../common/decorators/watch.js';
76
import { registerComponent } from '../common/definitions/register.js';
87
import {
98
type FormValue,
@@ -56,6 +55,13 @@ export default class IgcInputComponent extends IgcInputBaseComponent {
5655
return this.type !== 'number' ? stringValidators : numberValidators;
5756
}
5857

58+
private _min?: number;
59+
private _max?: number;
60+
private _minLength?: number;
61+
private _maxLength?: number;
62+
private _pattern?: string;
63+
private _step?: number;
64+
5965
/* @tsTwoWayProperty(true, "igcChange", "detail", false) */
6066
/**
6167
* The value of the control.
@@ -99,42 +105,84 @@ export default class IgcInputComponent extends IgcInputBaseComponent {
99105
* @attr
100106
*/
101107
@property()
102-
public pattern!: string;
108+
public set pattern(value: string | undefined) {
109+
this._pattern = value;
110+
this._validate();
111+
}
112+
113+
public get pattern(): string | undefined {
114+
return this._pattern;
115+
}
103116

104117
/**
105118
* The minimum string length required by the control.
106119
* @attr minlength
107120
*/
108121
@property({ type: Number, attribute: 'minlength' })
109-
public minLength!: number;
122+
public set minLength(value: number | undefined) {
123+
this._minLength = value;
124+
this._validate();
125+
}
126+
127+
public get minLength(): number | undefined {
128+
return this._minLength;
129+
}
110130

111131
/**
112132
* The maximum string length of the control.
113133
* @attr maxlength
114134
*/
115135
@property({ type: Number, attribute: 'maxlength' })
116-
public maxLength!: number;
136+
public set maxLength(value: number | undefined) {
137+
this._maxLength = value;
138+
this._validate();
139+
}
140+
141+
public get maxLength(): number | undefined {
142+
return this._maxLength;
143+
}
117144

118145
/**
119146
* The min attribute of the control.
120147
* @attr
121148
*/
122-
@property()
123-
public min!: number | string;
149+
@property({ type: Number })
150+
public set min(value: number | undefined) {
151+
this._min = value;
152+
this._validate();
153+
}
154+
155+
public get min(): number | undefined {
156+
return this._min;
157+
}
124158

125159
/**
126160
* The max attribute of the control.
127161
* @attr
128162
*/
129-
@property()
130-
public max!: number | string;
163+
@property({ type: Number })
164+
public set max(value: number | undefined) {
165+
this._max = value;
166+
this._validate();
167+
}
168+
169+
public get max(): number | undefined {
170+
return this._max;
171+
}
131172

132173
/**
133174
* The step attribute of the control.
134175
* @attr
135176
*/
136177
@property({ type: Number })
137-
public step!: number;
178+
public set step(value: number | undefined) {
179+
this._step = value;
180+
this._validate();
181+
}
182+
183+
public get step(): number | undefined {
184+
return this._step;
185+
}
138186

139187
/**
140188
* The autofocus attribute of the control.
@@ -167,20 +215,9 @@ export default class IgcInputComponent extends IgcInputBaseComponent {
167215

168216
constructor() {
169217
super();
170-
171218
this._formValue = createFormValueState(this, { initialValue: '' });
172219
}
173220

174-
@watch('min', { waitUntilFirstUpdate: true })
175-
@watch('max', { waitUntilFirstUpdate: true })
176-
@watch('minLength', { waitUntilFirstUpdate: true })
177-
@watch('maxLength', { waitUntilFirstUpdate: true })
178-
@watch('pattern', { waitUntilFirstUpdate: true })
179-
@watch('step', { waitUntilFirstUpdate: true })
180-
protected constraintsChanged() {
181-
this._validate();
182-
}
183-
184221
/* blazorSuppress */
185222
/** Replaces the selected text in the input. */
186223
public override setRangeText(

src/components/textarea/textarea.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ describe('Textarea component', () => {
399399
[
400400
{ slots: ['valueMissing'], props: { required: true } }, // value-missing slot
401401
{ slots: ['tooLong'], props: { maxLength: 3, value: '1234' } }, // too-long slot
402-
{ slots: ['tooShort'], props: { minLength: 3 } }, // too-short slot
402+
{ slots: ['tooShort'], props: { minLength: 3, value: '12' } }, // too-short slot
403403
{ slots: ['customError'] }, // custom-error slot
404404
{ slots: ['invalid'], props: { required: true } }, // invalid slot
405405
];

stories/input.stories.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,13 @@ const metadata: Meta<IgcInputComponent> = {
6767
control: 'number',
6868
},
6969
min: {
70-
type: 'number | string',
70+
type: 'number',
7171
description: 'The min attribute of the control.',
72-
options: ['number', 'string'],
7372
control: 'number',
7473
},
7574
max: {
76-
type: 'number | string',
75+
type: 'number',
7776
description: 'The max attribute of the control.',
78-
options: ['number', 'string'],
7977
control: 'number',
8078
},
8179
step: {
@@ -179,9 +177,9 @@ interface IgcInputArgs {
179177
/** The maximum string length of the control. */
180178
maxLength: number;
181179
/** The min attribute of the control. */
182-
min: number | string;
180+
min: number;
183181
/** The max attribute of the control. */
184-
max: number | string;
182+
max: number;
185183
/** The step attribute of the control. */
186184
step: number;
187185
/** The autofocus attribute of the control. */

0 commit comments

Comments
 (0)