Updating the attributes of an inline leaf node

I’m currently trying to port some code to work with the latest master branch, but I’m having problems updating the attributes of an inline leaf node.
With the old version I used the setNodeType method, but it seems like this method does not accept leaf nodes anymore.

This is the code I used before:

pm.tr.setNodeType(leafNodePos, leafNodeType, newAttributes).apply();

It now throws the error “No content node at given position”.

Is there a new recommended way to update the attributes of a leaf node?

Are you sure you’re passing in a position pointing directly in front of the node you want to change? That’s the error raised when there isn’t a node after pos.

I actually tried both positions with the new version, but couldn’t get it to work. I am testing this with the following document structure, where progress_indicator is an inline leaf node:


Running pm.tr.setNodeType(0, pm.schema.nodeType('progress_indicator'), {}).apply(); results in the error "Content can not be wrapped in ancestor ‘progress_indicator’ ". The error is caused by the ancestor step, because my progress_indicator node returns null in its contains method. When I change the contains method to return NodeKind.inline as a workaround, I get the error “< progress_indicator(progress_indicator) > cannot be placed in doc”.

I’m not sure how to get this to work using the setNodeType method. Ideally, I would like to use a method, which simply updates the attributes of a node at the given position. In my example this could look like pm.tr.updateAttributes(1, {}).apply().

Passing 1 as the position should work in that document. I can’t tell from your description if that’s what you mean by ‘tried both positions’.

Yes, that’s what I meant with ‘tried both positions’. Passing 1 as the position causes the “No content node at given position” error, because of the node.type.contains check in https://github.com/ProseMirror/prosemirror/blob/1af2acaf94adb61291573ec7aca8512b8cc32929/src/transform/ancestor.js#L218

Passing 1 as the position and returning NodeKind.inline from the node’s contains method works! But having to change the schema of my progress_indicator node to achieve this feels wrong. This node should be a leaf node and should not be able to contain any other nodes. Removing the node.type.contains check from setNodeType would solve this problem, but you probably put it there for a reason. What would you suggest in this situation?

Ah, I see what’s happening now. With the new position scheme there is no longer a valid position inside of a contentless node, so setNodeType can’t use an ancestor step (which needs to refer to the inside of the node) to change the node’s type. This patch makes it magically do the right thing in such a case. The problem you (or someone else?) initially had with markers around such nodes getting cleared when replacing a node has been solved, so I think that’ll address your problem.

Ok, that makes sense. Thanks for the patch, I can confirm that it fixed it for me and it also works with markers as I’m using these for this inline node.
Someone else raised the marker issue, but I experienced it too and it was the reason I moved from replaceWith to setNodeType in the first place. So it’s great that the marker issue was fixed too, now that replaceWith is used for this special case.