How to manage selection when bulk inserting nodes/text?

#1

I have hierarchical data which I’m letting users select from. The data selections need to be created in the editor as lists/nested lists and prepopulated with the data. I’m having a hard time conceptualizing the indexing in prosemirror and manipulating it to insert the proper node and text.

When data is selected, I have a handler that is called that should clear the document, create the structure for the selections, and then loop over the selections to 1)create the element and 2) insert the data.

//Clear Document
let docNode = state.doc
let start = 0
let end = start + docNode.content.size

tr.replaceWith(start,end, Fragment.empty)

//Create structure
let strut = this.createNodesStructure(paragraphs)

//Loop with tr
Object.keys(strut).forEach((key)=>{
  let paragraph = strut[key]

  tr.insert(tr.selection.anchor, paragraph.node)
  //Insert text to the end of the doc, probably wrong, but works on top level lists
  tr.insertText(paragraph.paragraph.paragraphText, tr.doc.resolve(0).end() - 2)

  if(paragraph.children.length > 0){
      //Set Selection to end of previously inserted node?
      //Insert<ul>
      //Insert child <li> node
  }
})

Trying to move the selection as in How to Select a Node Immediately After Inserting It, I’ve been getting a number of position errors and resolve() on the inserted nodes typically resolves to 0, which I don’t understand. I also can’t use replaceSelectionWith as the selection seems to span the entire document.

Any help would be appreciated. Thanks.

#2

resolve should (almost) never be called on any node that’s not the top-level document node, and it returns a resolved position not a number, so your formulation here rather sounds like you’re using it wrong.

If you’re clearing the whole document and replacing it with another, why are you even bothering with selections and individual insert and replaceText updates? Wouldn’t it be easier to generate a document that has the desired shape, given your source data, in one go?

#3

Good idea. I’ve been in the weeds on this for too long.

You’re referencing this part of the docs, right? Would there be any significant pros/cons to this approach compared to generating html and parsing that into the editor?

let doc = schema.node("doc", null, [
  schema.node("paragraph", null, [schema.text("One.")]),
  schema.node("horizontal_rule"),
  schema.node("paragraph", null, [schema.text("Two!")])
])
#4

Yes. You could then do oldDoc.tr.replace(0, oldDoc.content.size, newDoc.slice(0, newDoc.content.size)) to reset the document without creating an entire new state.

Both work, but by building up the document like this there’s no extra indirection between the data structure you create and the thing that ends up in the editor, which might help with clarity.