Skip to content

Commit

Permalink
fix(button): add value to form when submitting
Browse files Browse the repository at this point in the history
Fixes #4526

PiperOrigin-RevId: 558261952
  • Loading branch information
asyncLiz authored and copybara-github committed Aug 18, 2023
1 parent 3e13634 commit f23fac1
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
16 changes: 16 additions & 0 deletions button/internal/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ export abstract class Button extends LitElement implements FormSubmitter {

@property() type: FormSubmitterType = 'submit';

@property() value = '';

get name() {
return this.getAttribute('name') ?? '';
}
set name(name: string) {
this.setAttribute('name', name);
}

/**
* The associated form element with which this element's value will submit.
*/
get form() {
return this[internals].form;
}

@query('.button') private readonly buttonElement!: HTMLElement|null;

@queryAssignedElements({slot: 'icon', flatten: true})
Expand Down
23 changes: 23 additions & 0 deletions iconbutton/internal/icon-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,29 @@ export class IconButton extends LitElement implements FormSubmitter {

@property() type: FormSubmitterType = 'submit';

@property() value = '';

get name() {
return this.getAttribute('name') ?? '';
}
set name(name: string) {
this.setAttribute('name', name);
}

/**
* The associated form element with which this element's value will submit.
*/
get form() {
return this[internals].form;
}

/**
* The labels this element is associated with.
*/
get labels() {
return this[internals].labels;
}

@state() private flipIcon = isRtl(this, this.flipIconInRtl);

/** @private */
Expand Down
18 changes: 17 additions & 1 deletion internal/controller/form-submitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ export interface FormSubmitter extends ReactiveElement, WithInternals {
* - button: The element does nothing.
*/
type: FormSubmitterType;

/**
* The HTML name to use in form submission. When combined with a `value`, the
* submitting button's name/value will be added to the form.
*
* Names must reflect to a `name` attribute for form integration.
*/
name: string;

/**
* The value of the button. When combined with a `name`, the submitting
* button's name/value will be added to the form.
*/
value: string;
}

type FormSubmitterConstructor =
Expand Down Expand Up @@ -71,7 +85,8 @@ export function setupFormSubmitter(ctor: FormSubmitterConstructor) {
(ctor as unknown as typeof ReactiveElement).addInitializer(instance => {
const submitter = instance as FormSubmitter;
submitter.addEventListener('click', async event => {
const {type, [internals]: {form}} = submitter;
const {type, [internals]: elementInternals} = submitter;
const {form} = elementInternals;
if (!form || type === 'button') {
return;
}
Expand Down Expand Up @@ -102,6 +117,7 @@ export function setupFormSubmitter(ctor: FormSubmitterConstructor) {
});
}, {capture: true, once: true});

elementInternals.setFormValue(submitter.value);
form.requestSubmit();
});
});
Expand Down
23 changes: 22 additions & 1 deletion internal/controller/form-submitter_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// import 'jasmine'; (google3-only)

import {html, LitElement} from 'lit';
import {customElement} from 'lit/decorators.js';
import {customElement, property} from 'lit/decorators.js';

import {Environment} from '../../testing/environment.js';
import {Harness} from '../../testing/harness.js';
Expand All @@ -30,6 +30,8 @@ class FormSubmitterButton extends LitElement {
static formAssociated = true;

type: FormSubmitterType = 'submit';
@property({reflect: true}) name = '';
value = '';

[internals] = this.attachInternals();
}
Expand Down Expand Up @@ -116,4 +118,23 @@ describe('setupFormSubmitter()', () => {
.withContext('event.submitter')
.toBe(harness.element);
});

it('should add name/value to form data when present', async () => {
const {harness, form} = await setupTest();
form.addEventListener('submit', event => {
event.preventDefault();
});

harness.element.name = 'foo';
harness.element.value = 'bar';

await harness.clickWithMouse();

const formData = Array.from(new FormData(form));
expect(formData.length).withContext('formData.length').toBe(1);

const [formName, formValue] = formData[0];
expect(formName).toBe('foo');
expect(formValue).toBe('bar');
});
});

0 comments on commit f23fac1

Please sign in to comment.