mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 18:54:11 +08:00
fix(button): hidden button is added when form is set async (#27955)
Issue number: resolves #27952 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> The hidden button in `ion-button` that is responsible for submitting the form does not get added when the `form` property is set async. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - `ion-button` now checks to see if it needs to render a hidden button whenever it re-renders. This allows it to account for changes to the `type` property, `form` property, etc. Since this code can potentially run multiple times I added an extra check so we don't add multiple buttons to the form. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev build: `7.2.3-dev.11691523847.1760ab58`
This commit is contained in:
@ -153,19 +153,27 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
|||||||
*/
|
*/
|
||||||
@Event() ionBlur!: EventEmitter<void>;
|
@Event() ionBlur!: EventEmitter<void>;
|
||||||
|
|
||||||
connectedCallback(): void {
|
private renderHiddenButton() {
|
||||||
// Allow form to be submitted through `ion-button`
|
const formEl = (this.formEl = this.findForm());
|
||||||
if (this.type !== 'button' && hasShadowDom(this.el)) {
|
if (formEl) {
|
||||||
this.formEl = this.findForm();
|
const { formButtonEl } = this;
|
||||||
if (this.formEl) {
|
|
||||||
// Create a hidden native button inside of the form
|
/**
|
||||||
this.formButtonEl = document.createElement('button');
|
* If the form already has a rendered form button
|
||||||
this.formButtonEl.type = this.type;
|
* then do not append a new one again.
|
||||||
this.formButtonEl.style.display = 'none';
|
*/
|
||||||
// Only submit if the button is not disabled.
|
if (formButtonEl !== null && formEl.contains(formButtonEl)) {
|
||||||
this.formButtonEl.disabled = this.disabled;
|
return;
|
||||||
this.formEl.appendChild(this.formButtonEl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a hidden native button inside of the form
|
||||||
|
const newFormButtonEl = (this.formButtonEl = document.createElement('button'));
|
||||||
|
newFormButtonEl.type = this.type;
|
||||||
|
newFormButtonEl.style.display = 'none';
|
||||||
|
// Only submit if the button is not disabled.
|
||||||
|
newFormButtonEl.disabled = this.disabled;
|
||||||
|
|
||||||
|
formEl.appendChild(newFormButtonEl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +322,11 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
|
|||||||
if (fill == null) {
|
if (fill == null) {
|
||||||
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
|
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
type !== 'button' && this.renderHiddenButton();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Host
|
<Host
|
||||||
onClick={this.handleClick}
|
onClick={this.handleClick}
|
||||||
|
@ -130,6 +130,29 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
|
|||||||
|
|
||||||
expect(submitEvent).not.toHaveReceivedEvent();
|
expect(submitEvent).not.toHaveReceivedEvent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should submit the form by id when form is set async', async ({ page }, testInfo) => {
|
||||||
|
testInfo.annotations.push({
|
||||||
|
type: 'issue',
|
||||||
|
description: 'https://github.com/ionic-team/ionic-framework/issues/27952',
|
||||||
|
});
|
||||||
|
await page.setContent(
|
||||||
|
`
|
||||||
|
<form id="myForm"></form>
|
||||||
|
<ion-button type="submit">Submit</ion-button>
|
||||||
|
`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
|
||||||
|
const submitEvent = await page.spyOnEvent('submit');
|
||||||
|
const button = page.locator('ion-button');
|
||||||
|
|
||||||
|
await button.evaluate((el: HTMLIonButtonElement) => (el.form = 'myForm'));
|
||||||
|
|
||||||
|
await page.click('ion-button');
|
||||||
|
|
||||||
|
expect(submitEvent).toHaveReceivedEvent();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe(title('should throw a warning if the form cannot be found'), () => {
|
test.describe(title('should throw a warning if the form cannot be found'), () => {
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import { newSpecPage } from '@stencil/core/testing';
|
||||||
|
import { Button } from '../../button';
|
||||||
|
|
||||||
|
describe('Button: Hidden Form Button', () => {
|
||||||
|
it('should not add multiple buttons to the form', async () => {
|
||||||
|
const page = await newSpecPage({
|
||||||
|
components: [Button],
|
||||||
|
html: `
|
||||||
|
<form id="my-form"></form>
|
||||||
|
<ion-button form="my-form" type="submit">Submit</ion-button>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const getButtons = () => {
|
||||||
|
return page.body.querySelectorAll('form button');
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = page.body.querySelectorAll('form');
|
||||||
|
const button = page.body.querySelector('ion-button');
|
||||||
|
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
expect(getButtons().length).toEqual(1);
|
||||||
|
|
||||||
|
// Re-render the component
|
||||||
|
button.color = 'danger';
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
expect(getButtons().length).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user