From f4078fe245232519b5e4d9cf0487c01e96a8ea10 Mon Sep 17 00:00:00 2001 From: Denis Soriano Date: Wed, 20 Nov 2024 23:56:14 +0100 Subject: [PATCH 1/2] Allow form elements to live outside form tag by using the "form" attribute --- src/LiveComponent/assets/src/dom_utils.ts | 3 ++- src/LiveComponent/assets/test/dom_utils.test.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/LiveComponent/assets/src/dom_utils.ts b/src/LiveComponent/assets/src/dom_utils.ts index 7454cf28c3d..59842a38976 100644 --- a/src/LiveComponent/assets/src/dom_utils.ts +++ b/src/LiveComponent/assets/src/dom_utils.ts @@ -161,7 +161,8 @@ export function getModelDirectiveFromElement(element: HTMLElement, throwOnMissin } if (element.getAttribute('name')) { - const formElement = element.closest('form'); + const formId = element.getAttribute('form'); + const formElement = formId ? document.getElementById(formId) : element.closest('form'); // require a
around elements in order to // activate automatic "data binding" via the "name" attribute if (formElement && 'model' in formElement.dataset) { diff --git a/src/LiveComponent/assets/test/dom_utils.test.ts b/src/LiveComponent/assets/test/dom_utils.test.ts index 2afdbafd132..ff9c3725fce 100644 --- a/src/LiveComponent/assets/test/dom_utils.test.ts +++ b/src/LiveComponent/assets/test/dom_utils.test.ts @@ -230,6 +230,19 @@ describe('getModelDirectiveFromInput', () => { expect(directive?.action).toBe('user.firstName'); }); + it('reads name attribute if element lives out of form and use "form" attribute', () => { + const container = document.createElement('div'); + const formElement = htmlToElement('
'); + const element = htmlToElement(''); + container.appendChild(element); + container.appendChild(formElement); + document.body.appendChild(container); + + const directive = getModelDirectiveFromElement(element); + expect(directive).not.toBeNull(); + expect(directive?.action).toBe('user.firstName'); + }); + it('does NOT reads name attribute if form[data-model] is NOT present', () => { const formElement = htmlToElement('
'); const element = htmlToElement(''); From 7bbb4c49d5ab29a4af08673acbc47d4d7f161501 Mon Sep 17 00:00:00 2001 From: Denis Soriano Date: Thu, 21 Nov 2024 00:02:16 +0100 Subject: [PATCH 2/2] Build live_controller.js --- src/LiveComponent/assets/dist/live_controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LiveComponent/assets/dist/live_controller.js b/src/LiveComponent/assets/dist/live_controller.js index 94c9f8dd0ca..7b682f3e29d 100644 --- a/src/LiveComponent/assets/dist/live_controller.js +++ b/src/LiveComponent/assets/dist/live_controller.js @@ -305,7 +305,8 @@ function getModelDirectiveFromElement(element, throwOnMissing = true) { return dataModelDirectives[0]; } if (element.getAttribute('name')) { - const formElement = element.closest('form'); + const formId = element.getAttribute('form'); + const formElement = formId ? document.getElementById(formId) : element.closest('form'); if (formElement && 'model' in formElement.dataset) { const directives = parseDirectives(formElement.dataset.model || '*'); const directive = directives[0];