Associate nodes with database entries, inspect changes

Hi,

So right now I have a hashTag node type, and every time a hashTag is created and deleted, I’d like to insert/delete the corresponding database entry.

After looking around, I added a dispatchTransaction callback for the view, which passes in a Transaction.

In Prosemirror Dev Tool, I seemed to have access to the node through tx > steps > 0 > slice > content > content > hashTag node. But in code (TypeScript), I can’t seem to access slice on the Step. I tried converting it to ReplaceStep to no avail. Is there a way to get access, or am I doing it wrong?

Or maybe taking a step back, am I approaching this problem correctly?

Thanks in advance!

1 Like

Not all step types have slices. You could do an s instanceof ReplaceStep || s instanceof ReplaceAroundStep check to narrow the type, or you could iterate over the parts of the new doc covered by the step (with the step map’s forEach method).

Thanks for the pointers.

It looks like slice is not exposed in ReplaceStep and ReplaceAroundStep though: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/prosemirror-transform/index.d.ts#L347 Is there another way to access them?

But I guess to detect node removal, I still need to compare docs right? (I couldn’t find any info in the slice about what node was removed) So for that would the last doc in tr.docs give me a point of comparison?

Oh, good point, those are indeed not public it seems.

But indeed, to detect removal you’ll also need to iterate over the deleted range. The step maps also give you the information you need there.

Good to know.

So I’m using step.getMap() like this:

          const lastDoc = tr.docs[tr.docs.length - 1]
          const thisDoc = tr.doc

          tr.steps.forEach(step => {
            step.getMap().forEach((oldStart, oldEnd, newStart, newEnd) => {  

              const newNodes: Node[] = []
              thisDoc.nodesBetween(newStart, newEnd, newNode => { newNodes.push(newNode) })
              lastDoc.nodesBetween(oldStart, oldEnd, oldNode => {
                if (oldNode.type === schema.nodes.hashTag && !newNodes.includes(oldNode)) {
                  console.log('hash tag deleted', oldNode)
                }
              })
            })
          }

But it seems oldEnd was out of bound in lastDoc.nodesBetween(oldStart, oldEnd, ...

I assumed oldStart and oldEnd refers to the previous doc, and newStart and newEnd refers to the current doc, is that correct?

1 Like

Oh, I think I got it. Looks like each step should use its own doc through tr.docs[stepIndex].

Yes, that’s the idea — a step map indicates a difference between the docs before and after that step.

Thanks for the help. Finally things are coming together.