Undo twice to undo adding a node


#1

Walter,

May I show you a video related with wrong ‘modified’ issue I referred in another topic a couple of days ago.

In this video, I add a node and undo once.
But still the status of the model is ‘modified’.
I do undo once again, then the model has changed to be ‘not-modified’.

I’m analyzing the “ExternalObjectsDropped” event listener, but I do not have any incomes.

    function onExternalObjectsDropped(e) {
        // stop any ongoing text editing
        if (_d.currentTool instanceof go.TextEditingTool) {
            _d.currentTool.acceptText(go.TextEditingTool.LostFocus);
        }

        // expand any "macros"
        _d.commandHandler.ungroupSelection();
    }

How may I analyze this issue.
Please help me.

Here’s the debug error message.

Change not within a transaction: !dChangedEvent.Insert parts: Layer “” new: -2 1
go-debug.js:35 Change not within a transaction: !d data: -2 new: -2
go-debug.js:35 Change not within a transaction: !d text: TextBlock("") old: Normal Node new:
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(NaN,NaN) new: Point(-104,33)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(-104,33) new: Point(-105,30)
go-debug.js:35 Change not within a transaction: !m loc: -2 old: -105 30 new: -75 45
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(-105,30) new: Point(-75,45)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(-105,30) new: Point(-75,45)
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(-75,45) new: Point(-60,45)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(-75,45) new: Point(-60,45)
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(-60,45) new: Point(-45,45)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(-60,45) new: Point(-45,45)
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(-45,45) new: Point(-30,60)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(-45,45) new: Point(-30,60)
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(-30,60) new: Point(-15,60)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(-30,60) new: Point(-15,60)
go-debug.js:35 Change not within a transaction: !dChangedEvent.Remove parts: Layer “” old: Node#5575(-2) 1


#2

Walter, I adds several logs in ‘ModelChanged’ listener.
And I found something strange.


DiagramManager.js:5027 onModelChanged:Insert null {category: “Normal”, key: -2, __gohashid: 5400}
go-debug.js:35 Change not within a transaction: !dChangedEvent.Insert parts: Layer “” new: -2 1
go-debug.js:35 Change not within a transaction: !d data: -2 new: -2
go-debug.js:35 Change not within a transaction: !d text: TextBlock("") old: Normal Node new:
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(NaN,NaN) new: Point(127,147)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(127,147) new: Point(120,150)
DiagramManager.js:5091 onModelChanged:StartedTransaction eg {tr: ya, Iw: “”, pn: “StartedTransaction”, ye: Y, ca: null, …}
DiagramManager.js:5094 onModelChanged:CommittingTransaction eg {tr: ya, Iw: “”, pn: “CommittingTransaction”, ye: Y, ca: null, …}
DiagramManager.js:4996 onModified dg {ca: E, ac: “Modified”, nx: null, Tw: null, sr: false}
DiagramManager.js:5097 onModelChanged:CommittedTransaction eg {tr: ya, Iw: “”, pn: “CommittedTransaction”, ye: Y, ca: null, …}
go-debug.js:35 Change not within a transaction: !m loc: -2 old: 120 150 new: 270 165
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(120,150) new: Point(270,165)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(120,150) new: Point(270,165)
go-debug.js:35 Change not within a transaction: !d position: -2 old: Point(270,165) new: Point(285,165)
go-debug.js:35 Change not within a transaction: !d location: -2 old: Point(270,165) new: Point(285,165)
DiagramManager.js:5041 onModelChanged:Remove {category: “Normal”, key: -2, __gohashid: 5400, loc: “285 165”, bounds: C} null
go-debug.js:35 Change not within a transaction: !dChangedEvent.Remove parts: Layer “” old: Node#5447(-2) 1
DiagramManager.js:5091 onModelChanged:StartedTransaction eg {tr: ya, Iw: “”, pn: “StartedTransaction”, ye: Y, ca: null, …}
DiagramManager.js:5027 onModelChanged:Insert null {category: “Normal”, key: -2, __gohashid: 5523}
DiagramManager.js:5094 onModelChanged:CommittingTransaction eg {tr: ya, Iw: “”, pn: “CommittingTransaction”, ye: Y, ca: null, …}
DiagramManager.js:5097 onModelChanged:CommittedTransaction eg {tr: ya, Iw: “”, pn: “CommittedTransaction”, ye: Y, ca: null, …}


