NodeView constructor being called multiple times

Hi, I’m currently trying to integrate MathJax into an editor, and began with inline math first. I created an input rule (/ $.+$ /), which, when triggered, created an inline_math node, defined here

inline_math: {
  inline: true,
  group: "inline",
  attrs: {
    texts: {}
  },
  draggable: true,
  parseDOM: [{tag: "span"}],
  toDOM(node) { return ["span", 0]}
},

which was linked to a NodeView, defined here.

export class InlineMathView {
    ...

  constructor(node: Node, view: EditorView, getPos: () => number) {
      this.node = node;
      this.view = view;
      this.getPos = getPos;
      this.dom =  document.createElement("span");
      this.dom.appendChild(document.createTextNode(this.node.attrs.texts));
  
      console.log(this.view);
      console.log(this.getPos());

      console.log(this.node.attrs.texts);
  
      this.typesetter.typeset(this.dom);
  }
}

So upon creation of the node, its content, which is set to $$, is typesetted and its content rendered into the DOM. Currently, the editor can correctly parse the ‘$’ delimiters and render the MathJax content, but upon pressing any character after the NodeView, the constructor is called again, as the content is typesetted again, as seen here. Also, when the NodeView is created again for more inline math on the same line, the other views’ constructors are called and are all re-rendered. I’m not too familiar with NodeViews currently, but I’m wondering what could be the cause of this problem?

Also, apologies if my last few posts have been vague or without much context. If there’s any more information needed for this post, however, please let me know.

ProseMirror reserves the right to recreate node views any time it pleases, but it tries to be efficient by reusing the ones that are already in the DOM. I’m not sure why it wouldn’t do that in this case. Can you distill it down to a minimal example (possibly replacing the math node with an even simpler inline node, say a view for images) and see if it still happens there? If so, I’ll try to debug that.

1 Like

Sorry another thing I should have clarified was that, for the case where there were multiple NodeViews in a line, they would only be re-rendered after typing any character after the last NodeView was created, if that changes things. I recently tried it with an image view like so:

export class ImageView {
  private node: Node;
  private view: EditorView;
  private getPos: () => number;
  public dom: HTMLElement;

  constructor(node: Node, view: EditorView, getPos: () => number) {
    this.node = node;
    this.view = view;
    this.getPos = getPos;
    this.dom = document.createElement("img");
    this.dom.setAttribute("src", node.attrs.src);
    this.dom.addEventListener("click", e => {
    console.log("You clicked me!");
    e.preventDefault();
    })
    console.log(this.node);
    console.log(this.view);
    console.log(this.getPos);
  }
}

and the same issue occurred. I also found out that, if you are on an empty line, create the NodeView, and type any character, it won’t call the constructor multiple times, but if at any point the line isn’t empty and the NodeView is created, it will re-render. I can send further Prosemirror-related code if it is needed. Thank you.

When I try it, adding a node view for image and typing around in a paragraph with images in it does not recreate the node view.

1 Like

Ah, I see. I have tried to strip every feature of my editor, including a custom dispatchTransaction and other node views, yet the image views are still re-rendered after typing a single character after the node view. Could you elaborate on the common situations in which a node view is re-rendered? Thank you.

Are you running a recent version of prosemirror-view? Older ones had some bugs where this would happen. Again, during normal typing it shouldn’t, so if you can put your test case on jsbin or glitch or something, that would make it easier for me to figure out what’s going on.

1 Like

I’m currently running the most recent version of prosemirror-view. I just tested an image NodeView in this glitch, and from this gif glitch-demo

when you create an ImageView, then press a character right after, it is constructed again. I’m wondering now if it’s just expected behavior? Thank you in advance.

I’m not seeing the image view being recreated in that glitch when I type after the image.

I just tried it on different browsers and it seems that Firefox doesn’t seem to have this issue. Are you using Firefox as well?

I tested Firefox and Chrome.