Error when creating NodeSelection

Hey there,

I’m trying to find a node in the current selection that has a given mark and select it in the editor.

For this, I start by obtaining the node position with doc.nodesBetween. I exptected to be able to select the node with the mark with NodeSelection. However, when I create it with $pos = tr.doc.resolve(pos) and new NodeSelection($pos), I always receive an exception: Uncaught TypeError: this.nodeDOM.classList is undefined.

Strangely, when I add 1 to the position I get from doc.nodesBetween, the selection is applied - but not on its first character ($pos = tr.doc.resolve(pos + 1) ):
Screenshot from 2022-02-14 00-20-48

How can I make sure the entire node is selected instead? Am I missing something?

This is what I’m doing:

const state = editorView.state
const { doc, selection } = state
doc.nodesBetween(selection.from, selection.to, (node, pos) => {
  if (node.marks && schema.marks.myMark.isInSet(node.marks)) {
    const tr = state.tr
    const $pos = tr.doc.resolve(pos)
    tr.setSelection(new NodeSelection($pos))
    editorView.dispatch(tr)
  }
})

Thanks in advance :slight_smile:

How about using NodeSelection.create(doc, pos) replace new NodeSelection?

doc.nodesBetween(selection.from, selection.to, (node, pos) => {
  if (node.marks && schema.marks.myMark.isInSet(node.marks)) {
    const tr = state.tr
    tr.setSelection(NodeSelection.create(doc, pos))
    editorView.dispatch(tr)
  }
})

Thanks for your suggestion, @percy507!

Unfortunately this results in exactly the same behavior:
tr.setSelection(NodeSelection.create(tr.doc, pos)) throws the Uncaught TypeError: this.nodeDOM.classList is undefined error while tr.setSelection(NodeSelection.create(tr.doc, pos + 1)) selects the node except for its first character.

It will be helpful for handling your issue if you provide a demo through https://glitch.com/.

Thanks for the suggestion, @percy507!

I’ve remixed the sample project here with a button that does what my code above does:

As you can see, it triggers the same error from ProseMirror (it goes away if you change pos to pos + 1 though strangely the selection doesn’t actually change then)

You can’t create a node selection on a text node (or a non-selectable node), and it looks like your code is doing just that.

Ah, thanks!

So now I’ve tried to manually create the selection with new Selection like this:

        const tr = state.tr;
        const $anchor = tr.doc.resolve(pos);
        const $head = tr.doc.resolve(pos + node.nodeSize);
        const selection = new Selection($anchor, $head);
        tr.setSelection(selection);
        window.view.dispatch(tr);

I’ve also updated the Glitch demo here:

Unfortunately, this results in another error: Uncaught TypeError: t.selection.eq is not a function.

Any ideas why this also doesn’t work?

Selection is an abstract base class and cannot be used directly (rather, inherit from it, and implement the required methods).

Okay, understood, thanks for clarifying this, @marijn!

So for anyone else who is facing a similar problem: You can change the selection to fully contain a text node like this:

const tr = state.tr
const selection = TextSelection.create(tr.doc, pos, pos + node.nodeSize)
tr.setSelection(selection)
window.view.dispatch(tr)