Uncaught TypeError: Cannot read property 'previousSibling' of undefined when using a custom node view

I’m still relatively new with prosemirror. I have this custom node definition :

const editorTitle = {
        name: 'editorTitle',
        content: 'text*',
        isTextblock: true,
        attrs: {
          class: { default: 'editorTitleId' },
        },
        group: 'block',
        parseDOM: [
          {
            priority: 51, // must be higher than the default image spec
            tag: 'div[class]',
            getAttrs(dom) {
              const nodeClass = dom.getAttribute('class');
              if (nodeClass != 'editorTitleId') {
                return false;
              }
              return true;
            },
          },
        ],
        toDOM(node) {
          return ['div', { class: 'editorTitleId' }, 0];
        },
      };

and this related custom node view :

 class editorTitleView {
      setDataBeforeContent(outer, textContent) {
        const dataBeforeContent = textContent ? '' : 'Untitled item';    
        outer.setAttribute('data-before-content', dataBeforeContent);
      }
      findNodePosition(doc, target, not) {
        let result = -1;
        doc.descendants((node, pos) => {
          const condition = not ? target !== node : target === node;
          if (condition) {
            result = pos;
            return false;
          }
        });
        return result;
      }
      constructor(node, view, getPos) {
        const vm = this;
        const outer = document.createElement('div');
        outer.textContent = textContent;
        outer.classList.add('editorTitleId');
        outer.setAttribute('contenteditable', true);
        vm.setDataBeforeContent(outer, textContent);
        $(outer).on('keydown paste', ev => {
          const { currentTarget, keyCode, type, originalEvent, ctrlKey } = ev;
          const isPaste = type == 'paste';
          if (![8, 46, 17].includes(keyCode) && (!ctrlKey || isPaste)) {
            const clipboardData = originalEvent.clipboardData || window.clipboardData;
            let value = clipboardData && isPaste ? clipboardData.getData('text') : undefined;
            if (!isPaste) {
              value = currentTarget.value;
            }
            let { tr, doc } = view.state;
            const _node = doc.content.content[0];
            const nodeStartPos = vm.findNodePosition(doc, _node);
            const { type } = _node;
            if (type.name == 'editorTitle') {
              if (nodeStartPos != -1) {
                tr = tr.setNodeMarkup(
                  nodeStartPos,
                  undefined,
                  { value: value }, 
                );
                view.updateState(view.state.apply(tr));
              } else {
                console.error('nodeStartPos == -1 !!!!!!!!');
              }
            }
          }
        });
        setTimeout(() => {
          outer.focus();
        }, 150);
        vm.dom = outer;
      }
      ignoreMutation() {
        return true;
      }
      update(node, decorations) {
        return false;
      }
      selectNode() {
        console.log('editorTitleView :: selectNode ');
      }
    }

FYI , i’m using ‘use-prosemirror’, so this is how i pass mySchema

const mySchema = new Schema({
    nodes: { ...nodes, resizableImage, editorTitle },
    marks: schema.spec.marks,
  });
const [state, setState] = useProseMirror({
    doc: DOMParser.fromSchema(mySchema).parse(prevsioulyPersistedContent goes here..),
    schema: mySchema,
    plugins: [
      keymap(baseKeymap),
    ],
  });
<ProseMirror
        state={state}
        dispatchTransaction={transaction => {
          console.log('dispatchTransaction ');
          const { view } = useProseMirrorComp;
          let newState = view.state.apply(transaction);
          persistContentInBackend(state, newState, mySchema, props);
          view.updateState(newState);
        }}
        ref={r => {
          useProseMirrorComp = r;
        }}
        nodeViews={getNodeViews(resizableImage, editorTitle)}
      >
        <div id="content" /></ProseMirror>

The initial display is fine but then when i just click on the dom element generated by the custom view i get this error

Uncaught TypeError: Cannot read property 'previousSibling' of undefined
    at domIndex (index.js:34)
    at CustomNodeViewDesc.localPosFromDOM (index.js:782)
    at NodeViewDesc.posFromDOM (index.js:822)
    at posFromCaret (index.js:336)
    at posAtCoords (index.js:406)
    at EditorView.posAtCoords$1 [as posAtCoords] (index.js:4885)
    at handlers.mousedown (index.js:3523)
    at HTMLDivElement.view.dom.addEventListener.view.eventHandlers.<computed> (index.js:3295)

Somebody has a clue why it does happen ?

I think upgrading to prosemirror-view 1.18.0 should make this go away.

1 Like