Undo & Redo is not working when focus is on Node/Link

Undo & Redo is not working when focusing on Node/Link.

When we drag the nodes/links the default focus is on the node we dragged. When we try command+z undo/redo is not working until we explicitly focus on canvas. Is this expected behavior? If not, is anything to be handled?

We added config:

‘undoManager.isEnabled’: true,
‘undoManager.maxHistoryLength’: 10,

I tried using the diagram.focus() undo is working only once. For multiple undo’s are not working with this.

Yes, by default only the Diagram’s Div element handles keyboard input events, so the Diagram must have focus in order for it to receive keyboard events if you want it to execute keyboard commands.

You could define a keyboard input event handler on an HTML element that encloses the Diagram’s Div. Or you could call Diagram.focus when focus is elsewhere.

Perhaps when the users selects a Part you change focus to be in some other HTML element? Either don’t change focus to there, or automatically change focus back to the diagram after the user is finished there, or handle some or all keyboard events and redirect them to the Diagram.

By the way, 10 seems a rather short undo history length.

I tried the same scenario for gojs samples. There is node is selected(focus is on the node) but still multiple undo’s are happening @walter |

I tried Diagram.focus on the mouse move event, but the undo is still happening for only a single undo action, not multiple. undoes.

It sounds like the Diagram is losing focus unexpectedly.

Set a breakpoint in your Diagram initialization code, to see whether the Diagram is being re-created unnecessarily.

If that is not the problem, try recording a screen video of your app showing all of the diagram interaction leading up to the problem state.

By the way, keyboard focus cannot be given to an individual Node or Link. It can only go to a whole Diagram.

We tried adding a breakpoint in the diagram initialization code, but it’s been calling 3 times. It’s needed as per the requirement is what I got to know from our team.

I am attaching a screen recording @walter please have a look.
Screen Recording 2024-12-13 at 2.12.13 PM (3)

The first thing I would do is fix the errors that happen.

Second, I don’t understand those “Render duration” messages – those times seem terribly long, and thus very suspicious. What’s going on then?

Third, why is your diagram initialization code running three times? (I assume you were not counting your palette initialization code.)

Fourth, I recommend using go-debug-module.js (or go-debug.mjs, the same file) in order to catch more errors.

Hi @walter I debugged & got to know that in selectionchanged, we have a code to update diagram model data (diagram.model.commit(m => {});), because of which we are unable to undo/redo/delete while the selection is on node.

Any thoughts here?

As documented, the “ChangedSelection” DiagramEvent listener must not modify the diagram, including its model.

“ChangedSelection” , an operation has just changed the Diagram.selection collection,
which is also the value of the DiagramEvent.subject;
do not make any changes to the selection or the diagram in the event listener; note that just setting Part.isSelected will not raise this event, but tools and commands will.

Or maybe you’re talking about the Part.selectionChanged event handler. http://localhost:8080/api/symbols/Part.html#selectionChanged Hmmm, its documentation doesn’t state the same restriction, but it should.

In both cases, that means not executing any transactions that record any ChangedEvents.

So, why are you executing that transaction? Is it because users have updated some fields that reflect state in the model? It’s certainly reasonable for some HTML DOM event handlers to execute a transaction. For example, the GoJS Data Inspector does that. But such transactions are necessarily asynchronous, not synchronous in a DiagramEvent listener or selectionChanged event handler.

Hi @walter, As per your comment, we tried to avoid **model commit **- related changes. But we are still facing a similar issue. We debugged through it and found we introduced an accessibility feature. To do that, we used invisible buttons, and using those buttons, we navigated. To achieve that, we explicitly focused on the invisible buttons.

I think that’s changing the diagram focus. Without that code, it’s working. Any thoughts here? Any alternatives?

Yes, if your code is giving focus to an HTML button, the Diagram/Div is losing focus.

Either pass unhandled keyboard events to the Diagram or handle what you need in the diagram by overriding CommandHandler.doKeyDown and calling the super method for all keyboard events that your code doesn’t handle.

Have you seen the AriaCommandHandler? Its implementation is at either extensionsJSM/AriaCommandHandler.ts or extensions/AriaCommandHandler.js. That can give you an example of implementing such behavior.

@walter I tried doing as below:

  "commandHandler.undo": function(event) {
        this.diagram.undoManager.undo();
  }

This is working only for the first undo. The next undo action is not working. Is there something I am missing here? ANy other way to achieve?

Thanks

I did not suggest that you should override CommandHandler.undo. In fact, that it exactly how it is defined by default, except that there is no argument to the method.

I did suggest handling keyboard events on your HTML button and passing most of the keys on to the Diagram.

I also suggested an alternative: not passing focus to that HTML button but instead handling the additional events on the Diagram, and perhaps passing some of the events onto elsewhere.