Jaquarh
Jaquarh

Reputation: 6693

timeout not working as expected

I am trying to get the button to change from the default 'this Will Change' to then change what it says to 'New message' and back to 'someButton' every 2 seconds and then stop it with a click.

So far, I have this code:

var timeouts = [];

var someArray = {button: 'new Message', button: 'Some Btn'};

$(document).ready(function(){
var i = 2000;
$.each(someArray, function(index, value){
    timeouts.push(setTimeout(function(){
          $(index).html(value);
     },i));
     i = i + 2000;
});


$('#stop').click(function(){
    $.each(timeouts, function (_, id) {
       clearTimeout(id);
    });
    timeouts = [];
    $(button).html('Some Btn');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type='button'>
This will change
</button>
<a id='stop' href='#'>Stop</a>

It seems to ignore the first setTimeout() or that timeout is not run on the New message index.. Then when I press the click button, no timeouts get cleared?

Any help would be greatly appreciated to where I'm going wrong.

Update: I'd like to keep this as jQuery oriented as possible, thanks!

Upvotes: 0

Views: 101

Answers (3)

ryanlutgen
ryanlutgen

Reputation: 3051

Your use case describes exactly what a setInterval is meant for.

"Repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. Returns an intervalID."

the setInterval function returns an ID, which can be passed into clearInterval to stop the code from executing every X seconds.

I've posted a code snippet to what I think you're trying to achieve.

Plnkr Link

var strings = ["This will change", "Some button"];
var intervalID;
var button;
var index = 0;

$(document).ready(function() {
  button = $("#myButton");
  intervalID = window.setInterval(function() {
    console.log("hi");
    button.html(strings[index]);
    index = (index == 1 ? 0 : 1);
  }, 2000);
  $("#stop").click(function() {
    window.clearInterval(intervalID);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="myButton" type='button'>
  This will change
</button>
<a id='stop' href='#'>Stop</a>

Upvotes: 2

jeremiah.trein
jeremiah.trein

Reputation: 806

Here's a clean, functional way. Just for fun.

The selected answer is spot on. I'm just offering another option, using a slightly different style.

It starts, toggles and stops.

// "constant" array of messages
var messagesArray = ['new Message', 'Some Btn'];

// original button text
var btnOrigText = $('button').text()

// reverse an array
var _arrReverse = function(arr) {
    return arr.reverse()
}

// insert text from array 0th index into an element
var _insertTextArrayZero = function(el, messages) {
    // inserts an array's 0th index as HTML to an element
    return $(el).html(messages[0]);
}

// clears a timeout when given an id
var _clearIntvlAt = function(intvlId) {
    return clearTimeout(intvlId);	
}

$(document).ready(function(){
    // set interval
    var intvl = 2000;
    // keep our original array intact
    var messagesCloned = messagesArray.slice(0)
    // run interval
    var toggleTextIntvl = setInterval(function() {
    	// insert reversed array from [0] index of array into HTML element
        // NOTE: this only works for arrays of 2 items which need to toggle
    	return _insertTextArrayZero('button', _arrReverse(messagesCloned))
    }, intvl);
     
    // initiate "stopping" of toggle text
    $('#stop').click(function() {
        // stop toggleTextIntvl
        _clearIntvlAt(toggleTextIntvl)
        // set markup back to default
        $('button').html(btnOrigText);
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type='button'>
This will change
</button>
<a id='stop' href='#'>Stop</a>

Upvotes: 1

Rajesh
Rajesh

Reputation: 24955

The reason why its skipping new Message is because of this:

var someArray = {button: 'new Message', button: 'Some Btn'};

Your someArray is an object. So if you have same property name, it will get overriden and it will be parsed as

var someArray = {button: 'Some Btn'};

Just use a proper structure and it should work

var timeouts = [];

var someArray = [{
  type: "button",
  message: 'new Message',
}, {
  type: "button",
  message: 'Some Btn'
}];

$(document).ready(function() {
  var i = 2000;
  $.each(someArray, function(index, value) {
    timeouts.push(setTimeout(function() {
      $(value.type).html(value.message);
    }, i));
    i = i + 2000;
  });


  $('#stop').click(function() {
    $.each(timeouts, function(_, id) {
      clearTimeout(id);
    });
    timeouts = [];
    $(button).html('Some Btn');
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type='button'>
  This will change
</button>
<a id='stop' href='#'>Stop</a>

Updated code

This is how I would write. Few basic changes,

  • Use $(document).ready as start of your code flow. Not as wrapper for your code. It should call to necessary function.
  • You should use Array.map, Array.forEach instead of $.each(). These functions are very powerful and handy.
  • Variables defined outside any function will be part of global scope. Its a bad practice to pollute global scope.
  • Use small functions. This way there is a higher possibility you can reuse your code. Any code that can be use somewhere else, can be used as a function.

$(document).ready(function() {
  var someArray = [
    { type: "button", message: 'new Message', }, 
    { type: "button", message: 'Some Btn' }
  ];

  var timeouts = registerTimeouts(someArray);
  registerEvents(timeouts)
});

function registerTimeouts(array) {
  return array.map(function(value, index) {
    return setTimeout(function() {
      $(value.type).html(value.message);
    }, (index + 1) * 2000);
  });
}

function registerEvents(timeouts) {
  $('#stop').click(function() {
    timeouts.forEach(function(id) {
      clearTimeout(id);
    });
    timeouts = [];
    $(button).html('Some Btn');
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type='button'>
  This will change
</button>
<a id='stop' href='#'>Stop</a>

Upvotes: 2

Related Questions