Show values from array in jquery - javascript

Ok, the title might make it sound easy (and maybe it is), but I can't figure out how to show values from an array, not just do a each with them, but put them on the site slowly, with a nice effect...
Like this Twitter widget, but from an array (maybe wait 2sec, and when throw another value from the array)?
My array contains another array, with 4 values, is it possible to show the first 2 values, wait about 2 sec, and then show the last 2 values? Now when the last two values is out (from the prev array), wait 2 more seconds, and show the next array (again with four values, first show 2, wait 2 sec, and show the next 2, and so on...)

You can do this easily using setInterval or a chained series of setTimeout. I tend to prefer the latter, which looks something like this:
function showValues(a, delay) {
var index = 0;
if (a.length !== 0) {
// If you want a delay before the first one:
setTimeout(showValue, delay);
// Alternately, if you want to show the first right away
// showValue();
}
// Function to show one value
function showValue() {
// Get the value
var value = a[index++];
/* ...show the value however you see fit... */
// Schedule next display, if any
if (index < a.length) {
// Schedule next run
setTimeout(showValue, delay);
}
}
}
Usage:
showValues(["value1", "value2", /* etc. */, 2000); 2000 = two seconds
Live example | source

Animation functions like fadeIn() make use of the jQuery FX queue so you can use .delay() in the call chain to delay the calling of these functions. In the following example one element is shown every second.
var data = ['foo', 'bar', 'foobar', 'moo', 'meow', 'xxx'];
var list = $('ul');
$.each(data, function(i, value) {
$('<li/>', { text: value }).hide().appendTo(list).delay(i * 1000).fadeIn();
});
Demo: http://jsfiddle.net/ThiefMaster/frW8s/

Related

Get second element of array after removing elements and updating array

Task: I have var = array; in a function that can hold the following sample array - the items represent time (seconds):
["20.30", "30.55", "8.25", "32.74", "2.75", "39.24"]
A setInterval loop displays the third item (array[2]) when a timer exceeds or matches second item in array (array[1]). Currently, after that happens, the first two items of array (array[0] and array[1]) are removed and array variable is re-indexed like so, looping the process until done:
array = array.splice(2).filter(function(){return true;});
Dilemma: I thought it would be easiest to just remove the first two items and update the array this way so as to simply apply a condition like so: if ( array[1] <= timer ){ but the splice() and filter() methods - which apply after the conditional statement in the loop - don't seem to re-index array variable.
Is there a way to make sure the array variable is re-indexed by new length, or perhaps there is a better way by navigating through the array variable without having to mutate/update it? The latter would perhaps be best, but I am kind of noob in better array manipulation and would appreciate some help.
UPDATE
Below I summarize what I clearly wish to attain:
var array = ["20.30", "30.55", "8.25", "32.74", "2.75", "39.24", etc...]
Instead of programmatically fetching each and every item iteration (impossible since amount will dynamically change) like follows ...
timelinePolling = setInterval(function(e){
...
if ( array[1] <= timer ){
timeline(array[2]); // Apply 3rd item timeline value
} else if ( array[3] <= timer ){
timeline(array[4]); // Apply 5th item timeline value
}
// etc, for remaining determined/undetermined items.
}, 30);
... I wish to iterate and dynamically increment the index target of array item variable (what is in brackets) the moment array[index] <= timer is achieved, like so (pseudo):
timelinePolling = setInterval(function(e){
...
if ( array[end] <= timer ){
// [end] is always an odd-numbered 0-based indexed item
// in array list (see Note1 below).
timeline(array[start]);
// [start] is always an even-numbered 0-based indexed item
// in array list (see Note2 below).
// Note1: [end] must be swapped with next chronological
// odd-numbered indexed item in array list at this point in code.
/* Missing code here! */
// Note2: [start] must be swapped with next chronological
// even-numbered indexed item in array list at this point in code.
/* Missing code here! */
}
}}, 30);
So it's the dynamic index increment part that I wish to resolve, which would make my day to say the least. Perhaps my array should be constructed differently to facilitate the task? In this fashion the array must remain intact (no mutation). Any pointers/help will be appreciated.
Looks like you code in is in the right direction take a look at circular arrays:
https://www.geeksforgeeks.org/circular-array/
Possibly you are looking at something like this -
index = beg;
while (index < end) {
if( arr[index] < timer) {
// set beg and end appropriately
// swap the values you need from the notes
// Note1: [end] must be swapped with next chronological
// odd-numbered indexed item in array list at this point in code.
/* Missing code here! */
// Note2: [start] must be swapped with next chronological
// even-numbered indexed item in array list at this point in code.
/* Missing code here! */
timeline(arr[index+1]);
}
index += 2; // jump to the next even number.
index %= arr_len; //check here if there is something that needed to be done for even odd index
}
You could do this with setTimeout, and then you won't have to do the comparison yourself.
At the end of each timeout loop, you splice the array as you suggested, if there are still 3 or more entries in the array then recall the function that sets the timeout.
(The timer here is only to display the total time)
(I reduced your array of number to speed it up)
let timer = 0;
const times = ["4.30", "5.55", "6.25", "6.74", "5.75", "4.24"];
function test(array) {
const timeInMilliseconds = parseFloat(times[1]) * 1000;
setTimeout(() => {
document.querySelector('#ignore').innerHTML = array[0];
document.querySelector('#test').innerHTML = array[1];
document.querySelector('#display').innerHTML = array[2];
timer += timeInMilliseconds / 1000;
document.querySelector('#timer').innerHTML = timer;
document.querySelector('#array').innerHTML = array;
array = array.splice(2);
if (array.length >= 3) {
test(array);
}
}, timeInMilliseconds);
}
test(times);
<p>ignore: <span id="ignore">-</span></p>
<p>test: <span id="test">-</span></p>
<p>display: <span id="display">-</span></p>
<p>Timer: <span id="timer"></span></p>
<p>Array: <span id="array"></span></p>

How can I get this code to make the sequence obvious?

The code below allows me to have an array with a set of numbers such as "thearray=[2,8,9]" and loop through that array, and for each number item in the array for example "2,8,9", the code calls a function an amount of times equal to the current number item in the array. So if the current number item is 2, the function gets called twice.
After the set of calls, there is a pause, and then the function is called again an amount of times equal to the current number in the array etc. In other words, as the array is being looped through, if the current number item is 2, the function named "thefunction" will be called twice then there is a pause and the function "thefunction" is then again called an amount of times equal to the next number in the array.
In my case, "thefunction" simply displays an alert box message two times followed by a pause, then 8 times followed by a pause, then 9 times followed by a pause etc. Of course, with the alert box messages, I get the messages in sequence because I must select ok before I see the next alert message. The problem is, I can't get the calls to "thefunction" to appear sequential like when the code to be executed within "thefunction" displays an alert box, when other code such as appending an li item with data to a ul is within that function.
It's as if the 2 calls are made at once, then the 8 calls are made at once, etc. Even though that may not be the case, it happens so fast, it seems like it. I would like to slow it down. So if the code within "thefunction" was code that would append information to an li element, instead of just seeing the information rapidly added where the sequence of calls isn't noticeable, I would like there to be a delay so that when li elements are appended, the sequence is more obvious rather than rapid where it's hard to see the sequence.
Here is the code:
function runArray(arr, fn) {
// initialize array index - can't use for loop here with async
var index = 0;
function next() {
var cnt = +arr[index];
for (var i = 0; i < cnt; i++) {
fn(index, cnt);
}
// increment array index and see if there's more to do
++index;
if (index < arr.length) {
setTimeout(next, 400);
}
}
// start the whole process if the array isn't empty
if (arr.length) {
next();
}
}
runArray(thearray, shakeit);
and here is a jsfiddle demonstrating a log rapidly adding information. I want to slow it down so the information is added slow enough to make it obvious there is a sequence.
http://jsfiddle.net/jfriend00/Loycmb3b/
What you want to do in essence is insert a delay between executions of the for loop. The only sane way to introduce a delay in JavaScript is using setTimeout and setInterval, so that's what you have to work with.
The next thought is that since each loop iteration is to be implemented as a callback to setTimeout and friends, the logic that moves to the next array element after each loop completes is necessarily going to be part of that -- you can't move to the next element before the loop completes.
But the logic that moves to the next element is already inside next, and we already established that next is supposed to set up the callback. So next is going to schedule the callback, and the callback is also going to schedule next -- there's no other way.
Therefore:
function runArray(arr, fn, delay) {
var index = 0;
var cnt = 0;
var i = 0;
// Called once for each array element
function next() {
if (index >= arr.length) {
return;
}
cnt = +arr[index];
i = 0;
loop();
}
// Represents a single iteration of what was previously a for loop
// Will either schedule the next iteration or move to the next element
function loop() {
if (i < cnt) {
fn(index, i++);
setTimeout(loop, delay); // delay before next iteration
}
else {
++index;
setTimeout(next, delay); // delay before moving to next element
}
}
if (arr.length) {
next();
}
}
I kept the same delay both between "loop iterations" and between the end of a loop and the start of the next one, but that can easily be changed.
See it in action.
Unless I'm misunderstanding something...
function runArray(arr, fn, delay, idx, cnt) {
idx = idx || 0;
cnt = cnt || 0;
if(cnt >= arr[idx]) {
idx++;
cnt = 0;
}
if(idx >= arr.length)
return;
fn(idx, cnt);
setTimeout(function() { runArray(arr, fn, delay, idx, cnt + 1) }, delay);
}
http://jsfiddle.net/Loycmb3b/8/
I may or may not understand what you are trying to do, but with this piece of code here
runArray(theArray, theFunction, 400);
you are executing theArray and theFunction to occur after 400 ms, 1000 is one second, so if you want it to be a more substantial pause, increase that 400, here I increased it to 4000(4 seconds) and the pause is much more noticable.
http://jsfiddle.net/Loycmb3b/7/

Track which JSON objects have been output

I'm outputting 20 or so JSON objects randomly by setting the index to a randomNumber() initially when the page is loaded.
I'm refreshing each JSON object individually that has already been output on a timeInterval.
To keep track of which JSON items have been output I am storing the index of each item into an array via arrUsed.push[index]
Now trying to write the function that will update() each JSON objects individually and am currently stuck on how I can update the each div with the information from a new JSON object that has not already been output (pushed to the arrUsed[]).
Here's the function I have so far:
function reloadItems() {
var itemTotal = $('div.item').length; // Total number of items loaded initially
var randomNumber=Math.floor(Math.random()*301) //returns number
index = randomNumber; // Sets index to be used in JSON data to random number
}
The array that contains the already output index's is declared globally: arrUsed = []; Each item that is output initially when the page load is being stored to the array fine, so that part is covered. It's a matter of choosing a random JSON object, checking to ensure it is not in the array/not been output already, and then updating the div on the page.
Here's the previous question that has led me to this point
Here's a working example of a JSON/AJAX Ticker:
http://ticker.weisser.co/
Per twhyler's specification, it randomly swaps an item every 4.5 seconds, keeping track of ones that have already been seen. Once they've all been seen, it starts over again:
Code Files:
default.html (Main Program)
template.html (Product Template)
UK.top.20.html (JSON Data)
ticker.js (jQuery)
ticker.css (Style Sheet)
First, we should store template.html in our global template variable and fire the getJson() function:
template = '';
....
$(document).ready(function () {
$.get('template.html', function(html) { template = html; getJson(); });
});
Then, we'll store the JSON into our data variable and fire the initialize() function:
data = ''; // JSON data will be stored here
myurl = 'UK.top.20.html';
....
function getJson() {
$.getJSON(myurl, function (JSON) { data = JSON; initialize(); });
}
Here, we'll call the load() function 3 times to populate our 3 product div's with data right away. Then we set i back to 2 (that's so it will change the 3rd DIV first), and schedule tick() to fire in 4.5 seconds:
tick_time = 4500;
....
function initialize() { // Start with the first 3
for (i = 1; i < 4; i++) { load(); }
i = 2;
setTimeout('tick()', tick_time);
}
Before we explain the load() function, let's talk about `String.prototype.f' at the bottom of the script:
String.prototype.f = function () { var args = arguments; return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; }); };
This function works similar to String.Format(formatstring, arg1, arg2, arg3...) in C# or sprintf($formatstring, arg1, arg2, arg3...) in PHP. Here's an example:
formatstring = 'Roses are {0}, Violets are {1}, String.Format {2} and so do {3}!';
result = formatstring.f('red', 'blue', 'rocks', 'you');
alert(result);
So as you can see, this String.prototype.f function comes in very handy!
The first thing the load() function will do is set rid = randomId();. Let's take a look at the randomId() function next. The first thing it does is get a number from 1-20 (based on the length of our JSON data). Then, it checks to see if our seen array is the same size as our JSON data, and if it is - it sets it back to 0. Next it makes sure that our rid hasn't been seen recently, and if it has, the function recursively calls itself again till it gets a unique random id. Otherwise, we store the rid in our seen array and return the value.
function randomId() {
rid = Math.floor(Math.random() * data.results.length);
if (seen.length == data.results.length) { seen.length = 0; }
if ($.inArray(rid, seen) == -1) {
seen.push(rid);
return rid;
} else { return randomId(); }
}
Next in our load() function after getting that random ID, we setup item and plat as convenient shortcuts. plat_html is a temporary storage place for the Platform elements. The for-loop looks at all the Platform data in our JSON and uses our String.Format function to fill our plat_html string.
Finally, we allow the current value of i (which is global) determine which #product_ gets updated, and template.f fills our template with JSON data which is done with a smooth jQuery animation thanks to .fadeIn().
function load() {
rid = randomId();
item = data.results[rid];
plat = item.Platform;
plat_html = '';
for (var j = 0; j < plat.length; j++) {
plat_html += plat_fmt.f(
plat[j].Hardware,
plat[j].Market
);
}
$('#product_' + i).html(
template.f(
item.Image,
item.id,
item.AgeRating,
item.WikiUrl,
item.Title,
item.Source,
item.Genre,
plat_html
)
).fadeIn();
}
Lastly, let's take a look at the recursive tick() function. It begins by incrementing our global i variable and setting it back to 1 when it reaches 4. Then we perform an animated fadeOut() on our #product_ element and wait till it's finished till we call load() again. Then, it schedules itself to run again in another 4.5 seconds.
function tick() {
i++; if (i == 4) { i = 1; }
$('#product_' + i).fadeOut(function() { load(); });
setTimeout('tick()', tick_time);
}
That's it!
Use $.inArray(): http://api.jquery.com/jQuery.inArray/
$.inArray(indexInQuestion, arrUsed);
It will return -1 if the element is not in the array, so you will know wether indexInQuestion was already added to arrUsed.