This log shows that the process works by ‘insert’ - ‘remove’ - ‘insert’ sequence.
The first ‘insert’ adds a node and ‘remove’ removes it.
They has same __gohashid on newValue in insert and oldValue in remove.
The second ‘insert’ adds a new node again.
It has another __gohashid.

Still I don’t know what this means.


#3

I don’t understand why you are getting all of those “Change not within a transaction” warnings. When I implement “Changed” and “ModelChanged” DiagramEvent listeners in the Macros sample (which you seem to have started from), I do not get those warnings.

The cross-diagram drag-and-drop creates temporary nodes in the model and diagram when the mouse enters the target diagram. It removes them when leaving the diagram and when the drag-and-drop stops. But upon a successful drop, it obviously still needs to add the real data to the model and create the corresponding nodes and links for real in the diagram.


#4

Okay, now I understand the process that add a node.

I’ll find where “Change not within a transaction” occurred.


#5

Walter,

I’d like to check your latest reply again.

You explained ‘cross-diagram drag-and-drop’ to me.

By your explanation, is it expected that should undo twice to revert a node added by ‘cross-diagram drag-and-drop’?


#6

If you try any of the samples that have two diagrams that support dragging from one to the other, such as when one is a Palette, you will find that a successful drag-and-drop can be reversed with a single Undo command.


#7

walter, thank you for your confirmation.
I’m analyzing the ‘modified’ issue more exactly based on your confirmation.

I’m very suffered by the issue.
Quite many actions makes wrong ‘modified’ issue in my project.
It is now time to solve this problem that I’ve accumulated.
It should not be neglected anymore.
I’m doing my best to resolve this.
Please help me sometimes.


#8

I don’t have enough pertinent information to be able to guess about your problem. I suggest that you remove event handlers and listeners and method overrides, simplifying until you can narrow down the cause of the problems.


#9

Walter,

I have a question and I need your advice.
It’s a little long story.

I have a feature that shows the scale of node in dynamic.

I have 12 types of node and 4 ‘stand alone’ types of them.
Stand alone types would not be connected with any one.

The other types are scale up and down by the zoom level that means the ‘scale’ value of the diagram.
But stand alone types always keep a certain size correspond to scale == 1.0 on the screen(monitor) when diagram.scale >= 1.0.

Let me show you below.


I uses below function to implement this feature.

    function updateEachNodeScale(newscale) {
        // _DEFAULT_SCALE = 1.0
        if (newscale > _DEFAULT_SCALE)
            return;

        var oldskips = _d.skipsUndoManager;
        _d.skipsUndoManager = true;
        _d.startTransaction("updateEachNodeScale");

        _d.nodes.each(function(node) {
            if (new Set(["Comment", "Dict", "Replace"]).has(node.category)) {
                node.scale = _DEFAULT_SCALE / newscale;
            }
            else if (node.category == "Gain" && node.findNodesConnected().count == 0) {
                node.scale = _DEFAULT_SCALE / newscale;
            }
            else {
                return;
            }
        });

        _d.commitTransaction("updateEachNodeScale");
        _d.skipsUndoManager = oldskips;
    }

And I call this function on the listener function for ViewportBoundsChanged event.

    function onViewportChanged(e) {
        if (_trace_event_) console.log('onViewportChanged', e);
        if (!_d1Initialized) return;

        _isD1PositionChanged = true;

        var diagram = e.diagram;
        if (e.subject.scale !== diagram.scale) {
            updateEachNodeScale(diagram.scale);
        }

        syncScaleAndPosition();
    }// end of function onViewportChanged(e)

It is working fine(not fire ‘modified’) on zooming by mouse scrolling like the video over there.

And I have another feature ‘node search’.

The searcher call below function to show the node found after searched a node.

    function highlightNode(key) {
        var node = _d.findNodeForKey(key);
        if (!node) return;

        _d.scale = _DEFAULT_SCALE;
        _d.select(node);

        setTimeout(function() {
            _d.centerRect(node.actualBounds);
        },100);
    }// function highlightNode(key)

This function fires ViewportBoundsChanged event on the line _d.scale = _DEFAULT_SCALE; and the flow goes from onViewportChanged() to updateEachNodeScale().

I added logging lines on to all event listeners according to your advice.

And I guess that ‘updateEachNodeScale()’ fires ‘Modified’ based on the log message below, right?
Modified is enclosed betweenCommitingTransaction and CommittedTransaction.

cf.

