How to render Array.length from inside of object to html page? - javascript

I am using jQuery and got an response from API by using $.ajax. I want to grab the Arrays length from inside each object and display that in the html page. This is what I have done so far.
Here is the API response, i did breakdown of the last object, which contains an array and player names:
{_type: "InjuredPlayers", flaggedTokens: Array(1)} //1 injured player name
{_type: "InjuredPlayers", flaggedTokens: Array(3)} //3 injured players names
{_type: "InjuredPlayers", flaggedTokens: Array(5)} //5 injured players names
{_type: "InjuredPlayers", flaggedTokens: Array(2)} //2 injured players names
>flaggedTokens:Array(2)
>0:{offset: 0, token: "John", type:"UnknownToken"}
>1:{offset: 1, token: "Adam", type:"UnknownToken"}
length: 2
>_proto_:Array(0)
_type: "InjuredPlayers"
>_proto_: Object
In order to grab the length of the Array I can do any of these 2 methods according to this Get length of array inside object
console.log(response.flaggedTokens.length)
1
3
5
2
OR
console.log(response["flaggedTokens"].length)
1
3
5
2
My Failed Attempts: I assigned this output to a variable and tried to loop through and output by doing this:
$.ajax(gameResponse).done(function(response) {
let injuredPlayers = response.flaggedTokens.length;
let injuredPlayersArray = [];
for (let i = 0; i < injuredPlayers.length; i++) {
injuredPlayersArray.push(injuredPlayers[i])
}
$('.injured_players').html(injuredPlayersArray[i])
})
<div class="container">
Team One Total number: <span class="injured_players"></span> //should be 1
Team Two Total number: <span class="injured_players"></span> //should be 3
Team Three Total number:<span class="injured_players"></span> //should be 5
Team Four Toal number: <span class="injured_players"></span> //should be 2
</div>
Clearly I made some mistake which I can't seem to figure this out by myself. I was hoping if someone can guide me through the right direction.

To start with, in your for loop, you are returning the push action, but that's unnecessary and it kills the loop on the first iteration. Also, you have already set the length of the array to a new variable, but then in your for loop, you try to get the length of the new variable. Lastly, you declare injuredPlayersArray in your ajax statement, but based on your post, you recieved 4 separate api responses, so it should be declared outside of your ajax call so that the array doesn't get overwritten with every new call. And you don't need a for loop as you're only working with one array. Here is what it should look like.
let injuredPlayersArray = [];
$.ajax(gameResponse).done(function(response) {
let injuredPlayers = response.flaggedTokens.length;
injuredPlayersArray.push(injuredPlayers)
})
Your other mistake is that you are trying to dynamically display the value in the proper html tag, but you're setting the value for every span tag at the same time. So after your loop is finished, they would all say 2.
To fix that you can add a for loop after all of your api calls are completed (aka NOT inside a $.ajax().done()):
for (let i = 0; i < injuredPlayersArray.length; i++) {
$('.injured_players').eq(i).html(injuredPlayersArray[i])
}
Note: .eq() returns a set of DOM elements that match the selector it is called upon. So $('.injured_players') matches 4 elements on your page and in your for loop, it finds the i-th element in that set (so index 0 is equal to the first span tag) and sets the html for that element.
Note 2: There is an assumption I had to make with your api calls. From the way your api call is storing the length of the flaggedToken array in your response, it seems each ajax response returns a single object with the array of injured players and that you will have 4 separate api calls. However, if that's not the case and the response returns a array of objects, you will need to iterate over the array and get the length for every array in every object one at a time. You can also then ignore my suggestion to move the declaration of injuredPlayersArray to outside the api call. And the second for loop i wrote would go inside the api call.

Related

Turning off JavaScript setInterval timers stored in array of timer / websocket client pairs

so I have a node js / websocket server going, where I want to store multiple instances of setInterval timers...
I have them stored in an array of [timer, client] objects that I want to step through when a client disconnects, then step through the array and turn off all the timers that are paired with the disconnecting client before removing them from the array.
Removing the objects connected with the clients is working, however, the timers are not stopping...
I am declaring the timers like this -
clientSchedulePairs.push([setInterval(makeVisibleHandler, master_period, item, name), client]);
then trying to turn the schedule off like this when a client disconnects-
clearInterval(clientSchedulePairs[i][0]);
in my research i found this question -
clearInterval() is not stopping setInterval() - Firefox Extension Development
which says that I need to make a timer a global variable? but that isnt helping because if I have multiple timers for multiple clients how can i make them global variables?
I am storing them in a global const array that is declared globally such as-
const clientSchedulePairs = [];
however it is not working...
any idea on if the reason its not working is because its not declared as a global variable? or how I can get around this and get it to work? (i already tried declaring the schedule as a variable in my method before adding it to the array)
thanks.
UPDATED---
i got it working turning off the timers --- not sure if it had something to do with the way the client was disconnecting, after I removed my for loop into an external method that took in the client socket as a variable, then looped through my array of client / timer pairs and checked for the clients and removed them it started working. However, I am running into a kind of strange issue now...
as i said, i am looping through a clientTimerPairs array and checking if the client paired to that timer is === to the client_socket that was passed in from when the method was called when a client disconnects, in this loop, calls this--
clearInterval(clientTimerPairs[i].interval);
and the timers turn off, however I had a problem removing the client - timer tuples from the clientTimerPairs array now
i couldnt get them to remove from the array, so i changed it to work like this-
var indexToRemove = [];
for (var i = 0; i < clientTimerPairs.length; i++) {
if (clientTimerPairs[i].pairedClient === client_socket) {
clearInterval(clientTimerPairs[i].interval);
indexToRemove.push(i);
}
}
for (var i = 0; i < indexToRemove.length; i++) {
console.log('removing index ' + indexToRemove[i] + '...');
clientSchedulePairs.splice(indexToRemove[i], 1);
}
however, even if i console print indexToRemove, and it has all index 0 - 6 in it, (because during testing i only connected 1 client with 6 timers), it should be stepping through clientTimerPairs and removing every single index so clientTimerPairs is empty, however, for some strange reason instead of going from 6 to 0 size, the array always ends up at 3 size!
even though it prints the removing index line 6 times and says it is removing index 0 - 5, 3 items are always left over in the clientTimerPairs array!
any idea why this might happen?
That push statement does not provide a proper key-value pair. How about using es6 Map to secure actual pairs?
However, it should work as intended.
const timers = [];
for (let i = 0; i < 5; i++) {
timers.push([setInterval(runTimer.bind({ id: i}), 100), i]);
}
function runTimer() {
console.log(`running for id ${this.id}`);
}
setTimeout(() => {
console.log('clearing timers')
for (let i = 0; i < timers.length; i++) {
clearInterval(timers[i][0]);
}
}, 2000);
Edit regarding the addition to your post
The splicing does exactly as it is intended to do. Say you have an array of 6 elements. You are clearing elements from the array using an array of indices and remove the first element. That array length becomes 5. The second index points to the 6th element. When you try to splice the 6th element by its index, nothing happends. This is because you removed one element from the array, which made the 6th element shift to the 5th position.
A simple solution could be using es6 filter:
let items = ['one', 'two', 'three', 'four'];
let indices = [1, 3];
items = items.filter((item, index) => indices.indexOf(index) === -1);
This returns an array with the first and third elements.

meteor minimongo getting inconsistent collection.findOne() results

I've been trying to debug a chunk of code for some hours now, banging my head against the wall, and finally pinpointed my issues to a place in the code where assigning the results of a collection.findOne() call to a variable is giving me different data than what I see with a console.log() of the same findOne() on the previous line.
prePostState = function(thisStID) {
console.log(Students.findOne({_id:thisStID}));
var stTemp = Students.findOne({_id:thisStID});
console.log(stTmp);
var testsTemp = stTmp.tests;
The collection object has a 'tests' array. In this instance, the array contains 3 objects as its elements.
While both the console.log() lines return something like this
Object {_id: "eXf9dqQbaemKS24Ti", name: "Student,Name", group: "none", site: "SiteName", tests: Array[3]}
Expanding each shows different data. The first one shows the correct tests: Array[3], the second one shows tests: Array[1], and the single element in that array also has data that is different from the matching element in the full array.
----Update----
Doing some further testing, I've changed the code a bit.
prePostState = function(thisStID) {
console.log(Students.find({_id:thisStID}).fetch()); //1
var stTmp = Students.find({_id:thisStID}).fetch();
console.log(stTmp); //2
console.log(stTmp[0].tests.length); //3
for(var i = 0; i < stTmp[0].tests.length; i++) {
console.log(stTmp[0].tests[i]); //4
}
1 Returns:
[Object]
0: Object
_id: "AqLHB8hT8GxzQ7zyD"
group: "none"
name: "Student,Name"
site: "SiteName"
tests: Array[3]
2 Returns:
[Object]
0: Object
_id: "AqLHB8hT8GxzQ7zyD"
group: "none"
name: "Student,Name"
site: "SiteName"
tests: Array[1]
3 Returns:
3
The for loop at 4 repeats three times and prints out each of the three objects in the tests array.
Obviously this means I can access the data I need. Instead of
var testArray = stTmp.tests;
Which leaves me with an array with only a single element, I will just have to get the length of stTmp.tests, and then use a for loop to access each element by index and insert them into the testArray variable.
So I can continue on, but I still don't understand the behavior I'm seeing. I'm on a bit of a timeline to keep making progress at this point, but when I have some time I may revisit this and try and replicate it in a meteorpad or other form that I can share the full code with.
1) If you modify a return value from Minimongo, don't expect it to persist. Minimongo was specifically written this way, so you are forced to use update operators to update the values.
2) The correct projection API is Coll.find({..selector..}, {fields:{..projection..}})

Detecting if array object is "in use"

I have some script that is calling AJAX information from a server and then displaying the information into blocks on the page. And every 8 seconds those blocks will fade to a new set of information.
The information from the server is stored in a fixed queue that pushes new items to it every 8 seconds.
And for each block I have it grab a random item from that array to show. The only thing is my blocks are getting a lot of duplicates.
Is there a way to check and see if that array item has been called from another block, and if so it will move on to find another item not in use.
var queue = FixedQueue( 50 );
$(document).ready(function() {
$('.submit').click(function(){
setInterval(function(){
queue.push(fulltweet);
},8000);
});
});
setInterval(function(){
randotime = intervals[Math.floor(Math.random()*intervals.length)];
$('.block1', '.photo1:nth-child(1)').queue(function(){
$(this).hide();
$(this).html(queue[0]);
$(this).fadeIn(2000);
$(this).delay(randotime);
$(this).dequeue();
});
$('.block1', '.photo1:nth-child(1)').fadeOut(2000);
},randotime);
I was creating a random number based on the length of the queue and using that to call queue[rando] but again, I keep getting duplicates in the blocks.
First, if you don't want duplicate items in your array, don't let them to be duplicate. Before inserting new items to your array, control whether it exists in your array or not. Using equality operation may not work if you use objects instead of primitive types(string, integer, etc..). Therefore you need a function checks if a given element exists in the array before insertion, and this function must use a equals function which compares two given objects.
Secondly, javascript allows you to add fields to objects in runtime. So when a block reaches and displays an object, you can put a field over this object. Let's say its name is 'inuse'.
When block A reaches the object:
object.inuse = true;
When block B reaches the same object randomly:
var object = pickRandomly();
while (object.inuse) {
object = pickRandomly();
}
// here's the unique object which is not used by another block.
I hope that helps.
If you can provide a sample code, I can provide a better answer.

javascript array/object issue

I am trying to push elements onto an array.
EDIT
task.prototype.goTest=function(){
for(a = 0; a < test.length; a++) {
if(this.testnumber != test[a].number) {
//it will only loop 8 times under conditional statement
group = {
title: test[a].Title,
ID: test[a].ID,
contents: []
};
this.company.push(group);
this.testnumber = test.number[a];
}
//outside of if conditional statement.. it will loop 15 times
//i want every test[a].conetents get pushed to group.contents array.
//this.company is the final variable I need for this function...
group.contents.push(test[a].contents);
}
console.log(this.company);
}
However, when I do
console.log(this.company);
I see 8 elmements with only 1 element in each group.contents array. The ideal situation is to have 8 elements with 2 to 3 elements in the group.contents array.
this refers to the object in the function.
Any idea how to solve my issue?
You are making a new group object each loop, so the reference to group.contents is only the current one, it does not reference the previously created group objects.
So, each time you call group.contents.push, you are only pushing onto the object created in that loop iteration.

Javascript/jQuery Id check to drive numbering function with validation

I need help with a loop... it's probably simple but I'm having difficulty coding it up.
Basically, I need to check existing Ids for their number so I can create a unique id with a different number. They're named like this: id="poly'+i'" in sequence with my function where i is equal to the number of existing elements. Example: Array 1, Array 2, Array 3 corresponding with i=1 for the creation of Array 1, i=2 for Array 2, etc.
Right now i is based on the total number of existing elements, and my "CreateNew" function is driven off x=i+1 (so the example above, the new element will be named Array 4). The problem is that if you delete one of the middle numbers, the "Create" function will duplicate the high number. i.e. Array 1, 2, 3 delete 2, create new-> Array 1, 3, 3.
I need an if() statement to check if the array already exists then a for() loop to cycle through all i's until it validates. Not sure how to code this up.
The code I'm trying to correct is below (note I did not write this originally, I'm simply trying to correct it with my minimal JS skills):
function NewPanel() {
var i = numberOfPanels.toString();
var x = (parseInt(i)+1).toString();
$('#items').append('<div onclick="polygonNameSelected(event)" class="polygonName" id="poly'+i+'"> Array '+ x +' </div>');
$('div[id*=poly]').removeClass('selected');
$('#poly'+i).addClass('selected');
$('#poly'+i).click(function() {
selectedPolygon = i;
$('div[id*=poly]').removeClass('selected');
$(this).addClass('selected');
});
}
THANK YOU! :)
Please clarify "The problem is that if you delete one of the middle numbers, ". What do you mean by delete? Anyway, the simplest solution is to create two arrays. Both arrays will have the same created id's. Whenever an id is created in the first array, an id will be added to the second array. So when it is deleted from first array, check your second array's highest value and then create this id in first array. I hope this did not confuse you.
Well it is hard to tell why you cannot just splice the array down. It seems to me there is a lot of extra logic involved in the tracking of element numbers. In other words, aside from the index being the same, the ids become the same as well as other attributes due to the overlapping 1, 3, 3 (from the example). If this is not the case then my assumption is incorrect.
Based on that assumption, when I encounter a situation where I want to ensure that the index created will always be an appending one, I usually take the same approach as I would with a database primary key. I set up a field:
var primaryKeyAutoInc = 0;
And every time I "create" or add an element to the data store (in this case an array) I copy the current value of the key as it's index and then increment the primaryKeyAutoInc value. This allows for the guaranteed unique indexing which I am assuming you are going for. Moreover, not only will deletes not affect future data creation, the saved key index can be used as an accessor.

Categories