if statement executes even with false condition - javascript

I've written some code which is a basic up/down voting list.
https://alasdairjames.github.io/up-down-counter1/
This works absolutely fine, apart from with the last list item. All the other list items up and down vote as they should.
With the last list item, if I 'down' vote it a few times, and then 'up' vote it, even if its counter is lower than its parent prev sibling counter, the if statement somehow still runs.
I've checked through all the code and I can't see where the problem is.
//Move it up
$(".testMoveUp").on("click", function(event){
// select the counter, increase it
const counter = $(event.target).siblings(".datasetCounter");
let counterNew = +$(counter).text()+1;
$(counter).text(counterNew);
//select this and previous counters
var thisCounter = $(event.target).siblings(".datasetCounter").text();
var prevCounter = $(event.target).parent().prev().children(".datasetCounter").text();
console.log(thisCounter);
console.log(prevCounter);
//move if appropriate
if ( thisCounter > prevCounter) {
var parent = $(event.target).parent();
var prevParent = $(event.target).parent().prev();
$(parent).insertBefore(prevParent);
}
});
//Move it down
$(".testMoveDown").on("click", function(event){
// select the counter, increase it
const counter = $(event.target).siblings(".datasetCounter");
let counterNew = $(counter).text()-1;
$(counter).text(counterNew);
//select this and previous counters
var thisCounter = $(event.target).siblings(".datasetCounter").text();
var nextCounter = $(event.target).parent().next().children(".datasetCounter").text();
console.log(thisCounter);
console.log(nextCounter);
//move if appropriate
if ( thisCounter < nextCounter) {
var parent = $(event.target).parent();
var nextParent = $(event.target).parent().next();
$(parent).insertAfter(nextParent);
}
});

if (thisCounter < nextCounter) -- you compare strings here, not numbers.
Use parseInt() to store numeric values in thisCounter and nextCounter:
var thisCounter = parseInt($(event.target).siblings(".datasetCounter").text(), 10);

The problem is on this two lines:
var thisCounter = $(event.target).siblings(".datasetCounter").text();
var nextCounter = $(event.target).parent().next().children(".datasetCounter").text();
You are getting the text value and comparing it.
The easier way to fix it is just to parse the texts to numbers. Since you are sure they will always be numbers, you can simply add '+' on your comparisons:
if (+thisCounter < +nextCounter) {
...
}
Note: remember to add it to both comparisons, not only one

String "9" is greater than string "10". Make sure to convert your values to numbers before comparing them.

Related

Can't get stable result with copying random values from array to an object

So I'm in process of creating a bot for a tournament and I got stuck on the part where I want to split players in pairs for play-off-style tournament. I just want to take 2 random players, get them from an array and write it as a value to a key as a round id for an object. Also I should not use those players again in the pair, so need to delete them or smth.
Here's the code:
var users = inc.funcs.getDatabase() //Getting a raw array of users (using my func that's basically a simplified fs.readFileSync func)
var tournamentPairs = new Object() //Object initialization
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * (users.length + 1)) //Randomizing 2 indexes
var second = Math.floor(Math.random() * (users.length + 1))
var player1 = client.users.get(users[first]) //Getting the players by id
var player2 = client.users.get(users[second])
tournamentPairs[id++] = [player1.id, player2.id] //Writing to the object
users.splice(first, 1) //Deleting user's indexes from the array to not use them anymore.
users.splice(second, 1)
}
console.log(tournamentPairs)
It works perfectly on the outside, but has a bad habit of duplicating users and I once could have a gamergod98 vs gamergod98 for example. I tried console.log this crap but it often get an error when trying to console.log player2 because it's undefined for some reason. If I try to print users[second] I get undefined though it never happened for the first player. So I tried different ways to prevent situations like this: first == second. Long story short it didn't help much.
I have 9 days 'till tournament starts, any ideas on how to improve this code?
You are getting undefined because you are going out of bounds of your users list. For a list of length the last element is list[length-1], but you are generating random numbers up to length.
To fix duplicate users, remove the first selected user from the list before selecting the second one (or for a less destructive approach, mark already selected users).
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * users.length)
var player1 = client.users.get(users[first])
users.splice(first, 1)
var second = Math.floor(Math.random() * users.length)
var player2 = client.users.get(users[second])
users.splice(second, 1)
tournamentPairs[id++] = [player1.id, player2.id]
}
Create a collection of used indexes and then if first or second are in used indexes then continue
var usedIndices = [] ;
if (usedIndices.indexOf(first) >= 0 ||
usedIndices.indexOf(second) >= 0) {
continue;
} else {
usedIndices.push(first);
usedIndices.push(second);
}
Put the usedIndices variable before for loop and the if else block inside loop after second

