socketio array.splice dont work if make console.log - socket.io

Strange phenomenon. socketio
SERVER
i have that code...
socket.on('disconnect', function(){
console.log('user disconnected');
for(var i=0; i<stores.length; i++ ){
var c = stores[i];
if(c.socketid == socket.id){
stores.splice(i,1);
break;
}
}
});
everything goes well with the .splice. If i print the stores array from elsewhere, it displayed correct ...but in this situation
socket.on('disconnect', function(){
console.log('user disconnected');
for(var i=0; i<stores.length; i++ ){
var c = stores[i];
if(c.socketid == socket.id){
for(var i=0; i<stores.length;i++){
console.log(i+" one"+stores[i].name+"-"+stores[i].id)
}
stores.splice(i,1);
for(var i=0; i<stores.length;i++){
console.log(i+" two"+stores[i].name+"-"+stores[i].id)
}
break;
}
}
});
the array has not lost its values, i visit the page from my browser(i connected),
socket.on('storelogged', function (msg){
var storeInfo = new Object();
storeInfo.name = msg.name;
storeInfo.id = msg.id;
storeInfo.socketid = socket.id;
stores.push(storeInfo);
console.log(msg.name + " has connected with " + msg.id + " id." );
});
so, stores pushed. But when i disconnected in the second situation of socket.on('disconnect',callback) the stores array still contains the values( in other words, splice dont work )
comment for giving, much and better information. Also you can test it and see the results

Your embedded for loops are overwriting the i variable from the top level for loop.
Either use let instead of var as in for (let i = 0; ....) for all your for loops so each has a different locally scoped value of i and the inner loops won't overwrite the outer loops or use a different variable name for the embedded for loops or use .forEach() which creates a new variable for the index.
In addition, after you call .splice() on the array you are iterating, you have decrement the current array index from your for loop or you will skip looking at one of the values in the array because the .splice() moved it down into the index spot that you just removed and that your for loop has already iterated.
For example, you can change variable names of the inner for loops like this:
socket.on('disconnect', function () {
console.log('user disconnected');
for (var i = 0; i < stores.length; i++) {
var c = stores[i];
if (c.socketid == socket.id) {
for (var j = 0; j < stores.length; j++) {
console.log(j + " one" + stores[j].name + "-" + stores[j].id)
}
stores.splice(i, 1);
// make sure not to skip the value we just moved into the i slot in the array
i--;
for (var k = 0; i < stores.length; k++) {
console.log(k + " two" + stores[k].name + "-" + stores[k].id)
}
break;
}
}
});
Or, you can use let for the for loops:
socket.on('disconnect', function () {
console.log('user disconnected');
for (var i = 0; i < stores.length; i++) {
var c = stores[i];
if (c.socketid == socket.id) {
for (let i = 0; i < stores.length; i++) {
console.log(i + " one" + stores[i].name + "-" + stores[i].id)
}
stores.splice(i, 1);
// make sure not to skip the value we just moved into the i slot in the array
i--;
for (let i = 0; i < stores.length; i++) {
console.log(i + " two" + stores[i].name + "-" + stores[i].id)
}
break;
}
}
});
Or, you can use .forEach():
socket.on('disconnect', function () {
console.log('user disconnected');
for (var i = 0; i < stores.length; i++) {
var c = stores[i];
if (c.socketid == socket.id) {
stores.forEach(function(item, index) {
console.log(index + " one" + item.name + "-" + item.id)
});
stores.splice(i, 1);
// make sure not to skip the value we just moved into the i slot in the array
i--;
stores.forEach(function(item, index) {
console.log(index + " one" + item.name + "-" + item.id)
});
break;
}
}
});

Related

How to copy a formula from "Parent Tab" to "Child Tab" on Google Sheet

