Skip to content
Advertisement

how to show array element one by one onclick event in javascript?

I have textarea and storing in array onclick i need to show one by one from the last element and redo onclick one by one from where user clicks. i am doing a custom undo and redo functionality.

var stack =[];

jQuery('#enter-text').keypress(function() { 
console.log(jQuery('#enter-text').val());
stack.push(jQuery('#enter-text').val());

  })

 jQuery('#undo_text').click(function() {
    console.log(stack.pop());
 })

jQuery('#redo_text').click(function() {
    // how to redo onclik where user undo text
})

I have created jsfiddle

https://jsfiddle.net/k0nr53e0/4/

Advertisement

Answer

instead if keeping different stacks for the actions you’ve done, and undone, you can keep them in one Array, and memorize the current position:

var stack = [ jQuery('#enter-text').val() ], index = 0;
updateButtonsDisabled();

jQuery('#enter-text').keypress(function() { 
    //adding the current action
    stack[++index] = jQuery('#enter-text').val();
    
    //removing the entries after the last one you added: they belong to a different redo-stack
    stack.length = index+1;
    updateButtonsDisabled();
})

jQuery('#undo_text').click(function() {
    if(!index) return;

    jQuery('#enter-text').val(stack[--index]);
    updateButtonsDisabled();
})

jQuery('#redo_text').click(function() {
    if(index === stack.length-1) return;
    
    jQuery('#enter-text').val(stack[++index]);
    updateButtonsDisabled();
})

//just some sugar
function updateButtonsDisabled(){
    jQuery('#undo_text').toggleClass("disabled", index === 0);
    jQuery('#redo_text').toggleClass("disabled", index === stack.length-1);
}

index holds the position in stack of the currently shown value. You can undo and redo as much as you want, but as soon as you start typing, the redo-stack will be cleared.

You should consider limiting the items you want to keep in stack, or you’ll allocate quite some memory. And you could change the logic for keypress to wait for a pause of like 300ms before you update the stack. That would decrease the items in your stack tremendously.

Edit: made a snippet implementing the possible changes I mentioned, like detached update, and limited stacksize. Take a look at that

//this value is kept small for testing purposes, you'd probably want to use sth. between 50 and 200
const stackSize = 10;

//left and right define the first and last "index" you can actually navigate to, a frame with maximum stackSize-1 items between them.
//These values are continually growing as you push new states to the stack, so that the index has to be clamped to the actual index in stack by %stackSize.
var stack = Array(stackSize),
  left = 0,
  right = 0,
  index = 0,
  timeout;
//push the first state to the stack, usually an empty string, but not necessarily
stack[0] = $("#enter-text").val();
updateButtons();

$("#enter-text").on("keydown keyup change", detachedUpdateText);
$("#undo").on("click", undo);
$("#redo").on("click", redo);

//detach update
function detachedUpdateText() {
  clearTimeout(timeout);
  timeout = setTimeout(updateText, 500);
}

function updateButtons() {
  //disable buttons if the index reaches the respective border of the frame
  //write the amount of steps availabe in each direction into the data-count attribute, to be processed by css
  $("#undo")
    .prop("disabled", index === left)
    .attr("data-count", index - left);

  $("#redo")
    .prop("disabled", index === right)
    .attr("data-count", right - index);

  //show status
  $("#stat").text(JSON.stringify({
    left,
    right,
    index,
    "index in stack": index % stackSize,
    stack
  }, null, 2))
}

function updateText() {
  var val = $("#enter-text").val().trimRight();
  //skip if nothing really changed
  if (val === stack[index % stackSize]) return;

  //add value
  stack[++index % stackSize] = val;

  //clean the undo-part of the stack
  while (right > index)
    stack[right-- % stackSize] = null;

  //update boundaries
  right = index;
  left = Math.max(left, right + 1 - stackSize);

  updateButtons();
}

function undo() {
  if (index > left) {
    $("#enter-text").val(stack[--index % stackSize]);
    updateButtons();
  }
}

function redo() {
  if (index < right) {
    $("#enter-text").val(stack[++index % stackSize]);
    updateButtons();
  }
}
#enter-text {
  width: 100%;
  height: 100px;
}

#undo,
#redo {
  position: relative;
  padding-right: 1em;
}

#undo:after,
#redo:after {
  content: attr(data-count);
  position: absolute;
  bottom: 0;
  right: 0;
  font-size: 0.75em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<textarea id="enter-text"></textarea>
<button id="undo">undo</button>
<button id="redo">redo</button>
<pre id="stat">

</pre>
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement