I am trying to integrate Splidejs into a Grapesjs editor.
When mounting splides, I get the Uncaught Error: [splide] A track/list element is missing.
After debugging, I realise that Splide does not find the required track or list HTML Element for mounting properly. However, they are present in the HTML of the Grapes component.
...
<div class="splide__track">
<ul class="splide__list">
...
The reason why Splide doesn't find them seems to be related to different HTMLElement base types, leading to my elements not to be recognized.
The test below (Splide 3.6.9) returns false
When investigating in Chrome dev tools console, the __proto__
chain evaluated by instanceof
looks correct at first glance. However a closer look shows that subject
has additionnal __zone_symbol__onxxx
properties.
> subject.__proto__.__proto__
HTMLElement {…}
...
__zone_symbol__ononabortpatched: true
__zone_symbol__ononanimationendpatched: true
__zone_symbol__ononanimationiterationpatched: true
...
> HTMLElement.prototype
HTMLElement {…}
...
none of the __zone_symbol __onxxx present
...
> subject.__proto__.__proto__ == HTMLElement.prototype
false
This could be explained by those two references:
instanceof
and multiple context (e.g. frames or windows)Different scopes have different execution environments. This means that they have different built-ins (different global object, different constructors, etc.). This may result in unexpected results. For instance,
[] instanceof window.frames[0].Array
will returnfalse
,
(2) https://grapesjs.com/docs/modules/Components-js.html#important-caveat
Keep in mind that all component scripts are executed inside the iframe of the canvas (isolated, just like your final template), and therefore are NOT part of the current document.
I am suspecting that my Splide content gets enhanced by zone.js. Therefore I started creating the Grapes component outside of the Angular zone
this.zone.runOutsideAngular(() => {
this.initGrapesEditor()
})
but the error remains.
Do you have any hints on how I could fix this issue?
I have also reported the issue on grapesjs' github https://github.com/artf/grapesjs/discussions/4062
and added two workarounds
as in
/**
* Tests to see if the given TypeName appears anywhere
* in the prototype chain of the given subject.
* This is a lose version of the instanceof operator
* (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof)
* required when checking the type of elements that cross window and iframe bouderies.
*
* @param subject
* @param typeName
* @returns `true` if
*/
function isInstanceOf(subject: any, typeName: string) {
if (subject === null) {
return false;
}
let p = subject.__proto__;
while (p !== null) {
if (p.constructor.name === typeName) {
return true;
}
p = p.__proto__;
}
return false;
}
export function isHTMLElement( subject: unknown ): subject is HTMLElement {
return isInstanceOf( subject, 'HTMLElement' );
}
export function isHTMLButtonElement( subject: unknown ): subject is HTMLButtonElement {
return isInstanceOf( subject, 'HTMLButtonElement' );
}