If I comment _d.scale = _DEFAULT_SCALE; out in highlightNode(), the problem not happen.
if I comment updateEachNodeScale(diagram.scale); out in onViewportChanged(), the problem not happen.

At last, here is my question.

Why highlightNode() makes the problem but mouse scroll zoom does not?
Even they all fires ViewportBoundsChanged event and perform updateEachNodeScale().
It looks that _d.skipsUndoManager = true; is not working at all.

Thank you walter, always.


#10

Setting Diagram.skipsUndoManager only stops the UndoManager from recording ChangedEvents in the current Transaction… It expressly does not stop the delivery of those ChangedEvents to any listeners for ChangedEvents.

What exactly is the problem that you are worried about? I do not notice any warnings about “Change not within a transaction” in your latest screenshot of console output.


#11

I do want node.scale = _DEFAULT_SCALE / newscale; does not make ‘modified’ status.
I want to make node.scale be considered unchanging.

Sorry I cannot understand your answer exactly.
I heard your answer as Modified event would be created even if I set Diagram.skipsUndoManager to true but the UndoManager takes nothing to undo.
Is this right?
But my code is still stacking things(transaction) into the UndoManager even within Diagram.skipsUndoManager block.

Then, how can I block the status changing from ‘not modified’ to ‘modified’ in this situation. (myabe in updateEachNodeScale())

If I remove _d.startTransaction("updateEachNodeScale"); in updateEachNodeScale(), another Transaction that is type of Layout occurs.

And even if I set Diagram.skipsUndoManager like below, still the ‘modified’ event happened.

    function updateEachNodeScale(newscale) {
        if (newscale > _DEFAULT_SCALE)
            return;

        var oldskips = _d.skipsUndoManager;
        _d.skipsUndoManager = true;
        //_d.startTransaction("updateEachNodeScale");

        _d.nodes.each(function(node) {
            if (new Set(["Comment", "Dict", "Replace"]).has(node.category)) {
                node.scale = _DEFAULT_SCALE / newscale;
            }
            else if (node.category == "Gain" && node.findNodesConnected().count == 0) {
                node.scale = _DEFAULT_SCALE / newscale;
            }
            else {
                return;
            }
        });

        //_d.commitTransaction("updateEachNodeScale");
        _d.skipsUndoManager = oldskips;
    }

I cannot analyze who fires ‘Layout’ transaction on where.
And still I don’t know why I cannot block changing to ‘modified’ status even within Diagram.skipsUndoManager block in updateEachNodeScale().

In conclusion,

  1. I do want to update node.scale with not to make the status of model ‘modified’.
  2. Who makes the Layout transaction.
  3. How can I block the Layout transaction not to make the status of model ‘modified’.

thank you, walter.


#12

Sorry about this.
I’ve turned off go-debug.js here.

“Change not within a transaction” is still occurred.
I think I have many kinds of wrong “modified” problem in several codes in my gojs application.
And I have to solve them all now.

Maybe “Change not within a transaction” and this problem related with a feature that shows the scale of node in dynamic for the stand alone types would be independent.


#13

I tried these two DiagramEvent listeners:

            "Modified": function(e) { console.log("MODIFIED"); },
            "ViewportBoundsChanged": function(e) {
              if (e.subject.scale !== e.diagram.scale) {
                console.log("changing scale");
                e.diagram.commit(d => d.nodes.each(n => n.scale = 1/d.scale), null);
              }
            },

Note that the null second argument to Diagram.commit automatically temporarily sets Diagram.skipsUndoManager to false.

I did not get any “MODIFIED” console message when zooming in and out. However the zooming did result in “changing scale” messages. After several zooms, I found that myDiagram.isModified remained false.


#14

walter,

I was able to reproduce the problem thanks to your advice.
I could write the code based on ‘stateChart’ sample on gojs ‘Samples’.
I sent the code to ask you to analyze it to gojs nwoods.com.
I think it’s related with ‘diagram.model.isReadOnly’.

And I have another ‘modified’ problem related with ‘isSelected’ that looks more complex.

thank you always.


#15

OK, we’ll continue this discussion via email.


#16

Sorry for the untimely solution check, finally I have last one issue related with ‘Change not within a transaction’ left.
I’m going to analyze this and I hope to be in touch to you soon here.
Still I have to undo twice after add a node to make not modified status back.

I sorry again.
I couldn’t distinguish several divided issues and I’ve mix them in one topic.