diff --git a/src/LiveComponent/assets/dist/live_controller.js b/src/LiveComponent/assets/dist/live_controller.js index 06c281c0c15..09f3417aa95 100644 --- a/src/LiveComponent/assets/dist/live_controller.js +++ b/src/LiveComponent/assets/dist/live_controller.js @@ -1107,7 +1107,7 @@ class default_1 extends Controller { }); } $render() { - this._makeRequest(null); + this._makeRequest(null, {}); } _getValueFromElement(element) { return element.dataset.value || element.value; @@ -1121,17 +1121,18 @@ class default_1 extends Controller { const clonedElement = cloneHTMLElement(element); throw new Error(`The update() method could not be called for "${clonedElement.outerHTML}": the element must either have a "data-model" or "name" attribute set to the model name.`); } + let finalValue = value; if (/\[]$/.test(model)) { const { currentLevelData, finalKey } = parseDeepData(this.dataValue, normalizeModelName(model)); const currentValue = currentLevelData[finalKey]; - value = updateArrayDataFromChangedElement(element, value, currentValue); + finalValue = updateArrayDataFromChangedElement(element, value, currentValue); } else if (element instanceof HTMLInputElement && element.type === 'checkbox' && !element.checked) { - value = null; + finalValue = null; } - this.$updateModel(model, value, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {}); + this.$updateModel(model, finalValue, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {}); } $updateModel(model, value, shouldRender = true, extraModelName = null, options = {}) { const directives = parseDirectives(model); @@ -1427,10 +1428,13 @@ class default_1 extends Controller { } else { callback = () => { - this._makeRequest(actionName); + this._makeRequest(actionName, {}); }; } const timer = setInterval(() => { + if (this.renderPromiseStack.countActivePromises() > 0) { + return; + } callback(); }, duration); this.pollingIntervals.push(timer); @@ -1539,6 +1543,9 @@ class PromiseStack { findPromiseIndex(promise) { return this.stack.findIndex((item) => item === promise); } + countActivePromises() { + return this.stack.length; + } } const parseLoadingAction = function (action, isLoading) { switch (action) { diff --git a/src/LiveComponent/assets/src/live_controller.ts b/src/LiveComponent/assets/src/live_controller.ts index 9bda5781207..676ffe9bd4d 100644 --- a/src/LiveComponent/assets/src/live_controller.ts +++ b/src/LiveComponent/assets/src/live_controller.ts @@ -184,7 +184,7 @@ export default class extends Controller { } $render() { - this._makeRequest(null); + this._makeRequest(null, {}); } _getValueFromElement(element: HTMLElement|SVGElement) { @@ -206,22 +206,23 @@ export default class extends Controller { // HTML form elements with name ending with [] require array as data // we need to handle addition and removal of values from it to send // back only required data + let finalValue : string|null|string[] = value if (/\[]$/.test(model)) { // Get current value from data const { currentLevelData, finalKey } = parseDeepData(this.dataValue, normalizeModelName(model)) const currentValue = currentLevelData[finalKey]; - value = updateArrayDataFromChangedElement(element, value, currentValue); + finalValue = updateArrayDataFromChangedElement(element, value, currentValue); } else if ( element instanceof HTMLInputElement && element.type === 'checkbox' && !element.checked ) { // Unchecked checkboxes in a single value scenarios should map to `null` - value = null; + finalValue = null; } - this.$updateModel(model, value, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {}); + this.$updateModel(model, finalValue, shouldRender, element.hasAttribute('name') ? element.getAttribute('name') : null, {}); } /** @@ -309,7 +310,7 @@ export default class extends Controller { } } - _makeRequest(action: string|null, args: Record) { + _makeRequest(action: string|null, args: Record) { const splitUrl = this.urlValue.split('?'); let [url] = splitUrl const [, queryString] = splitUrl; @@ -659,11 +660,16 @@ export default class extends Controller { } } else { callback = () => { - this._makeRequest(actionName); + this._makeRequest(actionName, {}); } } const timer = setInterval(() => { + // if there is already an active render promise, skip the poll + if (this.renderPromiseStack.countActivePromises() > 0) { + return; + } + callback(); }, duration); this.pollingIntervals.push(timer); @@ -820,6 +826,10 @@ class PromiseStack { findPromiseIndex(promise: Promise) { return this.stack.findIndex((item) => item === promise); } + + countActivePromises(): number { + return this.stack.length; + } } const parseLoadingAction = function(action: string, isLoading: boolean) {