0

Currently i'm creating a table dynamically, in that multiple rows get added dynamically (Similar to Excel).Table can have millions of rows.

For redo/undo functionality i've used Angular-Chronicle. Now redo/undo working perfectly when rows count is upto 100. How to improve redo/undo performance when data is too large.

Here is working demo.

Note : Pagination is not suit for my case.I want to load data on scroll.

Please suggest any other suitable angular plugin or any other way to achieve redo/undo functionality with better performance.

1
  • 1
    From having a short look at how Cronicle is working, it seems to watch for changes, and this is what takes the most performance in angular (and often that code will be called multiple times, because of the way angular works). So you might want to step away from this approach and go for one of you own. I once had issues with filters on large lists and found it better performance by doing the filtering only when it's required by a change of the dataset (triggered by code not by a watch). Commented Dec 7, 2016 at 6:39

1 Answer 1

3

To summarise, you can add state management with a Memento Factory.

All the code you need is below, but there's a little more background on my blog: AngularJS Memento Factory.

function MementoFactory(){
  return function() {
    var memento = this;
    // Private properties
    var subjects = arguments; // We can track multiple objects or arrays
    var stack = []; // Each call to "save" makes a copy of every subject on the stack
    var currentIndex = 0; // The "current" position on the stack stack
    // Begin by saving the current state
    save();
    // Public properties
    memento.timestamp = null; // The timestamp for the current stack
    // Public methods
    memento.save = save;
    memento.canUndo = canUndo;
    memento.undo = undo;
    memento.canRedo = canRedo;
    memento.redo = redo;

    function save() {
      var snapshot = {
        timestamp: Date.now(), // The save time
        subjects: [], // Contains each of the subjects
      };
      for (var a = 0, al = subjects.length; a < al; a++) {
        snapshot.subjects.push(angular.copy(subjects[a]));
      }
      if (stack[currentIndex] && angular.equals(stack[currentIndex].subjects, snapshot.subjects)) {
        return; // Do nothing if the new snapshot is the same as the current snapshot
      }
      if (canRedo()) {
        stack = stack.slice(0, currentIndex + 1); // Since we can "redo" we must overwrite that timeline (consider Back To The Future: Part II)
      }
      memento.timestamp = snapshot.timestamp; // Store the time
      stack.push(snapshot);
      currentIndex = stack.length - 1;
    };
    function canUndo() {
      return currentIndex > 0;
    };
    function undo() {
      if (canUndo()) {
        restoreSnapshot(-1);
      }
    };
    function canRedo() {
      return currentIndex < stack.length - 1;
    };
    function redo() {
      if (canRedo()) {
        restoreSnapshot(+1);
      }
    };
    function restoreSnapshot(indexDiff) {
      currentIndex += indexDiff;
      var snapshot = stack[currentIndex];
      memento.timestamp = snapshot.timestamp; // Update the timestamp
      for (var s = 0, sl = snapshot.subjects.length; s < sl; s++) {
        if (snapshot.subjects[s] !== subjects[s]) {
          angular.copy(snapshot.subjects[s], subjects[s]);
        }
      }
    };
  };
};

angular
  .module('app')
  .factory('Memento', MementoFactory);

Create a new Memento(...) object, passing the non-primitive variables you want to track

ctrl.user = { name: 'David King', location: 'England' };
ctrl.tags = [ 'AngularJS', 'Angular', 'Firebase' ];
// Create a new Memento object
var memento = new Memento(ctrl.user, ctrl.tags);
// Expose the undo and redo methods
ctrl.canUndo = memento.canUndo;
ctrl.redo    = memento.redo;
ctrl.canRedo = memento.canRedo;
ctrl.undo    = memento.undo;

Add undo and redo buttons to your View

<button
  type="button"
  ng-click="ctrl.undo()"
  ng-disabled="!ctrl.canUndo">Undo</button>
<button
  type="button"
  ng-click="ctrl.redo()"
  ng-disabled="!ctrl.canRedo">Redo</button>

Save your Memento object, when appropriate

<input
  type="text"
  ng-model="ctrl.user.name"
  ng-change="ctrl.save()">
<input
  type="text"
  ng-model="ctrl.user.location"
  ng-change="ctrl.save()">

... and that’s it!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.