Motivation
In many scenarios the user makes changes to the data. Maybe presses Save now and then. Then wants to revert... and here are some familiar quotes (swearwords left out):
"What was the previous price on that item?"
"Or was it the one before it?"
"And the product code, do you recall that?"
"But I can't! I already pressed Save!"
"Don't they have Undo in this thing?"
Having the Undo option adds great value. This includes a scenario with a Save action: Did you save the wrong value? Undo it and Save again.
See also:Undo / Redo in Table: Insert, Delete and Edit Rows
The Application
In this document we focus on simple editing of values in a form. Here is the example application:
The Undo action is made possible by holding a list of "past" actions. The same goes for Redo with "future" actions. Here is the same application with the debugging panel made visible, showing these lists:
Do, Undo and Redo
It is easy to think of this as a person going through a time axis. Undo moves us back, Redo moves us forward.

Do - change of value - moves us forward towards a "new future", as we could only have one.

Here is a basic example with values:
| Action | Past | Present | Future |
|---|---|---|---|
| Starting with value A and changing to B and then C | ![]() | ![]() | |
| Undo | ![]() | ![]() | ![]() |
| Undo | ![]() | ![]() | |
| Redo | ![]() | ![]() | ![]() |
Modeling
We hold lists for Past and Future values, that we can use in Undo / Redo actions.
When the user changes a value, we need to pass the former value to the past, but we only know the new value! So we must hold in memory the Present too. When the UI changes, we use it to get previous UI values.
Modeling steps:
1. Add a Form View and define two fields - Text (TXT1) and Date (Date1).
2. Add three Data Share elements, for the past, present and future.
3. Define the cardinality to be Record Set (0..n).
4. Define the same set of fields: Text (TXT1) and Date (Date1) fields.
5. For the present data share open from the Define Data dialog the Initialize Data dialog, and add one record.

6. Add a Panel element, set its visibility to false (in the Configuration Panel).
7. Connect Grid View elements to the Data Shares, and place them inside the Panel. They are used for debugging / testing.

8. Add a Data Share element and name it size.
9. Define the following numeric fields: past and future. This is later used to set or get the size of our lists. Knowing the size we could disable / enable the Undo Redo buttons as appropriate.

10. Optional - change Txt1 control to a Drop Down and add an Entry List to it.
11. Add two buttons for Undo and Redo. The layout should look like this:

12. Define the Do (change value) Action for the controls Txt1 and Date1 as follows (see movie for the same😞
| Action | Parameters | Remarks |
|---|---|---|
| COPYTO | From:present To: past Scope: Current row Insert: First | Former present value is added to the Past list |
| ASSIGN | From: Form1 Value: =@TXT1 To: present Target Field: TXT1 | For Date1 copy value =@DATE1 |
| ASSIGN | From: [none] Value: =size@past+1 To: size Target Field: past | Increase past size |
| ASSIGN | From: [none] Value: 0 To: size Target Field: future | Reset future size |
| DELETE | From: Future Delete: All rows | The "old" future is irrelevant |
13. Define the Action for the Undo button (movie here😞
| Action | Parameters | Remarks |
|---|---|---|
| MOVETO | From: present To: future Scope: Current row Insert: First | Former present value is added to the Future list |
| MOVETO | From: past To: present Scope: Current row Insert: First | Recent past record is moving to present |
| ASSIGN | From: [none] Value: =size@past-1 To: size Target Field: past | Decrease past size |
| ASSIGN | From: [none] Value: =size@future+1 To: size Target Field: future | |
| COPYTO | From: present To: Form1 Scope: Current row Insert: After | update the UI |
14. Define the Action for the Redo button (movie here):
| Action | Parameters | Remarks |
|---|---|---|
| MOVETO | From: present To: past Scope: Current row Insert: First | Former present value is added to the Past list |
| MOVETO | From: future To: present Scope: Current row Insert: First | Recent future record is moving to present |
| ASSIGN | From: [none] Value: =size@past+1 To: size Target Field: past | |
| ASSIGN | From: [none] Value: =size@future-1 To: size Target Field: future | |
| COPYTO | From: present To: Form1 Scope: Current row Insert: After | update the UI |
15. Define the Enabled condition for the Undo Button: =size@past>0
16. Define the Enabled condition for the Redo Button: =size@future>0

That's it
Next relevant scenario:
Handling table values: Allow undo / redo for insert, delete and edit of table rows.
Here is an example modeled application:









