#Lustre: Uncaught DOMException: Node.insertBefore: Child to insert before is not a child of this node

1 messages · Page 1 of 1 (latest)

tough ledge
#

I have a preview pane next to a text area. On every input change in the text area, the corresponding preview pane div gets populated and rendered, followed by an effect that renders all the Latex in that div (using KaTeX). This works fine on first KaTeX render. All subsequent renders get one of two errors:

Uncaught DOMException: Node.removeChild: The node to be removed is not a child of this node

Uncaught DOMException: Node.insertBefore: Child to insert before is not a child of this node

Consequently the expected preview output in the preview pane gets appended and not replaced.

Here's a minimal code snippet for the preview pane:

      keyed.div([], [
        #(
          constant_id,
          element.fragment([
            html.div([], [html.text(preview_content)]),
          ]),
        ),
      ])
cloud snow
#

this is expected, you're modifying the dom that lustre owns its innevitable that things will break

#

use unsafe_raw_html

#

or better yet write a web component for it

tough ledge
#

Ok let me try this ty

tough ledge
#

unsafe_raw_html worked!

#

But you recommend writing a web component since Lustre would then manage it? So then I'd end up with something like

preview_pane.element(the_content)

and I would not need to use unsafe_raw_html in the implementation of preview_pane, right?

cloud snow
#

i'd do something like

window.customElements.define(
  "katex-preview",
  class KatexPreview extends HTMLElement {
    static template = `
      <style>
        /* Hide the slotted children * /
        slot { display: none; }
      </style>
      <div id="output"></div>
      <slot></slot>
    `

    constructor() {
      super();
      this.shadowRoot = this.attachShadow({ mode: 'closed' })
      this.shadowRoot.innerHTML = KatexPreview.template
    }

    connectedCallback() {
      const slot = this.shadowRoot.querySelector('slot')
      const output = this.shadowRoot.querySelector('#output')

      // the slotchange event will fire whenever the direct children
      // of this custom element changes
      slot.addEventListener('slotchange', () => {
        const nodes = Array.from(slot.assignedNodes())
        // concat the text content of all children
        const content = nodes.reduce((content, node) => {
          switch (node.nodeType) {
            case Node.ELEMENT_NODE: 
            case Node.TEXT_NODE:
              return content + node.textContent

            default:
              return content
          }
        }, '')

        // convert the latex into html and render it into the output
        // div
        magicKatexRenderer(output, content)
      })
    }
  }
)
#

in lustre you'd just do

element("katex-preview", [], [html.text(preview_content)])
tough ledge
#

Interesting, a javascript soln

#

Thank you for the detailed snippet