Get the highest number or the next available number in a list

I'm encountering a problem with assigning the next invoice line value.
I have written a piece of javascript to get the next value but somehow it is missing the next available value and still choosing the highest value.
What I need is the highest or the next available number, LineNo is what I need the highest or next of.
Code
onGridBeforeEditLines: function (e) {//grid 2
var event123 = e;
var lineNo = 0;
var grid = $("#gridLines").data("kendoGrid");
$(grid.dataSource.data()).each(function (i, v) {
if (v != null) {
if (v.LineNo >= lineNo)
lineNo = v.LineNo; //Getting the highest value
}
});
lineNo++;
grid = $("#gridContracts").data("kendoGrid");
if (e.model.PaymentPeriodID == 0) {
var selectedItem = grid.dataItem(grid.select());
e.model.PaymentPeriodID = selectedItem.ID;
e.model.LineNo = lineNo; //setting the value to the grid
}
},
Images
It seems to work fine for getting the highest number and adding 1 to it. The highest is 3, so 4 is the next available line number.
It doesn't seem to work in when finding the next available number. I have removed line no 2 so 2 should be the next available option but it still gets the highest and adds 1 to it.
Thank you in advance for help.
if (v.LineNo > lineNo+1) { // then we skipped a space
// next open value is lineNo+1
lineNo = lineNo+1;
return false; // break loop
} else if (v.LineNo == lineNo+1) {
lineNo = v.LineNo; //Getting the next sequential value , keep looping
} else {
// lineNo should stay the same
}

How can you dynamically slice an array in Javascript/jQuery?

I have a photo gallery that includes images that will be continuously uploaded. The PHP array has been converted/encoded to a JSON array so that I can manipulate the data with JavaScript.
Ideally, I would like to click a button ("Next Set" in the CodePen example) and load the next set (of 2) thumbnail images. This is in an effort to not load all of the images at once, which could be hundreds.
Problem: I cannot figure out how to dynamically slice the array on click (next 5 images). I can of course load, say, 2 at a time:
myArray.slice(0,2);
myArray.slice(3,5);
However, this will not work because images will be continuously added to the gallery. Furthermore, I would have to have too many sets of the above to keep slicing 5 out at a time.
I have tried:
Splitting the array into smaller arrays
for loops and $.each loops
I essentially need to be able to move the start and end index of the slice by (for example) 2 on click. Right now it just keeps slicing the same two images because the slicing is not dynamic.
Here is my CodePen
I don't think there's a way to do exactly what you want, but you can just keep track of where you were in the array and do a slice from there, like this:
var nextSet = myArray.slice(lastIndex, lastIndex + 2);
Replace your existing click() with this (including the declaration of lastIndex) to try it:
var lastIndex = 0
$('.button').click(function() {
var nextSet = myArray.slice(lastIndex, lastIndex + 2);
lastIndex += 2;
for (var i = 0; i < 2; i++) {
var li = $('<li/>').attr('role', 'menuitem').appendTo('.myList').append('<img src=' + nextSet[i] + '>');
}
});
Note that I've moved the slice() line outside the for loop. There's no need to slice a new array for every iteration.
Here's a CodePen using .slice().
An alternate method is to use to shift() to peel off the first item in the array with each iteration:
var nextItem = myArray.shift()
This is destructive though (it removes the item from the original array), so you'll need to make a copy of the original array first if you want to use it for anything else. Replace your click() with:
$('.button').click(function() {
for (var i = 0; i < 2; i++) {
var nextItem = myArray.shift();
var li = $('<li/>').attr('role', 'menuitem').appendTo('.myList').append('<img src=' + nextItem + '>');
}
});
Here's a CodePen using .shift().
your problem is simple i think. you do a slice and allways get back the same array
var array = [0,1,2,3,4,5];
let newArray1 = array.slice(0,2); // returns a new array
let newArray2 = array.slice(0,2); // returns the same new array
for(var i = 0; i < 2; i = i+2) {
result = array.slice(i, i+2);
console.log(result);
}

