Skip to content

Commit 4bcd3bb

Browse files
authored
feat: Expose defaultValue/defaultChecked property for form-associated components (#1464)
1 parent 25663ff commit 4bcd3bb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2834
-1555
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

77
## [Unreleased]
8+
### Added
9+
- Form-associated elements now have a `defaultValue` property (`defaultChecked` for radio buttons, checkboxes, and switches). When a form is reset, components will use this property’s value as their new value or checked state.
10+
811
### Changed
912
- Calendar - allow passing a string value to the backing `value`, `values` and `activeDate` properties [#1467](https://github.com/IgniteUI/igniteui-webcomponents/issues/1467)
1013
- Date-time input - allow passing a string value to the backing `value`, `min` and `max` properties [#1467](https://github.com/IgniteUI/igniteui-webcomponents/issues/1467)
1114
- Date picker - allow passing a string value to the backing `value`, `min`, `max` and `activeDate` properties [#1467](https://github.com/IgniteUI/igniteui-webcomponents/issues/1467)
15+
- Component validation - aligned validation constraints to follow the behavior of their native HTML counterparts.
16+
For example, `minlength` will no longer trigger a `tooShort` validity state, unless there is text present in the component.
17+
18+
### Fixed
19+
- Combo - Rendering issue after Edge browser autofill behavior [#1497](https://github.com/IgniteUI/igniteui-webcomponents/issues/1497)
1220

1321
## [5.1.2] - 2024-11-04
1422
### Added

src/components/button/button.spec.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
22

33
import { defineComponents } from '../common/definitions/defineComponents.js';
4-
import { FormAssociatedTestBed, isFocused } from '../common/utils.spec.js';
4+
import {
5+
createFormAssociatedTestBed,
6+
isFocused,
7+
} from '../common/utils.spec.js';
8+
import IgcInputComponent from '../input/input.js';
59
import IgcButtonComponent from './button.js';
610

711
const Variants: Array<IgcButtonComponent['variant']> = [
@@ -14,7 +18,7 @@ const Types: Array<IgcButtonComponent['type']> = ['button', 'reset', 'submit'];
1418

1519
describe('Button tests', () => {
1620
let button: IgcButtonComponent;
17-
before(() => defineComponents(IgcButtonComponent));
21+
before(() => defineComponents(IgcButtonComponent, IgcInputComponent));
1822

1923
describe('Button component', () => {
2024
const ignored_DOM_parts = {
@@ -214,49 +218,47 @@ describe('Button tests', () => {
214218
});
215219

216220
describe('Form integration', () => {
217-
const spec = new FormAssociatedTestBed(
218-
html`<input type="text" name="username" value="John Doe" />
219-
<igc-button type="submit">Submit</igc-button>`
220-
);
221+
let button: IgcButtonComponent;
222+
const spec = createFormAssociatedTestBed<IgcInputComponent>(html`
223+
<igc-input type="text" name="username" value="John Doe"></igc-input>
224+
<igc-button type="submit">Submit</igc-button>
225+
`);
221226

222-
beforeEach(async () => await spec.setup(IgcButtonComponent.tagName));
227+
beforeEach(async () => {
228+
await spec.setup(IgcInputComponent.tagName);
229+
button = spec.form.querySelector(IgcButtonComponent.tagName)!;
230+
});
223231

224232
it('is form associated', async () => {
225-
expect(spec.element.form).to.equal(spec.form);
233+
expect(button.form).to.equal(spec.form);
226234
});
227235

228236
it('submits the associated form', async () => {
229-
const button = spec.element as unknown as IgcButtonComponent;
230-
231237
const handler = (event: SubmitEvent) => {
232238
event.preventDefault();
233-
expect(
234-
new FormData(event.target as HTMLFormElement).get('username')
235-
).to.equal('John Doe');
239+
expect(new FormData(spec.form).get('username')).to.equal('John Doe');
236240
};
237241

238242
spec.form.addEventListener('submit', handler, { once: true });
239243
button.click();
240244
});
241245

242246
it('resets the associated form', async () => {
243-
const button = spec.element as unknown as IgcButtonComponent;
244-
const input = spec.form.querySelector('input') as HTMLInputElement;
245-
246-
input.value = 'Jane Doe';
247+
spec.setProperties({ value: 'Jane Doe' });
247248
button.type = 'reset';
248-
await elementUpdated(button);
249249

250250
button.click();
251-
expect(input.value).to.equal('John Doe');
251+
expect(spec.element.value).to.equal('John Doe');
252252
});
253253

254-
it('reflects disabled ancestor state', async () => {
254+
it('reflects disabled ancestor state', () => {
255255
spec.setAncestorDisabledState(true);
256256
expect(spec.element.disabled).to.be.true;
257+
expect(button.disabled).to.be.true;
257258

258259
spec.setAncestorDisabledState(false);
259260
expect(spec.element.disabled).to.be.false;
261+
expect(button.disabled).to.be.false;
260262
});
261263
});
262264
});

src/components/checkbox/checkbox-base.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import { blazorDeepImport } from '../common/decorators/blazorDeepImport.js';
66
import type { Constructor } from '../common/mixins/constructor.js';
77
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
88
import { FormAssociatedCheckboxRequiredMixin } from '../common/mixins/forms/associated-required.js';
9+
import {
10+
type FormValue,
11+
createFormValueState,
12+
defaultBooleanTransformers,
13+
} from '../common/mixins/forms/form-value.js';
914
import { isEmpty } from '../common/util.js';
1015
import { checkBoxValidators } from './validators.js';
1116

@@ -34,8 +39,8 @@ export class IgcCheckboxBaseComponent extends FormAssociatedCheckboxRequiredMixi
3439
}
3540

3641
protected _kbFocus = addKeyboardFocusRing(this);
42+
protected override _formValue: FormValue<boolean>;
3743
protected _value!: string;
38-
protected _checked = false;
3944

4045
@query('input', true)
4146
protected input!: HTMLInputElement;
@@ -69,13 +74,12 @@ export class IgcCheckboxBaseComponent extends FormAssociatedCheckboxRequiredMixi
6974
*/
7075
@property({ type: Boolean })
7176
public set checked(value: boolean) {
72-
this._checked = Boolean(value);
73-
this._setFormValue(this._checked ? this.value || 'on' : null);
77+
this._formValue.setValueAndFormState(value);
7478
this._validate();
7579
}
7680

7781
public get checked(): boolean {
78-
return this._checked;
82+
return this._formValue.value;
7983
}
8084

8185
/**
@@ -85,6 +89,15 @@ export class IgcCheckboxBaseComponent extends FormAssociatedCheckboxRequiredMixi
8589
@property({ reflect: true, attribute: 'label-position' })
8690
public labelPosition: 'before' | 'after' = 'after';
8791

92+
constructor() {
93+
super();
94+
95+
this._formValue = createFormValueState(this, {
96+
initialValue: false,
97+
transformers: defaultBooleanTransformers,
98+
});
99+
}
100+
88101
protected override createRenderRoot() {
89102
const root = super.createRenderRoot();
90103
this.hideLabel = isEmpty(this.label);

0 commit comments

Comments
 (0)