Angular Undo
by mslocum
HTML
<div ng-controller="Ctrl">
<p>Hit save to save the current value of the input box. Then change it. Then hit undo.</p>
<br/>
<input type="text" ng-model="value"/><br/>
<button ng-click="save()">save</button>
<button ng-click="saveFunc()">save function</button>
<button sx-do-undo sx-has-undo>undo</button>
<button sx-do-redo sx-has-redo>redo</button>
</div>
JavaScript
angular.module('sxUndo', [])
.service('$undo', [ function(){
var aHistory = [],
aRedo = [],
bRedoEnabled = true,
oScopeCache = null;
/**
* Set a cached scope which will make the push of oScope optional
* @param oScopeIn
*/
this.setScope = function(oScopeIn) {
oScope = oScopeIn;
};
this.add = function(strLocation, oScope, func) {
aRedo = [];
push(strLocation,
oScope || oScopeCache,
func,
oScope[strLocation],
aHistory);
return this;
};
function push(strLocation, oScope, func, value, aStack) {
var oUndo = aStack[aStack.length -1];
if (!oUndo ||
oUndo.value != value ||
oUndo.location != strLocation ||
oUndo.scope != oScope ||
oUndo.func != func)
{
aStack.push({
scope: oScope,
location: strLocation,
value: angular.copy(value),
func: func
});
}
}
this.undo = function(iNth) {
pop(iNth, aHistory);
};
this.redo = function(iNth) {
pop(iNth, aRedo);
};
function pop(iNth, aStack) {
var oUndo, oldValue;
iNth = parseInt(iNth, 10) || aStack.length - nextUndo(aStack);
if (aStack.length >= iNth) {
oUndo = aStack.splice(iNth * -1)[0];
oldValue = oUndo.scope[oUndo.location];
if (typeof oUndo.func == "function") {
oUndo.func.call(oUndo.scope, oUndo.value);
} else {
oUndo.scope[oUndo.location] = oUndo.value;
}
if (bRedoEnabled) {
push(oUndo.location,
...