diff --git a/packages/main/cypress/specs/FormSupport.cy.tsx b/packages/main/cypress/specs/FormSupport.cy.tsx index 1d833272dacd..49e7f49d10bb 100644 --- a/packages/main/cypress/specs/FormSupport.cy.tsx +++ b/packages/main/cypress/specs/FormSupport.cy.tsx @@ -19,6 +19,7 @@ import StepInput from "../../src/StepInput.js"; import Switch from "../../src/Switch.js"; import TextArea from "../../src/TextArea.js"; import TimePicker from "../../src/TimePicker.js"; +import Tokenizer from "../../src/Tokenizer.js"; const getFormData = ($form: HTMLFormElement) => { const formData = new FormData($form); @@ -423,6 +424,57 @@ describe("Form support", () => { .should("be.equal", "multi_input5=&multi_input6=ok&multi_input7=&multi_input7=ok&multi_input8=ok&multi_input8=ok&multi_input9=ok&multi_input10=ok&multi_input11=&multi_input11=ok&multi_input12=ok&multi_input12=ok"); }); + it("ui5-tokenizer in form", () => { + cy.mount( +
+ + + + + +
+ ); + + cy.get("form").then($form => { + $form.get(0)!.addEventListener("submit", e => e.preventDefault()); + $form.get(0)!.addEventListener("submit", cy.stub().as("submit")); + }); + + cy.get("button") + .realClick(); + + cy.get("@submit") + .should("have.been.called"); + + cy.get("form") + .then($el => getFormData($el.get(0)!)) + .should("equal", "tags=Apple&tags=Banana"); + }); + + it("ui5-tokenizer does not submit anything if no tokens", () => { + cy.mount( +
+ + +
+ ); + + cy.get("form").then($form => { + $form.get(0)!.addEventListener("submit", e => e.preventDefault()); + $form.get(0)!.addEventListener("submit", cy.stub().as("submit")); + }); + + cy.get("button") + .realClick(); + + cy.get("@submit") + .should("have.been.called"); + + cy.get("form") + .then($el => getFormData($el.get(0)!)) + .should("equal", ""); + }); + it("ui5-radio-button in form 1", () => { cy.mount(
diff --git a/packages/main/src/Tokenizer.ts b/packages/main/src/Tokenizer.ts index 022c60a3516e..1f59636729ae 100644 --- a/packages/main/src/Tokenizer.ts +++ b/packages/main/src/Tokenizer.ts @@ -12,6 +12,7 @@ import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/Acc import getActiveElement from "@ui5/webcomponents-base/dist/util/getActiveElement.js"; import { getFocusedElement } from "@ui5/webcomponents-base/dist/util/PopupUtils.js"; import ScrollEnablement from "@ui5/webcomponents-base/dist/delegate/ScrollEnablement.js"; +import type { IFormInputElement } from "@ui5/webcomponents-base/dist/features/InputElementsFormSupport.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; import type { I18nText } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; @@ -139,6 +140,7 @@ enum ClipboardDataOperation { @customElement({ tag: "ui5-tokenizer", languageAware: true, + formAssociated: true, renderer: jsxRenderer, template: TokenizerTemplate, styles: [ @@ -184,7 +186,7 @@ enum ClipboardDataOperation { bubbles: true, }) -class Tokenizer extends UI5Element { +class Tokenizer extends UI5Element implements IFormInputElement { eventDetails!: { "token-delete": TokenizerTokenDeleteEventDetail, "selection-change": TokenizerSelectionChangeEventDetail, @@ -214,6 +216,18 @@ class Tokenizer extends UI5Element { @property({ type: Boolean }) multiLine = false; + /** + * Determines the name by which the component will be identified upon submission in an HTML form. + * + * **Note:** This property is only applicable within the context of an HTML Form element. + * **Note:** When the component is used inside a form element, + * the value is sent as the first element in the form data, even if it's empty. + * @default undefined + * @public + */ + @property({ type: String }) + declare name?: string; + /** * Defines whether "Clear All" button is present. Ensure `multiLine` is enabled, otherwise `showClearAll` will have no effect. * @@ -360,6 +374,23 @@ class Tokenizer extends UI5Element { this._nMoreCount = this.overflownTokens.length; } + get formFormattedValue(): FormData | null { + const tokens = this.tokens || []; + + if (this.name && tokens.length) { + const formData = new FormData(); + const name = this.name; + + tokens.forEach(token => { + formData.append(name, token.text || ""); + }); + + return formData; + } + + return null; + } + constructor() { super(); diff --git a/packages/main/test/pages/FormSupport.html b/packages/main/test/pages/FormSupport.html index a6cb896d87fa..0a04b92b757a 100644 --- a/packages/main/test/pages/FormSupport.html +++ b/packages/main/test/pages/FormSupport.html @@ -146,6 +146,15 @@ Submits form
+
+ ui5-tokenizer + + + + + + Submits form +
ui5-radio-button