How to implement undo in plain javascript?

I have a page and I am showing data in a table.
In each table, I have a column with checkbox which if checked user can change a specific row using javascript .
This is done as its td encapsulates either input or select , and I make them editable. The user changes the line and clicks save and the changes are saved. So far so good.
My problem is how to implement cancel ?
The user can select several cells in the row and also change them, but the user can also click cancel. When canceling, the initial values ​​should be displayed (and the lines again become inaccessible for editing).
But how is the cancel operation performed in javascript ? Have data been stored in some global data structures? What would be in javascript ?

+7
source share
4 answers

Well, after adding the information you provided, I suggest you set up the following mecanism:

 function getDatas() { var oXhr; //get datas from database: oXhr = new XMLHttpRequest(); oXhr.onreadystatechange = function() { if (oXhr.readyState == 4 && (oXhr.status == 200)) { g_oData = (new DOMParser()).parseFromString(oXhr.responseText, "text/xml"); } } oXhr.open("POST", "yourphpscriptthatreturnsthexmldatas.php", true); oXhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8"); oXhr.send(); } function populateGrid() { //use g_oData to populate your grid, but at first totally clean the body var mygrid = document.getElementById("mygridid"); //mygrid.innerHtml = "<table><tr><td>...</td></tr></table>"; //use the xml library to parse g_oData and fill up the table: var xmlRows = g_oData.getElementsByTagName("TAG"); var xmlRow; iLen = xmlRows.length; for (var i=0;i<iLen;i++) { xmlRow = xmlRows[i]; //use xmlRow->textContent to build each cell of your table } } function revertChange() { //on cancel, revert the changes by populating the grid. //it will use the global xml/json object loaded directly from database, to refill everything. populateGrid(); } 

I have done this myself many times to update some data on the page. Basically, what you do, except that you are not querying anything in the database, you just replenish the fields.

+1
source

You can use the HTML5 data- attributes to implement the return function. Thus, each <input> will have its original value if the revert button is used.

Here's what it looks like:

 <table> <tr> <td><input type='text' value='change me' data-original='change me' /></td> <td><input type='text' value='change me2' data-original='change me2' /></td> <td><input type='button' value='revert' onclick='revert(this)'/></td> </tr> <table> 

And the code that is returned:

 function revert(btn) { var parentTr = btn.parentNode.parentNode; var inputs = parentTr.getElementsByTagName('input'); for(var i = 0; i < inputs.length; i++) { if (inputs[i].type == 'text') { inputs[i].value = inputs[i].getAttribute('data-original'); } } } 

The data-original attribute can be generated:


As a side solution, you can save the original values ​​in the map object . Here (3) is a demo for this (notification I added an id for each input , so it can be used as a key to map ).

Keep in mind that neither solutions (2) nor (3) require changing the code on the server side (3 if your inputs have identifiers). And (2) feels more clear.

About the defaultValue attribute:
The defaultValue attribute can only be a solution if the return value never changes and if the text input s fields are involved.

Firstly, changing the "default" is rather inconvenient and might break something else when using the page (one would expect browsers to use the defaultValue attribute as defaultValue only, but that doesn't seem to be the case). Secondly, you will be limited to the input text type.

However, if this is not a problem, the above code can be quickly adapted for use instead of data- attributes.

+1
source

Here is a pretty simple way:

Do not replace the contents of a cell with a form element. Save the value (text) in the span element and hide it when you show the form element. Then you do not need to do anything when canceling. Just show the span and hide or delete the form element. Refresh span only when the user wants to keep the value.

Here is an example. Show and hide using CSS.

 <tr> <td> <span>value</span> <input type='text' value='' /> </td> <td> <button class="save">Save</button> <button class="revert">Revert</button> </td> </tr> 

JS:

 var rows = document.querySelectorAll('table tr'); for(var i = 0, l = rows.length; i < l; i++) { rows[i].addEventListener('click', function(event) { // all value display elements in the row var spans = this.querySelectorAll('span'); // all form elements in the row var inputs = this.querySelectorAll('input'); // handle click on save button if (event.target.className === 'save') { [].forEach.call(inputs, function(input, i) { spans[i].innerHTML = input.value; }); this.className = ''; } // handle click on revert button else if (event.target.className === 'revert') { // not much to do this.className = ''; } else { // update form element values [].forEach.call(inputs, function(input, i) { input.value = spans[i].innerHTML; }); this.className = 'edit'; } }); } 

Demo

+1
source

You can access the original value attribute to enter defaultValue . Implementation Example:

 $("table").on("dblclick", "td", function(e) { var val = $(this).html(); $(this).empty().append($("<form/>").append( $("<input/>", {type:"text"}).attr("value", val), // ^^^^ // set the *attribute*, as if it was present in the parsed HTML $("<button/>", {type:"reset"}).text("Reset"), $("<button/>", {type:"button", class:"cancel"}).text("Cancel"), $("<button/>", {type:"submit"}).text("Submit") )); }).on("submit", "form", function(e) { var val = $(this).find("input:text").val(); // ^^^^^ // which is equivalent to .prop("value") /* then do something with val, eg send it to server via ajax */ $(this).parent().html(val); e.preventDefault(); }).on("click", "button.cancel", function(e) { var $form = $(this).parent(), $input = $form.find("input:text"), oldval = $input.attr("value"); // ^^^^^^^^^^^^^ // or .prop("defaultValue"), but not .val()! if (oldval == $input.val() || confirm("Do you really want to discard your changes?")) $(this).parent().html(oldval); e.preventDefault(); }); 

( Demo on jsfiddle.net )

Perhaps a simpler solution would be to use a dblclick handler that creates the form as a closure and simply stores the original html in a local variable there.

+1
source

All Articles