I'm doing RolePlay Character Sheets on a "Parent tab" I've called "MODEL", where I masterize my formulas.
I've created a second tab "Character1" and a third one "Character2". But when I try to use =QUERY or =TEXTFORMULA or whatever. It doesn't make the formulas to calculate on the actual spreadsheet, it just get the data from the "MODEL" tab.
My only way is actually to copy/past all my formulas, but if I do a mistake, I'll have to correct it in every spreadsheet every time.
Is that possible to have a formula which take the cell at:
MODELE!AE58
And automatically generate the same formulas in every tabs:
CHARACTER1!AE58
CHARACTER2!AE58
etc...
Sorry if its blur, I'm doing my best to explain.
simple
Try
function onEdit(e) {
var sh = e.source.getActiveSheet()
var rng = e.source.getActiveRange()
if (rng.getFormula() != '' && sh.getName() == 'MODEL') {
var excl = ['MODEL', 'OTHER'];//excluded sheets
SpreadsheetApp.getActiveSpreadsheet().getSheets().forEach(sh => {
if (!~excl.indexOf(sh.getSheetName())) {
sh.getRange(rng.getA1Notation()).setFormula(rng.getFormula())
}
})
}
}
when you change a formula in MODEL, this will also change in other tabs excepts excluded ones
multiple
If you edit the formulas by dragging them into the MODEL sheet, use this one which allows you to edit all the formulas at once
function onEdit(e) {
var sh = e.source.getActiveSheet()
if (sh.getName() != 'MODEL') return;
for (var i = e.range.rowStart; i <= e.range.rowEnd; i++) {
for (var j = e.range.columnStart; j <= e.range.columnEnd; j++) {
if (sh.getRange(i, j).getFormula() != '') {
var excl = ['MODEL', 'OTHER'];//excluded sheets
SpreadsheetApp.getActiveSpreadsheet().getSheets().forEach(child => {
if (!~excl.indexOf(child.getSheetName())) {
child.getRange(sh.getRange(i, j).getA1Notation()).setFormula(sh.getRange(i, j).getFormula())
}
})
}
}
}
}
global
Il you need to reset all formulas, enable google sheets api and try
function onOpen() {
SpreadsheetApp.getUi().createMenu('⇩ M E N U ⇩')
.addItem('👉 Apply all formulas from MODEL to all tabs', 'spreadFormulas')
.addToUi();
}
function spreadFormulas() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('MODEL')
if (sh.getName() != 'MODEL') return;
var data = [];
var formulas = sh.getRange(1, 1, sh.getLastRow(), sh.getLastColumn()).getFormulas()
for (var i = 0; i < formulas.length; i++) {
for (var j = 0; j < formulas[0].length; j++) {
if (formulas[i][j] != '') {
var excl = ['MODEL', 'OTHER'];//excluded sheets
SpreadsheetApp.getActiveSpreadsheet().getSheets().forEach(child => {
if (!~excl.indexOf(child.getSheetName())) {
data.push({
range: `${child.getName()}!${columnToLetter(+j + 1) + (+i + 1)}`,
values: [[`${formulas[i][j]}`]],
})
}
})
}
}
}
if (data.length) {
var resource = {
valueInputOption: 'USER_ENTERED',
data: data,
};
try { Sheets.Spreadsheets.Values.batchUpdate(resource, ss.getId()); } catch (e) { console.log(JSON.stringify(e)) }
}
}
function columnToLetter(column) {
var temp, letter = '';
while (column > 0) {
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
if your sheet is called MODELE try on some other sheet just:
=MODELE!AE58
for array it would be:
={MODELE!AE58:AE100}
also take a look into "Named Ranges" - maybe you will find it more handy

For loop in promise function

I have below functions that I am trying to use an async function to check if an item Id was already added into a grid. But, I am stuck at the for loop "processFindCode" function, it always returns false. How to make the checking routine work and continue to addItem function?
My objective,
1. a loop up event pass in selected array values
2. get needed info array via web api
3. process each of array item
4. validate if the item.Id_item_code already exists in detail grid, if not add a new item into the grid
sorry for the lengthy code, I am considered new to js. please also advise the best way to achieve my objective.
Thank in advance
var theList = this.value;
if (theList == "") {
return true;
}
// Set up aysnc promise function
async function processAPIResult() {
let result;
let promises = []; //setup a promises aray
// Loop thru Lookup selections
// results store in the promises aray
theList.split(',').forEach(function (kId, k) {
promises.push(make_api_call(kId));
})
result = await Promise.all(promises); // async await
return result;
}
// Call API Function
function make_api_call(id) {
return ($.get(ew.API_URL + "GetQuotationDetail/" + encodeURIComponent(id)));
}
function delay() {
return new Promise(resolve => setTimeout(resolve, 300));
}
async function addItem(kcode) {
var ridx = $("#key_count_fs_invoicedtlgrid")[0].value; // get actual table row
// Get serices information from API
var tQty = 1;
if (ridx == 1 && $("#x1_Id_item_code")[0].value == "") {
$("#x" + ridx + "_Id_item_code").value(kcode);
$("#x" + ridx + "_qty").value(tQty);
$("#x" + ridx + "_Id_item_code").select();
$("#x" + ridx + "_Id_item_code").change();
//$("#x" + ridx + "_Id_quotattoindetl").value(Id_quotationDetail); // store quotation detail Id
} else {
// 2nd row onward
// when it is available but it it is not empty, create a new row
if (typeof $("#x" + ridx + "_Id_item_code") === 'undefined' || $("#x" + ridx + "_Id_item_code")[0] != "") {
ew.addGridRow('#tbl_s_invoicedtlgrid');
}
ridx = $("#key_count_fs_invoicedtlgrid")[0].value;
var c_part_code = $("#x" + ridx + "_Id_item_code")[0];
var c_qty = $("#x" + ridx + "_qty")[0];
c_part_code.value = kcode;
c_qty.value = fmtDecimal(tQty, 'qty');
$("#x" + ridx + "_Id_item_code").select();
$("#x" + ridx + "_Id_item_code").change();
//$("#x" + ridx + "_Id_quotattoindetl").value(Id_quotationDetail); // store quotation detail Id
// trigger onChange to updateAmount() function;
$("#x" + ridx + "_qty").change();
}
}
async function processFindCode(code) {
found = false;
var rCnt = $("#key_count_fs_invoicedtlgrid")[0].value;
for (j = 1; j < rCnt + 1; j++) {
// loop thru row and col
if ($("#x" + j + "_item_code").val() != null) {
if ($("#x" + j + "_item_code").val() == kcode) {
if ($("#x" + j + "_item_code")[0].style.display != "none") { // visible row only. Deleted row's display is set to hidden.
found = true;
}
break; // exit loop column
}
}
if (found) {
break; // exit loop row
}
} // end for loop rCnt
isFound = found;
return isFound;
}
async function processItemCode(code) {
// notice that we can await a function
// that returns a promise
let isFound = await processFindCode(code);
await delay();
if (!isFound) {
await addItem(code);
}
console.log('Done! ' + code);
//await delay();
//console.log(item.Id_item_code);
}
async function processAPIitem(item) {
for (const itm of item) {
await processItemCode(itm.Id_item_code);
}
//console.log('Done! '+ apiitem.Id_item_code);
}
// main async task to get results
//-------------------------------
async function doTask() {
//get result form API function
let result = await processAPIResult();
//process each API array
for (const item of result) {
await processAPIitem([item]);
}
}
doTask();
Simple answer: $item_code.hide() hides; it isn't a test. Use $item_code.is(':visible') instead.
function processFindCode(code) {
var found = false;
var rCnt = $('#key_count_fs_invoicedtlgrid').val();
for (var j=1; j<rCnt+1; j++) {
if ($('#x' + j + '_item_code').val() != null) {
if ($('#x' + j + '_item_code').val() == code) {
if ($('#x' + j + '_item_code').is(':visible')) {
found = true;
break;
}
}
}
}
return found;
}
Longer answer: Finding the desired element with $('#x' + j + '_item_code') is inefficient especially when performed three times. You can improve matters by leveraging the power of javascript/jQuery and write something like this.
function processFindCode(code) {
var $rows = $('#tbl_s_invoicedtlgrid tbody tr'); // select all table rows in the table's tbody (assumed selector) .
return $rows.get().reduce(function(bool, row) {
return bool || $("id*='_item_code'", row).filter(':visible').filter(function() {
return this.value === code;
}).length > 0;
}, false);
}
This is still not as efficient as it could be. The "id*='_item_code'" selector is pretty nasty but at least it only applies to one row at a time, not the whole DOM.
For vastly improved efficiency, give the item_code element class="item_code" and select with $(".item_code", row). The addItem() function would benefit greatly from the same approach.

javascript cannot read property undefined of undefined

I need help and quick since this project is for this wednesday and i dont know what its wrong with my code and its screwing everything.
This is supposed to be a battleships game
the click handler keeps screwing me over and i hope you can help me`
this.Handler = function (getRow, getColumn) {
var myId = "#grid_" + getRow + "_" + getColumn;
if (this.GridArray[getRow][getColumn] == 0) {
$(myId).removeClass('grid');
$(myId).addClass('gridMiss');
this.bullets--;
}
else if (this.GridArray[getRow][getColumn] == 1) {
$(myId).removeClass('grid');
$(myId).addClass('gridHit');
explosion.pause();
explosion.play();
Ships.isHit(getRow, getColumn);
this.ShipStatus();
this.bullets--;
this.bulletStatus();
//call the function that keep track of the hits of the ships
}
}
this.ClickHandler = function () {
refOutside = this
$('.grid').click(function (eventData) {
var getRow = $(this).attr('data-Row');
var getColumn = $(this).attr('data-Column');
refOutside.Handler(getRow, getColumn);
});
}
}
And in here i have the creation of the array
this.CreateEmptyGrid = function () {
for (i = 0; i < ROWS; i++) {
this.GridArray[i] = [];
for (j = 0; j < COLUMNS; j++) {
this.GridArray[i][j] = 0;
}
}
}

Modifying sort columns in jqGrid

I'm having some difficulty figuring out how to programatically modify the sort definition that is sent to the server when a user clicks on a column to sort it. I have added a onSortCol function to my grid configuration. In that function, I need to check whether the "Id" column is in any sort position other than the last position. If it is, it should be removed.
Here is what I have tried:
onSortCol: function (index, iCol, sortOrder) {
var grid = $(this);
var rawSorts = index.split(",");
if (rawSorts.length > 1) {
var idFieldIndex = -1;
var processedSorts = [];
for (i = 0; i < rawSorts.length; i++) {
var currentSort = rawSorts[i].match(/[^ ]+/g);
if (idFieldIndex === -1 && currentSort[0].toUpperCase() === "ID") {
idFieldIndex = i;
}
processedSorts.push({
field: currentSort[0],
direction: currentSort[1] || sortOrder
})
}
if (idFieldIndex !== -1) {
processedSorts.splice(idFieldIndex, 1);
for (i = 0; i < processedSorts.length; i++) {
if (i + 1 < processedSorts.length) {
grid.sortGrid(processedSorts[i].field + " " + processedSorts[i].direction);
}
else {
grid.setGridParam("sortorder", processedSorts[i].direction);
grid.sortGrid(processedSorts[i].field + " ", true);
}
}
return "stop";
}
}
}
The most simple implementation seems to me the following: you don't use any sortname in the grid initially and you sort by Id on the server side if sidx is empty. It seems the only what you need to do to implement your requirements.

Need to generate random data for Highcharts series

I'm trying to generate some random data points for my Highcharts series, but I'm having issues with the data function. Here's my code (simplified from Fiddle):
series : {
name : 'Total Mentions',
type:'spline',
lineWidth:1,
data : (function() {
var arr = [];
for(var i = 0; i < 500; i++) {
var date = randomDate(new Date(2004, 0, 9), new Date());
var randNum = Math.round(Math.random()*100);
var finalDate = "Date.UTC(" + date.getFullYear() + ", " + date.getDate() + ", " + date.getMonth() + ")";
arr.push([finalDate, randNum]);
}
return arr;
})()
},
[...etc...],
The format that should be coming out should look like this:
[Date.UTC(2008, 23, 8),56],
[Date.UTC(2012, 12, 6),21],
[Date.UTC(2008, 22, 10),16],
[Date.UTC(2009, 17, 7),25],
[...etc...],
Right now, my page isn't loading the chart. The page will load infinitely, as if it's not recognizing the data.
Any thoughts?
You should push date in millisec in array, like this;
arr.push([date.getTime(), randNum]);
arr.sort(function (a,b) { if (a[0] < b[0]) return -1; if (a[0] > b[0]) return 1;
return 0; })
return arr;
I've created a fiddle at; http://jsfiddle.net/hkskoglund/cnTqS/4/
Try catching other syntax errors in the console in Chrome devtools.

Resources