Names from localstorage into array to random name picker - javascript

i am trying to make a random name picker from an array of names taken from localstorage which seems that the error isn't popping up when i inspect it with google chrome.
Here's my code:
function getUserData() {
var Detail = localStorage.getItem("Detail");
if (Detail == null) {
Detail = []; // on new computer, create the local storage item } else {
Detail = JSON.parse(Detail); // convert from string to array
}
for (var i = 0; i < Detail.length; i++) { // loop through the array
var row = document.getElementById("Detail").insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
var cell4 = row.insertCell(3);
var cell5 = row.insertCell(4);
cell1.innerHTML = Detail[i].name;
cell2.innerHTML = Detail[i].admin;
cell3.innerHTML = Detail[i].email;
cell4.innerHTML = Detail[i].contact;
cell5.innerHTML = Detail[i].country;
}
}
function NamePicker() {
var Detail = localStorage.getItem("Detail");
if (Detail == null) {
Detail = []; // on new computer, create the local storage item
} else {
Detail = JSON.parse(Detail); // convert from string to array
}
// copy names
var nameArray = [];
for (var i = 0; i < Detail.length; i++) { // loop through the array
nameArray[i] = Detail[i].name;
}
for (var i = 0; i < Detail.length; i++) { // loop through the array
// get a number from random num generator %numArray.length
name = nameArray[num];
while (nameArray.length < 11) {
var randomnumber = Math.max(Math.ceil(Math.random() * 11))
var found = false;
for (var i = 0; i < nameArray.length; i++) {
if (name[i] == randomnumber) {
found = true;
break
}
}
if (!found) name[nameArray.length] = randomnumber;
}
// Display using modal
alert(name);
// remove using splice(num, 1);
name.splice(num, 1);
document.getElementById("Detail").innerHTML = name;
}
}
the problem is that it seems that num isn't removing the name from the list and alert function isn't popping up...
i really appreciate the help thanks in advance...

I found a couple of problems in you second function; you are using the local variable i in three for loops, and I think in one of them you meant to use num. Also, I changed Detail.length to nameArray.length in the second for loop since you are going through the nameArray. I also change the third for loop to use z instead of i.
function NamePicker() {
var Detail = localStorage.getItem("Detail");
if (Detail == null) {
Detail = []; // on new computer, create the local storage item
} else {
Detail = JSON.parse(Detail); // convert from string to array
}
// copy names
var nameArray = [];
for (var i = 0; i < Detail.length; i++) { // loop through the array
nameArray[i] = Detail[i].name;
}
for (var num = 0; num < nameArray.length; num++) { // loop through the array
// get a number from random num generator %numArray.length
name = nameArray[num];
while (nameArray.length < 11) {
var randomnumber = Math.max(Math.ceil(Math.random() * 11))
var found = false;
for (var z = 0; z < nameArray.length; z++) {
if (name[z] == randomnumber) {
found = true;
break
}
}
if (!found) name[nameArray.length] = randomnumber;
}
// Display using modal
alert(name);
// remove using splice(num, 1);
name.splice(num, 1);
document.getElementById("Detail").innerHTML = name;
}
}
Hope that helps!

Related

React Error : (function) is not defined at HTMLButtonElement.onclick