Play functionality in nested loops Javascript

I am trying to build play functionality using JavaScript to play different colors for my attribute values on map. The basic logic, I am building using simple for loop does not work for me as the loop is played so fast and I only get display last value on Map.
Example:
//Hash of my Values
var myHash = {};
myHash['1'] = [10,100];
myHash['2'] = [20,200, 30];
myHash['3'] = [40,300, 4, 5];
function startPlaying() {
for (item in myHash) {
var myValues= myHash[item];
var timeOut=setTimeout(function(){
animate(myValues,item);
},1000);
}
}
function animate(myValues,item) {
for(i in myValues) {
//calling my function for each value to play on map with different styles.
playMyMap();
}
}
I was expecting here that my function startPlaying will fire timeout function three times(for number of items with 1 sec delay) with corresponding myValues and item and It will keep on iterating over myValues individually for three items.
But this doesn't work for me beacuse the myValues gets messed up while each call of setTime out function.
Could anyone please give me an idea here, how can I build such functionality?
var timeOut=setTimeout(function(){
animate(myValues,item);
},1000);
}
Will trigger 3 times, but all after 1 second. If you keep a counter you have to do the 1000*counter to have 1 animate function each second.
The below example uses the item as the multiplyer because you start your index with 1. Normally array's start at index 0. If you change your first item to index 0, just do 1000 * (item + 1) to start with 1 second.
Try this:
function startPlaying() {
for (item in myHash) {
var myValues= myHash[item];
var timeOut=setTimeout(function(){
animate(myValues,item);
},1000 * item );
}
}

