Bug #103971
closedAjax-dispatcher.ts fails to load all stylesheets when they are loaded through an inline-relation in backend
100%
Description
We have a configuration in the backend. Where we have an accordion that can have multiple accordion items. Each accordion item can have multiple buttons. When you add a button to an accordion item, you can also select an icon for in that button. The icon can be selected using an custom styled input select.
When you open the accordion item, it will try to load all js and css required by the module. These are loaded dynamically through an ajax request. `ajax-dispather.ts` is used here to inject the relevant stylesheets. In my example it uses the following stylesheets.
[
"/_assets/937be57c7660e085d41e9dabf38b8aa1/Css/editor.css?1710839460",
"/_assets/f5f6d48c4a9e67b540bea426607200c5/CSS/iconField.css"
],
The issue is that only the first stylesheet is injected into the dom. So we're missing out on iconField.css.
I've debugged the issue, and found a bug in ajax-dispatcher.ts. And specifically in the function `processResponse`.
Here it's going wrong:
if (json.stylesheetFiles) {
for (const [index, stylesheetFile] of json.stylesheetFiles.entries()) {
if (!stylesheetFile) {
break;
}
const element = document.createElement('link');
element.rel = 'stylesheet';
element.type = 'text/css';
element.href = stylesheetFile;
document.querySelector('head').appendChild(element);
json.stylesheetFiles.splice(index, 1);
}
}
the line: json.stylesheetFiles.splice(index, 1); splices out an item from the array. But it modifies the array which is being looped through. This causes sideeffects. Which causes it to only inject the first item from the looped array.
The following code should fix it:
if (json.stylesheetFiles && json.stylesheetFiles.length) {
const copyStylesheetFiles = [...json.stylesheetFiles];
for (const stylesheetFile of copyStylesheetFiles.values()) {
if (!stylesheetFile) {
break;
}
const element = document.createElement('link');
element.rel = 'stylesheet';
element.type = 'text/css';
element.href = stylesheetFile;
document.querySelector('head').appendChild(element);
json.stylesheetFiles.splice(json.stylesheetFiles.indexOf(stylesheetFile), 1);
}
}
I've created some unit tests, to replicate the issue.
https://playcode.io/1894374