Understanding undo/redo

Posted by: adrien.corbin on 2 October 2018, 11:56 pm EST

    • Post Options:
    • Link

    Posted 2 October 2018, 11:56 pm EST

    I am trying to understand how undo/redo work to properly implement some custom commands.

    According to the documentation http://help.grapecity.com/spread/SpreadSheets11/webframe.html#undo.html, if I understood property, custom command will send undo with Ctrl-Z.

    I made a small sample to try, but undo is never called when using ctrl-z.

    
            spread.commandManager().register('undo', {
                canUndo: true,
                execute: (context, options, isUndo) => {
                    if(isUndo)  console.log('undo');
                    else console.log('do');
                }
            });
    
           spread.commandManager().setShortcutKey('undo', GC.Spread.Commands.Key.a, true, false, false, false);
    
    

    I read about undoManager but I am not ```

    The default instance can be provided with spread ```
    this.workbook.undoManager()
    

    For this reason I tried expanding my example with this, but it still does not trigger the undo.

            
    spread.commandManager().register('undo', {
                canUndo: true,
                execute: (context, options, isUndo) => {
                    if(isUndo)  console.log('undo');
                    else console.log('do');
                }
            });
    
            spread.commandManager().register('doundo', {
                canUndo: false,
                execute: (context, options, isUndo) => {
                    spread.undoManager().undo();
                }
            });
    
            spread.commandManager().setShortcutKey('undo', GC.Spread.Commands.Key.a, true, false, false, false);
            spread.commandManager().setShortcutKey('doundo', GC.Spread.Commands.Key.a, true, true, false, false);
    
    

    Is it possible to have some more explanation on how undo/redo works?

  • Posted 4 October 2018, 10:06 pm EST

    Hello,

    Undo and Redo are the methods UndoManager class which you can further customize as per your need. Also you can use Ctrl + Z to undo an action in the widget. You can then use Ctrl + Y to redo the action you cancelled.

    You can use ‘allowUndo’ property to enable or disable undo action in code.

    To know more about customizing Undo and Redo functions please go through the documentation here:

    http://help.grapecity.com/spread/SpreadSheets11/webframe.html#undo.html

    In case you have any questions or doubts please feel free to get back to me.

    Thanks,

    Deepak Sharma

  • Posted 5 October 2018, 12:04 am EST

    I read the documentation and I am wondering why in my example

    If I press Ctrl-A, it write to console ‘do’ and when I press Ctrl-Z (or Ctrl-Shift-A) is does not trigger the same command with isUndo = true.

  • Posted 8 October 2018, 1:59 am EST

    Hello,

    I am looking into this issue, I will get back to you soon.

    Thanks,

    Deepak Sharma

  • Posted 8 October 2018, 1:59 am EST

    Hello,

    I am looking into this issue, I will get back to you soon.

    Thanks,

    Deepak Sharma

  • Posted 8 October 2018, 11:28 pm EST

    Hello,

    I created a custom command and handled Ctrl+z, it worked fine:

    
     $(document).ready(function () {
                spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 3 });
                sheet = spread.sheets[0];
                spread.options.allowUndo = true;
    
                var myUndo = {
                    canUndo: true,
                    execute: function (context, options, isUndo) {
                        spread.undoManager().undo();
                        console.log(isUndo);
                    }
                };
    
                var commandManager = spread.commandManager();
                var commandName = "doUndo";
                commandManager.register(commandName, myUndo, null, false, false, false, false);
       commandManager.setShortcutKey(undefined, GC.Spread.Commands.Key.z, true, false, false, false);
               commandManager.setShortcutKey(commandName, GC.Spread.Commands.Key.z, true, false, false, false);
    
    
    

    There is no direct event to know when the undo command is initiated. The code above is the way to know when the undo is used with Ctrl+z since we are not using the default command.

    Thanks,

    Deepak Sharma

  • Posted 18 October 2018, 1:43 am EST

    The example above does not seem to work either.

    When pressing Ctrl+z does indeed trigger the spread.undoManager().undo().

    However the undo does not call the previous command with the undo parameter.

    By default, I do not need to override Ctrl-z and ctrl-y. What I expect and seem to be possible according to the documentation is that the custom command will be called with isUndo = true.

    This is what I am trying to represent with

            
    this.workbook.commandManager().register('customCommand', {
                canUndo: true,
                canRedo: true,
                execute: (context, options, isUndo) => {
                    if (isUndo) {
                        console.log('undo')
                    } else {
                        console.log('do')
                    }
                }
            });
    
            this.workbook.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.a, true, false, false, false);
            this.workbook.commandManager().setShortcutKey('customCommand', GC.Spread.Commands.Key.a, true, false, false, false);ute: (context, options, isUndo) => {
                    if(isUndo)  console.log('undo');
                    else console.log('do');
                }
            });
    
    
    1. Change cell B10 for ‘changed’

    2. When pressing Ctrl-A, should print ‘do’

    3. When pressing Ctrl-Z should print ‘undo’

    4. When pressing Ctrl-Z should set B10 to empty

    5. When pressing Ctrl-Y should set B10 to’ changed’

    6. When pressing Ctrl-Y should print ‘do’

    Currently, it undo B10 without doing the undo for the custom command.

    Is this possible or I misunderstand how commands works?

  • Posted 18 October 2018, 1:45 am EST

    Hello,

    Please have a look at the code below:

    
      var command = {
                    canUndo: true,
                    execute: function (context, options, isUndo) {
                        var Commands = GC.Spread.Sheets.Commands;
                        if (isUndo) {
                          
                            Commands.undoTransaction(context, options);
                         
                            return true;
                            console.log(undo);
                        } else {
                            Commands.startTransaction(context, options);
                            var sheet = context.getSheetFromName(options.sheetName);
                            var cell = sheet.getCell(options.row, options.col);
                            cell.backColor(options.backColor);
                            Commands.endTransaction(context, options);
                            return true;
                        }
                    }
                };
                var spread = GC.Spread.Sheets.findControl(document.getElementById("ss"));
                var commandManager = workbook.commandManager();
                commandManager.register("changeBackColor", command);
                commandManager.execute({ cmd: "changeBackColor", sheetName: spread.getSheet(0).name(), row: 1, col: 2, backColor: "red" });
    
    

    In above code we are creating a custom action and implementing undo and redo for it. If the backcolor of the cell is set with this command, it allow Undo for this particular command.

    With your code, it never goes to “execute” when you press Ctrl+Z and hence “undo” is never shown on console.

    To customize Undo , you can use the code I provided earlier, it will allow you to know when a use presses Ctrl+Z key , then you can handle it as per your requirement.

    Thanks,

    Deepak Sharma

  • Posted 9 November 2018, 3:10 am EST

    After further investigation, it works when called from

    commandManager.execute(…)

    But does not seems to work when binded to a shortcut

    
    
    var command = {
        canUndo: true,
        execute: function (context, options, isUndo) {
            var Commands = GC.Spread.Sheets.Commands;
            if (isUndo) {
                //Commands.undoTransaction(context, options);
    
                console.log('undo command');
                console.log(isUndo);
                return true;
            } else {
                //Commands.startTransaction(context, options);
                var sheet = context.getSheetFromName(options.sheetName);
                var cell = sheet.getCell(options.row, options.col);
                cell.backColor(options.backColor);
                console.log('do command');
                //Commands.endTransaction(context, options);
                return true;
            }
        }
    };
    
    var spread = GC.Spread.Sheets.findControl(document.getElementById("ss"));
    var commandManager = spread.commandManager();
    
    commandManager.register("changeBackColor", command);
    
    spread.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.a, true, false, false, false);
    spread.commandManager().setShortcutKey("changeBackColor", GC.Spread.Commands.Key.a, true, false, false, false);
    //commandManager.execute({ cmd: "changeBackColor", sheetName: spread.getSheet(0).name(), row: 1, col: 2, backColor: "red" });
    
    

    I also tried with following code but I don’t think we need it

    
    var commandName = "undo";
    var undo = {
        canUndo: true,
        canRedo: true,
        execute: function (context, options, isUndo) {
            if (isUndo)
                spread.undoManager().redo();
            else
                spread.undoManager().undo();
    
            console.log(context, options);
    
            console.log("ctrl-z:" + isUndo);
    
            return true;
        }
    };
    
    spread.commandManager().register(commandName, undo, null, false, false, false, false);
    spread.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.z, true, false, false, false);
    spread.commandManager().setShortcutKey(commandName, GC.Spread.Commands.Key.z, true, false, false, false);
    
    var commandName2 = "redo";
    var redo = {
        canUndo: true,
        canRedo: true,
        execute: function (context, options, isUndo) {
            console.log(context, options);
            spread.undoManager().redo();
            console.log("ctrl-y:" + isUndo);
    
            return true;
        }
    };
    
    spread.commandManager().register(commandName2, redo, null, false, false, false, false);
    spread.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.y, true, false, false, false);
    spread.commandManager().setShortcutKey(commandName2, GC.Spread.Commands.Key.y, true, false, false, false);
    
    
  • Posted 9 November 2018, 3:59 am EST

    I does seem though I can do something like this with the previous sample to make it work. Not really intuitive though.

    Here a full example where I could make it work, as I though, we do not need to set ctrl-z and ctrl-y in this case at least.

    
    var doCommandName = 'do';
    var doCommand = {
        canUndo: true,
        execute: function (context, options, isUndo) {
            if (isUndo) {
                console.log('undo command');
                return true;
            } else {
                console.log('do command');
                return true;
            }
        }
    };
    
    var executeDoCommandName = 'executeDo';
    var executeDoCommand = {
        execute: function (context, options, isUndo) {
            commandManager.execute({ cmd: doCommandName });
        }
    };
    
    
    var spread = GC.Spread.Sheets.findControl(document.getElementById("ss"));
    var commandManager = spread.commandManager();
    
    commandManager.register(doCommandName, doCommand);
    commandManager.register(executeDoCommandName, executeDoCommand);
    
    spread.commandManager().setShortcutKey(undefined, GC.Spread.Commands.Key.a, true, false, false, false);
    spread.commandManager().setShortcutKey(executeDoCommandName, GC.Spread.Commands.Key.a, true, false, false, false);
    
    
  • Posted 12 November 2018, 1:59 am EST

    Hello,

    Happy to know that you got your issue resolved. Calling ’ commandManager.execute’ method will make the command run.

    Thanks,

    Deepak Sharma

  • Posted 13 November 2018, 7:51 am EST

    It took me a while, but I had problem with your example with transactions.

    I found out the sheetName parameter seems to be required, may I ask why?

    
    commandManager.execute({ cmd: "changeBackColor", sheetName: spread.getSheet(0).name(), row: 1, col: 2, backColor: "red" });
    
    

    If not provided, undoTransaction does not work.

  • Posted 14 November 2018, 12:53 am EST

    Hello,

    Between ‘startTransaction’ and ‘endTransaction’ you need to access the cell to set backcolor.

    Commands.startTransaction(context, options);
                           var sheet = context.getSheetFromName(options.sheetName);
                           var cell = sheet.getCell(options.row, options.col);
                           cell.backColor(options.backColor);
                           Commands.endTransaction(context, options);
    

    And in order to access the cell you need to have access to sheet. With sheetname you can get the sheet. You can have other options too.

    Thanks,

    Deepak Sharma

  • Posted 15 November 2018, 2:36 am EST

    Yes I understood that. What I mean is, according to the following command:

    
    var command = {
        canUndo: true,
        execute: function (context, options, isUndo) {
            var Commands = GC.Spread.Sheets.Commands;
            if (isUndo) {
                Commands.undoTransaction(context, options);
            } else {
                Commands.startTransaction(context, options);
                var sheet = context.getActiveSheet();
                var cell = sheet.getCell(options.row, options.col);
                cell.backColor(options.backColor);
                Commands.endTransaction(context, options);
            }
        }
    };
    
    var spread = GC.Spread.Sheets.findControl(document.getElementById("ss"));
    var commandManager = spread.commandManager();
    commandManager.register("changeBackColor", command);
    

    This won’t work, please note that sheetName is not given and that the comment always use context.getActiveSheet();

    commandManager.execute({ cmd: “changeBackColor”, row:1, col:2, backColor:‘red’ });

    2. Ctrl-z
    
    This will work
    

    commandManager.execute({ cmd: “changeBackColor”, sheetName:‘Cell’, row:1, col:2, backColor:‘green’ });

    2. Ctrl-z
    
    
    In our cases we didn't need the sheetName, it took a while to understand it is required for the transction to work and I was wondering why.
  • Posted 15 November 2018, 11:01 pm EST

    Hello,

    Looking at all the examples it seems Sheetname is a commandOption that you need to pass when when calling the execute method.

    I will ask for further details about the ‘commandOptions’ from the concerned team and let you know. Tracking id for this issue is #267383

    Thanks,

    Deepak Sharma

  • Posted 5 March 2019, 8:35 pm EST

    Hello,

    Here is a list of command/actions with detailed information. Hope it helps you.

    Thanks,

    Deepak Sharmaaction description.txt.zip

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels