Undomanager question

1521
7
09-18-2014 06:20 AM
TimWitt2
MVP Alum

Hey everybody!

I was able to successfully use the undo manager in my graphics application, by following this example

Graphics with undo redo | ArcGIS API for JavaScript

It works great when I just create graphics and delete them with the undo button.

Now I ran into the following problem. In my application you can right-click a graphic and then delete it. This throws off my undo / redo button, since it only works if the "deletion" goes linear How would I handle a case like this?

I was playing with the undoManager.remove() method by also removing the specific graphic from the operation. But then I didn't know what to do if I want to get it back.

Thanks!

Tim

0 Kudos
7 Replies
JonathanUihlein
Esri Regular Contributor

Hi Tim.

You are right in using undoManager.remove() for your use case.

We will force the deletion to go linear by doing the following:

After removing the graphic using remove(), you should immediately re-add the graphic back using add(), then call undo().

This will make the graphic look 'deleted', but will still be accessible by redo(), if you desire.

I have not tested this but in theory, it should work. Also... there may be flickering, I'm not sure.

Let me know if this works out.

TimWitt2
MVP Alum

Hey Jonathan,

I eventually figured it out and what you described is what I ended up doing

Here is the code I used in my delete button:

  var MenuDelete = new MenuItem({

                label: "Delete",

                onClick: function () {

  var operation = new CustomOperation.Add({

  graphicsLayer: map.graphics,

  addedGraphic: selected

  });

  undoManager.add(operation);

  undoManager.undo();

  undoManager.remove(curcount);

                }

            });

"selected" is the currently selected graphic and "curcount" is the position of the currently selected graphic in my operation.

It seems to be working without flickering. http://jsfiddle.net/timw1984/4p7d241v/embedded/result/

Thanks!

Tim

0 Kudos
TimWitt2
MVP Alum

Hey Jonathan Uihlein‌ ,

I needed to redo the code, which now works if I delete 1 graphic in the middle of my other graphics, but if I delete another graphic straight after it will only redo the latest deleted graphic. I assume this happens because the redo stack gets cleared whenever you use the add() method.

Here is my code:

var MenuDelete = new MenuItem({

                label: "Delete",

                onClick: function () {

                      if (undoManager.length < "2") {

                           var operation = new CustomOperation.Add({

                           graphicsLayer: map.graphics,

                           addedGraphic: selected

                           });

                           undoManager.add(operation);

                           undoManager.undo();

                           undoManager.remove(0);

                      } else {

                           var operation = new CustomOperation.Add({

                                graphicsLayer: map.graphics,

                                addedGraphic: selected

                               });

                           undoManager.add(operation);

                           undoManager.remove(curcount);

                           undoManager.undo();

                      }

                 }

});

Here is the full code: Advanced Draw - JSFiddle

Any help is appreciated!

Tim

0 Kudos
JonathanUihlein
Esri Regular Contributor

Hey Tim! I had a few minutes to check out the logic in undoManager and you are right that the add() function calls this.clearRedo() after. However, this is expected and not the cause of your issue. You changed up the order of operations I suggested in my previous post.

  1. remove()
  2. add()
  3. undo()

Remove uses splice for the historyStack. add() will add your graphic back onto the front of the stack, and undo() should step back to the appropriate position.

You are using add, undo, remove and add remove undo, in those orders respectively. Logically, this will break the code, as you are seeing.

I also ran your application against a newer internal version of the API, which uses a newer DOJO, and found an issue with the following:

registry.forEach(function (d) {

    // d is a reference to a dijit

    // could be a layout container or a button

    if (d.declaredClass === "dijit.form.Button") {

        buttonclick = d.on("click", activateTool);

    }

});

You might want to change the above to this to avoid having to do it later. The reason for this is Registry is an object, not an array, and at certain points the forEach function might not be scoped.

array.forEach(registry.toArray(), function (d) {

    // d is a reference to a dijit

    // could be a layout container or a button

    if (d.declaredClass === "dijit.form.Button") {

        buttonclick = d.on("click", activateTool);

    }

});

TimWitt2
MVP Alum

Hey Jonathan Uihlein,

thanks for the help, especially for giving me the heads-up about the future changes.

After using the logic you have suggested I didn't need the if/else statement. I just wanted to make sure I understood you.

Once I use the delete button to get rid of the currently selected graphic and afterwards delete another graphic, by using the delete button, I will only be able to redo the latest deleted graphic, since my delete button would trigger the add() method and therefor remove the redo functionality of the first deleted graphic, correct?

Sorry I'm not very advanced in javascript, that's why it takes me a little longer!

I hope this sentence makes sense.

Here is the latest code: Advanced Draw - JSFiddle

Again thanks for the help!!!

Tim

0 Kudos
JonathanUihlein
Esri Regular Contributor

No worries! I'll take another look later today when I free up a bit and let you know what I find.

In my opinion, I think the undoManager needs a splice function that doesn't reset the stack.

This may be something that we end up implementing in the future

0 Kudos
TimWitt2
MVP Alum

Thanks for all the help!

Btw I like the LP's in your picture Time to fire up some Champion Sound!

0 Kudos