Force nodes of specific type to re-render

I have a simple leaf node that represents a variable. Its only attribute is the name of the variable. In toDOM() the actual value of the variable is used to as text content of the node. Roughly like this:

[ 'span', { class: 'variable' }, variableValue ]

The problem is that variableValue is stored and modified apart from the document. Hence changes to a variable’s value obviously won’t be reflected in the editor.

One approach I’m trying out is to force the editor to re-render all “variable nodes” whenever any variable values have changed. So far I haven’t found a way to do that except for updating the entire document/editor, but that seems overkill.

How can I force a re-render/update of all nodes of a specific type?

There are also decorations and node views but I have trouble finding good examples on how to use them. I have no idea whether they’ll actually be useful for my use-case.

You’ll want to use a node view here, since those are the only way to get direct control over a node’s rendering and DOM lifecycle, but those alone still don’t help much here, since they are only given a chance to update themselves when the node they represent changes in the document, or if any of the node decorations on that node changes. So you could write an extension that maintains decorations on all nodes of this type, and when the external data changes, makes sure to update them all, which will cause the node views’ update method to be called, allowing them to read the changed data and update their DOM content.

Wow, more difficult than I’ve expected. Thank you for the insight. I’ll give it a try and report back.

I’ve got it working with NodeView and Decoration.

Updating my variable values through a Transaction updates related Decorations which in turn updates related NodeViews. All encapsulated nicely in a Plugin and the variable values are now part of the state of my Plugin. The respective NodeSpec is also defined by the Plugin and accessed using plugin.nodeSpecs.

But I still have to access a variable’s value in NodeSpec.toDOM() for copy & paste to work properly. Unfortunately I’ve only got access to the Node and not the EditorState, so I cannot access the variable values from my Plugin's state.

There are multiple potential paths forward now:

  1. I find a way to access a Plugin's state from within NodeSpec.toDOM().
    I don’t think there is a proper one.
  2. I maintain a reference the EditorView from within my NodeSpec in order to access the current EditorState.
    That doesn’t sound clean.
  3. I allow my Plugin to provide a DOMSerializer that can serialize my NodeSpec. The problem here is the same as with toDOM() though: I don’t have access to the EditorState.
    So also not clean.
  4. I put all state of a variable (label, value, etc.) directly into all Nodes that reference it. I replace these Nodes every that state changes.
    That doesn’t sound right either. The node is only a simple variable reference with a name. Adding the value and other information to it shouldn’t be necessary.

It’s basically similar to the issue that I already have with state-sensitive text serialization, just with HTML this time:

Desired HTML output:

<span data-variable="varname">varvalue</span>

(varname is a Node attribute, varvalue is Plugin state)

Desired text output:

varvalue

Am I missing something here or is there no good solution to that problem?

No, this kind of thing is definitely tricky, and usually solved by going through some global state (which, depending on how your variables work, might not be practical). Creating a DOMSerializer that closes over a reference to (or getter function that can retrieve) the view might be the least problematic approach.