Extract array values with last extraction memory on callback in javascript

Let's say I have a dynamic array that is populated on page load with various amounts of strings inside:
var arr = ["string1","string2","string3","string4","string5","string6","string7","string8","string9","string10","string11","string12","string13","string14","string15","string16","string17","string18"];
I then have a function that is called on each event (let's say a click) that needs to bring back 3 strings of the array consecutively while remembering which value it left off at, the last time it was called. So:
First time function is called, it returns:
string1, string2, string3
Second time it is called, it returns:
string4, string5, string6
and so on...
I don't the need the code for the click event or the callback function, rather the code for the function that would generate the extraction each time and bring it back. Something simple like being able to call:
arr.runExtraction();
on each callback and having it bring back the desired data.
What should happen if the array is exhausted? Start from the beginning?
You could do something like this:
function get_iterator(values, steps, start) {
steps = steps || 1;
var current = start || 0,
max = values.length;
return function() {
var end = current+steps,
end = end > max ? max : end,
t = values.slice(current, end);
current = end % max;
// or if you don't want to wrap around:
// current = end;
return t;
}
}
Edit: Added start parameter.
As current will be the same as values.length in the end, splice will return an empty array if you don't wrap around.
Using slice won't change the original array.
And then
var extract = get_iterator(arr, 3);
var arr1 = extract(); // gives you the first three elements
var arr2 = extract(); // gives you the next three elements etc.
DEMO
It might give you less elements in the "last" extraction if the number of elements is not divisible by number of extracted elements. The next call will let it start from the beginning again. You could also modify it that it wraps around and takes elements from the beginning so that it will always return as many elements as you have specified.
Reference: Array.prototype.slice
var arr = ["string1","string2","string3","string4","string5","string6","string7","string8","string9","string10","string11","string12","string13","string14","string15","string16","string17","string18"];
var runExtraction = function () {
return arr.splice(0, 3);
}

Categories