Custom Dynamic List freezes after binding array and expanding rows to match length
Thanks for reporting this, @zhengtulymGh. The issue with Custom Dynamic List freezes after binding array and expanding rows to match length appears to be a race condition or state management timing problem. This typically happens when component lifecycle events and DOM modifications overlap, creating an inconsistent s...
Read full answer below βQuestion
GrapesJS version
- I confirm to use the latest version of GrapesJS
What browser are you using?
140.0.7339.214οΌζ£εΌηζ¬οΌ (x86_64)
Reproducible demo link
https://codesandbox.io/p/devbox/d27l6n
Describe the bug
I want to create a custom dynamic list component based on GrapesJS (with 3 rows by default). It can bind to an array variable and dynamically change the number of rows in the container according to the array length. Now I'm encountering a freeze issue. The reproduction steps are as follows:
-
Click the Variables tab on the left and create a new array variable with a length of 4.
[![enter image description here][1]][1]
-
Go back to the Components tab and drag a Dynamic List container component onto the canvas.
-
Select the Dynamic List component you just dragged in. On the right, the Styles tab will show a dropdown to bind an array variable. Choose the array variable created in step 1. After selection, the dynamic list on the canvas changes from 3 rows to 4 rows, which is expected.
[![enter image description here][2]][2]
4. Move the mouse over the dynamic list component (now 4 rows) on the canvas. You'll notice the page freezes.
After my investigation, the key issue lies in the logic that adjusts the number of container rows based on the array length, but I couldn't pinpoint the cause.
editor.on('component:update:attributes', (comp: any, attrs?: any, opts?: any) => {
console.log('component:update:attributes')
if (isSyncing(editor)) return;
if (comp.get && comp.get('type') === DL_TYPE) {
const dlAttrs = comp.getAttributes?.() || {};
const varName = dlAttrs[DL_ATTR_ARRAY_VAR];
const arrData = varName ? getDLArrayData(editor, comp) : undefined;
if (!varName || !Array.isArray(arrData)) {
// clearBindingsAndResetDefaults(editor, comp);
} else {
ensureRowCountByArray(editor, comp);
}
return;
}
});
function cloneIntoTarget(sourceRow: any, targetRow: any) {
console.log('cloneIntoTarget')
sourceRow.components().each((child: any) => {
const cloned = child.clone();
targetRow.append(cloned);
});
}
function ensureRowCountByArray(editor: any, dl: any) {
console.log('ensureRowCountByArray')
if (isSyncing(editor)) return;
const arr = getDLArrayData(editor, dl);
const targetCount = Array.isArray(arr) ? (arr.length > 0 ? arr.length : 3) : 3;
markSyncing(editor, true);
try {
let rows = getRows(dl);
const curCount = rows.length;
if (curCount !== targetCount) {
if (rows.length === 0) {
dl.append({ type: ROW_TYPE });
rows = getRows(dl);
}
const baseRow = rows[0];
if (curCount < targetCount) {
const need = targetCount - curCount;
for (let i = 0; i < need; i++) {
const newRow = dl.append({ type: ROW_TYPE })[0];
cloneIntoTarget(baseRow, newRow);
}
} else {
for (let i = curCount - 1; i >= targetCount; i--) {
rows[i].remove();
}
}
}
} finally {
markSyncing(editor, false);
}
}
What's going on here?
[1]: https://i.sstatic.net/7AlxKreK.png
[2]: https://i.sstatic.net/fe2lo06t.png
### Code of Conduct
- [x] I agree to follow this project's Code of ConductAnswers (1)
Thanks for reporting this, @zhengtulymGh.
The issue with Custom Dynamic List freezes after binding array and expanding rows to match length appears to be a race condition or state management timing problem. This typically happens when component lifecycle events and DOM modifications overlap, creating an inconsistent state.
What to try:
- Add a setTimeout wrapper to ensure the DOM has settled:
setTimeout(() => {
// your operation here
}, 0);
-
Check initialization order β make sure components are fully loaded before you interact with them
-
Use the editor's event system β listen to completion events:
editor.on('component:mount', (component) => {
// safe to interact with component here
});
Recommended next steps:
- Test with the latest GrapesJS version if you haven't
- Provide a minimal reproducible example (CodeSandbox) β this helps the team identify the root cause faster
- Include GrapesJS version, browser, and console errors in your report
Related Questions and Answers
Continue research with similar issue discussions.
Issue #6685
Custom component styles are not applied after deletion and re-addition
GrapesJS version [x] I confirm to use the latest version of GrapesJS What browser are you using? Chrome v143.0.7499.193 Reproducible demo l...
Issue #4573
parseStyle is not a function
GrapesJS version[X] I confirm to use the latest version of GrapesJSWhat browser are you using? Firefox 104.0.1Reproducible demo link https:...
Issue #4754
Closing `</script>` tag not escaped for script properties
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Chrome Version 107.0.5304.122 (64-bit) Rep...
Issue #6096
Resizable Box Disappears on Component Reselection
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Chrome Reproducible demo link https://jsfi...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Check the open-source GrapesJS plugins on GitHub or run a quick search in our free catalog.
Browse free plugins βPremium plugins ship with support, regular updates, and production-ready features β save days of integration work.
Browse premium plugins βBrowse Plugin Categories
Jump directly to plugin category pages on the marketplace.