dice random value 1 to 10 and overthrow in Javascript

Hi I have code like this:
$('#Generator_Rzutow').click (function(){
var val1 = $('#rzucane').val();
var val2 = $('#zachowywane').val();
var zbior = [];
var limit = 10;
alert (val1);
alert (val2);
for (var i=0; i<val1;i++){
var wynik_rzutu = 1+Math.floor(Math.random()*10);
if (wynik_rzutu<limit){
zbior.push(wynik_rzutu);
} else {
limit = limit+10;
wynik_rzutu = wynik_rzutu+1+Math.floor(Math.random()*10);
if (wynik_rzutu<limit){
zbior.push(wynik_rzutu);
} else {
limit = limit+10;
wynik_rzutu = wynik_rzutu+1+Math.floor(Math.random()*10);
zbior.push(wynik_rzutu);
}
}
}
$('#wypisz').text (zbior);
});
My problem is that when it randoms '10' it sometimes add 10 to array, when it should randomize another time and ad it to prev value.
My second question is. How to get it to randomize another value and ad it to prev as long as it randomize 10. For ex: so it could get numer 74, when it randomize 7x10 and 4, and then it past it to array.
I know I should do it by while lop but I couldn`t get working solition, so instead I put 'if'
The first problem is that you don't reset your limit at each iteration. You start with limit 10, then when the first number larger than 10 is generated, the limit is increased to 20 and all subsequent numbers will be compared to 20 to see if they are added to the array or re-generated (and they will all be added to the array, since they are all smaller than 20).
As for your second problem, i think this piece of code behaves accordingly:
for (var i=0; i<val1;i++){
var wynik_rzutu = 0, limit = 0;
while (wynik_rzutu >= limit) {
wynik_rzutu += 1+Math.floor(Math.random()*10);
limit += 10;
}
zbior.push(wynik_rzutu);
}
You can also add a counter to prevent it from an infinite cycle (if Math.random() always returns 0.9 for example), but i doubt it is something you really require.

JavaScript command line calculator

I want to made calculator without buttons.
Can you help me with function calculate?
I have two arrays, first array with numbers, and second with arithmetic operators.
In function calculate I must send one element from first array and one from second, but it dont work. In final program must give answer as number.
Can you explain me method reduce, can i send second array as a parameter?
Because in docs i find that it only sum elements.
Ill be very grateful if somebody write example of method reduce with function.
Here is my code.
var str = ("1+1+1+1-1*3");
var reg = /(\d+\.\d+)|\d+/g;
var myArray = str.match(reg);
var reg1 = /['+','-','*',"/"]/g;
var myArray2 = str.match(reg1);
console.log(myArray);
console.log(myArray2);
var i = 0;
function calculate(prev,curr,i){
if(myArray2[i] === "+"){
//
curr = parseInt(prev,10)+parseInt(curr,10);
}
else if(myArray2[i]==='-'){
//
curr = prev-curr;}
else if(myArray2[i] ==='*'){
//
return prev*curr;
}
else{
//
return prev/curr;
}
}
var finAns = myArray.reduce(calculate);
alert ("Answer = " +finAns);
Yes, you can use reduce (see MDN) with your own function, but here you have some errors :
you should start calculation at index 1 since for the first element (index = 0), you have curr = prev = the first element (here 1)
your regex does not match the symbol - (you should escape it)
I have made a jsfiddle : http://jsfiddle.net/6UyUq/.
EDIT : it does not take into account operators precedence as showed in #Jim Wharton's comment.....

Categories

Resources