I am using ReactJS and I am creating a button "remove" in a method called showData() and appending it to a row in a table of people.
I am setting its attribute onclick to my method removePerson() implemented in the same class of the method showData().
This is all good until I click on the button "remove" - then an error shows:
ReferenceError: removePerson() is not defined at HTMLButtonElement.onclick
This is my code:
showData() {
let localStoragePersons = JSON.parse(localStorage.getItem("personsForms"));
persons = localStoragePersons !== null ? localStoragePersons : [];
let table = document.getElementById('editableTable');
let x = table.rows.length;
while (--x) {
table.deleteRow(x);
}
let i = 0;
for (i = 0; i < persons.length; i++) {
let row = table.insertRow();
let firstNameCell = row.insertCell(0);
let lastNameCell = row.insertCell(1);
let birthdayCell = row.insertCell(2);
let salaryCell = row.insertCell(3);
let choclatesCell = row.insertCell(4);
let genderCell = row.insertCell(5);
let workTypeCell = row.insertCell(6);
let hobbiesCell = row.insertCell(7);
let descriptionCell = row.insertCell(8);
let colorCell = row.insertCell(9);
firstNameCell.innerHTML = persons[i].firstName;
lastNameCell.innerHTML = persons[i].lastName;
birthdayCell.innerHTML = persons[i].birthday;
salaryCell.innerHTML = persons[i].salary;
choclatesCell.innerHTML = persons[i].Choclates;
genderCell.innerHTML = persons[i].Gender;
workTypeCell.innerHTML = persons[i].workType;
hobbiesCell.innerHTML = persons[i].Hobbies;
descriptionCell.innerHTML = persons[i].Description;
colorCell.innerHTML = persons[i].favoriteColor;
colorCell.style.backgroundColor = persons[i].favoriteColor;
let h = persons[i].ID;
let removeButton = document.createElement('button');
removeButton.setAttribute('onclick', 'removePerson(' + h + ')')
removeButton.innerHTML = 'Remove';
row.appendChild(removeButton);
}
}
I tried to change the code
removeButton.setAttribute('onclick', 'removePerson(' + h + ')');
to
removeButton.onclick = this.removePerson(h);
but everyTime the "showData()" method runs this method "removePerson()" run also and i don't want this to happen.
removePerson(ID) {
alert(ID);
let table = document.getElementById('editableTable');
if (persons.length === 1) {
table.deleteRow(1);
persons.pop();
localStorage.setItem("personsForms", JSON.stringify(persons));
}
let target;
let i;
for (i = 0; i < persons.length; i++) {
if (persons[i].ID === ID) {
target = persons[i].firstName;
persons.splice(i, 1); break;
}
}
for (i = 1; i < table.rows.length; ++i) {
let x = table.rows[i];
if (x.cells[0].innerHTML === target) {
table.deleteRow(i); break;
}
}
let temp = [];
let j = 0;
for (i = 0; i < persons.length; ++i) {
if (persons[i] !== null) {
temp[j++] = persons[i];
}
}
persons = temp;
localStorage.clear();
localStorage.setItem("personsForms", JSON.stringify(persons));
this.showData();
}
When you set a variable to some value, the value is computed first.
Hence, when you write removeButton.onclick = this.removePerson(h); the right side of the equation is evaluated first.
You can wrap it with a fat-arrow function, so that the function that will be called upon user click would be the function that calls this.removePerson(h). This way its value is a lambda function, and not the actual value of this.removePerson(h):
removeButton.onclick = () => this.removePerson(h);

How to set data from an array to another array to improve performance

I'm currently developing a sheet that shows results from a set of data based on some filters but the data loads to slowly when getting the results, I've tried to follow the Best Practices from Google Documentacion with no luck, how can I set an array for the data to load faster?
Below is the code commented with what I've already tried
function realizarBusqueda() {
var inicio = SpreadsheetApp.getActive().getSheetByName("INICIO");
var aux_tags = SpreadsheetApp.getActive().getSheetByName("Aux_Tags");
var data = SpreadsheetApp.getActive().getSheetByName("Data");
var data_lc = data.getLastColumn();
var data_lr = data.getLastRow();
var searchRange = data.getRange(2,1, data_lr, data_lc);
var inicio_lc = inicio.getLastColumn();
inicio.getRange("A8:L1000").clearContent();
inicio.getRange("A8:L1000").clearFormat();
var countRows = inicio.getMaxRows();
inicio.deleteRows(20, (20-countRows)*-1);
if (inicio.getRange("B4").isBlank()) {
inicio.getRange("A8:L1000").clearContent();
inicio.getRange("A8:L1000").clearFormat();
var countRows = inicio.getMaxRows();
inicio.deleteRows(20, (20-countRows)*-1);
SpreadsheetApp.flush();
}
else if ((inicio.getRange("B4").getValue() != "" &&
inicio.getRange("C4").getValue() === "")) {
//filtrado 1
var arrayDatos = searchRange.getValues();
var inicio_fr = 8;
//var row = new Array(11);
for (var j = 2; j <= data_lr; j++) {
//row[j] = new Array(data_lr);
if (aux_tags.getRange("P2").getValue() === arrayDatos[j-2][4]) {
var inicio_fc = 1;
for (var i = 0; i < arrayDatos[j-2].length; i++) {
//row[j][i] = arrayDatos[j-2][i];
var row = arrayDatos[j-2][i];
inicio.getRange(inicio_fr, inicio_fc).setValue(row);
inicio_fc++;
}
inicio_fr++;
}
//inicio.getRange("A8").setValues(row);
}
}
I expect the output to load lots faster, currently what I've tried is commented, the code as-is is working but too slow
I just wanted to update this subject because I figured out myself, see attached the new code with the use of new 2D arrays
...
//filtrado 1
var arrayDatos = searchRange.getValues();
var inicio_fr = 8;
var rows = [];
var row = [];
for (var j = 2; j <= data_lr; j++) {
if (aux_tags.getRange("P2").getValue() === arrayDatos[j-2][4]) {
var inicio_fc = 1;
for (var i = 0; i < arrayDatos[j-2].length; i++) {
row.push(arrayDatos[j-2][i]);
if (i == 11) {
rows.push(row);
row = [];
}
}
}
}
inicio.getRange(8, 1, rows.length, rows[0].length).setValues(rows);
}
Now instead of writing on row at a time, I just write the whole array at once

JS missing ) in parenthetical (line #88)

I'm writing a program in JS for checking equal angles in GeoGebra.
This is my first JS code, I used c# formerly for game programming.
The code is:
var names = ggbApplet.getAllObjectNames();
var lines = new Set();
var angles = new Set();
var groups = new Set();
for(var i=0; i<names.length; i++)
{
if(getObjectType(names[i].e)==="line")
{
lines.add(names[i]);
}
}
for(var i=0;i<lines.size;i++)
{
for(var j=0;j<i;j++)
{
var angle = new Angle(i,j);
angles.add(angle);
}
}
for(var i=0;i<angles.size;i++)
{
var thisVal = angles.get(i).value;
var placed = false;
for(var j=0;j<groups.size;j++)
{
if(groups.get(j).get(0).value===thisVal)
{
groups.get(j).add(angles.get(i));
placed = true;
}
}
if(!placed)
{
var newGroup = new Set();
newGroup.add(angles.get(i));
groups.add(newGroup);
}
}
for(var i=0;i<groups.size;i++)
{
var list="";
for(var j=0;j<groups.get(i).size;j++)
{
list = list+groups.get(i).get(j).name;
if(j != groups.get(i).size-1)
{
list = list+",";
}
}
var comm1 = "Checkbox[angle_{"+groups.get(i).get(0).value+"},{"+list+"}]";
ggbApplet.evalCommand(comm1);
var comm2 = "SetValue[angle_{"+groups.get(i).get(0).value+"}+,0]";
ggbApplet.evalCommand(comm2);
}
(function Angle (i, j)
{
this.lineA = lines.get(i);
this.lineB = lines.get(j);
this.name = "angleA_"+i+"B_"+j;
var comm3 = "angleA_"+i+"B_"+j+" = Angle["+this.lineA+","+this.lineB+"]";
ggbApplet.evalCommand(comm3);
var val = ggbApplet.getValue(this.name);
if(val>180)
{val = val-180}
this.value = val;
ggbApplet.setVisible(name,false)
});
function Set {
var elm;
this.elements=elm;
this.size=0;
}
Set.prototype.get = new function(index)
{
return this.elements[index];
}
Set.prototype.add = new function(object)
{
this.elements[this.size]=object;
this.size = this.size+1;
}
It turned out that GeoGebra does not recognize Sets so I tried to make a Set function.
Basically it collects all lines into a set, calculates the angles between them, groups them and makes checkboxes to trigger visuals.
the GeoGebra functions can be called via ggbApplet and the original Workspace commands via ggbApplet.evalCommand(String) and the Workspace commands I used are the basic Checkbox, SetValue and Angle commands.
The syntax for GeoGebra commands are:
Checkbox[ <Caption>, <List> ]
SetValue[ <Boolean|Checkbox>, <0|1> ]
Angle[ <Line>, <Line> ]
Thank you for your help!
In short, the syntax error you're running to is because of these lines of code:
function Set {
and after fixing this, new function(index) / new function(object) will also cause problems.
This isn't valid JS, you're likely looking for this:
function Set() {
this.elements = [];
this.size = 0;
}
Set.prototype.get = function(index) {
return this.elements[index];
};
Set.prototype.add = function(object) {
this.elements[this.size] = object;
this.size = this.size + 1;
};
Notice no new before each function as well.
I'm not sure what you're trying to accomplish by creating this Set object though - it looks like a wrapper for holding an array and its size, similar to how something might be implemented in C. In JavaScript, arrays can be mutated freely without worrying about memory.
Here's an untested refactor that removes the use of Set in favour of native JavaScript capabilities (mostly mutable arrays):
var names = ggbApplet.getAllObjectNames();
var lines = [];
var angles = [];
var groups = [];
for (var i = 0; i < names.length; i++) {
if (getObjectType(names[i].e) === "line") {
lines.push(names[i]);
}
}
for (var i = 0; i < lines.length; i++) {
for (var j = 0; j < i; j++) {
angles.push(new Angle(i, j));
}
}
for (var i = 0; i < angles.length; i++) {
var thisVal = angles[i].value;
var placed = false;
for (var j = 0; j < groups.length; j++) {
if (groups[j][0].value === thisVal) {
groups[j].push(angles[i]);
placed = true;
}
}
if (!placed) {
groups.push([angles[i]]);
}
}
for (var i = 0; i < groups.length; i++) {
var list = "";
for (var j = 0; j < groups[i].length; j++) {
list += groups[i][j].name;
if (j != groups[i].length - 1) {
list += ",";
}
}
var comm1 = "Checkbox[angle_{" + groups[i][0].value + "},{" + list + "}]";
ggbApplet.evalCommand(comm1);
var comm2 = "SetValue[angle_{" + groups[i][0].value + "}+,0]";
ggbApplet.evalCommand(comm2);
}
function Angle(i, j) {
this.name = "angleA_" + i + "B_" + j;
var comm3 = "angleA_" + i + "B_" + j + " = Angle[" + lines[i] + "," + lines[j] + "]";
ggbApplet.evalCommand(comm3);
var val = ggbApplet.getValue(this.name);
if (val > 180) {
val -= 180;
}
this.value = val;
ggbApplet.setVisible(name, false);
}
Hopefully this helps!
Your function definition is missing the parameter list after the function name.
Also, you're initializing the elements property to an undefined value. You need to initialize it to an empty array, so that the add method can set elements of it.
function Set() {
this.elements=[];
this.size=0;
}

JavaScript cannot find method a second time?

I'm attempting to build a poker game. The method in question is very simple, and it works when it runs the first time.
This part isn't perfect convention because I'm just using it to test my methods:
var $ = function (id) { return document.getElementById(id); };
var test = function() {
var deck = new POKER.Deck();
var hand = new POKER.Hand();
for (var i = 0; i < 7; i++){
hand.addCard(deck.dealCard());
}
hand.sortByRank();
for (var j = 0; j < 7; j++){
var img = document.createElement("img");
var card = hand.getCardAtIndex(j); //** <------- WORKS HERE**
img.src = card.getImage();
$("images").appendChild(img);
}
var testHand = new POKER.Hand();
testHand = hand.removePairs();
for (var k = 0; k < testHand.length; k++) {
var img2 = document.createElement("img");
var card2 = testHand.getCardAtIndex(k); // **<------FAILS HERE**
img2.src = card2.getImage();
$("handImg").appendChild(img2);
}
};
window.onload = function() {
test();
};
The first and second loop work, and the hand is displayed and everything. When it gets to the last loop, the debugger tells me "TypeError: testHand.getCardAtIndex is not a function"
I was attempting to test the removePairs method (to test for straights more easily), and when watching the variables in the debugger, testHand clearly gets populated correctly. The method seems to work just fine.
getCardAtIndex:
POKER.Hand.prototype.getCardAtIndex = function(index) {
return this.cards[index];
};
removePairs:
POKER.Hand.prototype.removePairs = function(){
var allCards = this.cards;
var tempCards = [];
var uniqueRanks = [];
var unique;
for(var i = 0; i < allCards.length; i++){
unique = true;
for(var j = 0; j < uniqueRanks.length; j++){
if(allCards[i].getRank() == uniqueRanks[j]){
unique = false;
break;
}
}
if(unique){
uniqueRanks.push(allCards[i].getRank());
tempCards.push(allCards[i]);
}
}
return tempCards;
};
I'm completely perplexed.
var testHand = new POKER.Hand();
testHand = hand.removePairs();
hand.removePairs() returns an Array, not a Hand object.
That's why you don't have access to the getCardAtIndex method.
If cards is a public property you could do:
testHand.cards = hand.removePairs();
Or you can have a setter method:
testHand.setCards(hand.removePairs);

Adding a running sum to a javascript object

I have a javascript object as below
var mydata=[
{"Club":"Blackburn","EventNo":1,"Pnts":3,"CumPnts":0},
{"Club":"Blackburn","EventNo":2,"Pnts":1,"CumPnts":0},
{"Club":"Blackburn","EventNo":3,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":1,"Pnts":2,"CumPnts":0},
{"Club":"Preston","EventNo":2,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":3,"Pnts":2,"CumPnts":0},]
I want to update the object so that CumPnts contains a running points total for each Club as below
{"Club":"Blackburn","EventNo":1,"Pnts":3,"CumPnts":3},
{"Club":"Blackburn","EventNo":2,"Pnts":1,"CumPnts":4},
{"Club":"Blackburn","EventNo":3,"Pnts":4,"CumPnts":8},
{"Club":"Preston","EventNo":1,"Pnts":2,"CumPnts":2},
{"Club":"Preston","EventNo":2,"Pnts":4,"CumPnts":6},
{"Club":"Preston","EventNo":3,"Pnts":1,"CumPnts":7},]
Any help would be much appreciated
Here is a function that loops through the list and updates it after it's been added. But I suspect that the events come in one at a time so there could be another function that can look the cumPtns obj and take from that. Here is for the current list.
var cumData = {};
var mydata=[
{"Club":"Blackburn","EventNo":1,"Pnts":3,"CumPnts":0},
{"Club":"Blackburn","EventNo":2,"Pnts":1,"CumPnts":0},
{"Club":"Blackburn","EventNo":3,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":1,"Pnts":2,"CumPnts":0},
{"Club":"Preston","EventNo":2,"Pnts":4,"CumPnts":0},
{"Club":"Preston","EventNo":3,"Pnts":2,"CumPnts":0}];
function updateMyData() {
for (var i = 0; i < mydata.length; i++) {
var item = mydata[i];
if(cumData[item.Club] == undefined) {
cumData[item.Club] = {};
cumData[item.Club] = item.Pnts;
} else {
cumData[item.Club] = cumData[item.Club] + item.Pnts;
}
mydata[i].CumPnts = cumData[item.Club];
};
console.log(mydata);
//if you want to return it you can have this line below. Otherwise the object is updated so you'll probably want to do something with it once it's updated. Call back maybe?
return mydata;
}
updateMyData();
The first time it encounters a team it adds it to an array and so does with the corresponding cumPnts, so we can keep track of whether we checked a team earlier or not.
var tmArr = [];
var cumArr = [];
for(var i = 0; i < mydata.length; i++) {
var elm = mydata[i];
var club = elm.Club;
var points = elm.Pnts;
var idx = tmArr.indexOf(club);
if(idx > -1) {
cumArr[idx] += points;
elm.CumPnts = cumArr[idx];
}
else {
elm.CumPnts = points;
tmArr[tmArr.length] = club;
cumArr[cumArr.length] = points;
}
}
jsfiddle DEMO

Categories