Incrementing values in loop acting weird - JavaScript - javascript

I have a code that checks indexes of array with some ID's, and increases some order value for items with those ID's. The code looks something like this:
function changeOrder(initialIndex, newIndex, itemsMap, itemIds) {
const requestPayload = [];
itemsMap[itemIds[initialIndex]].order = itemsMap[itemIds[newIndex]].order;
requestPayload.push(itemsMap[itemIds[initialIndex]]);
if (initialIndex > newIndex) {
for (let i = newIndex; i < initialIndex; i++) {
itemsMap[itemIds[i]].order++;
requestPayload.push(itemsMap[itemIds[i]]);
}
}
console.log(requestPayload);
return requestPayload;
}
Now, the issue is when i hover over the requestPayload inside the console.log, order values are correct (0, 1, 2 in my case). But once it does the logging, or returns the requestPayload, values are 1, 2, 3. Function is triggered only once, so it doesn't increment them again. Here is the screenshot, you can see when I manually log the values when breakpoint is set vs logged payload.
EDIT: Solved with the help from #Pointy in the comments:
for (let i = newIndex; i < initialIndex; i++) {
const copy = { ...itemsMap[itemIds[i]] };
copy.order++;
requestPayload.push(copy);
}

Related

A problem with array and checking the values inside

Hello recently I was working with arrays in JavaScript and appear a little problem with a function.
My problem is in the function checkRepeat, in this function I try to know if I click a Card before or not, when I click the first Card work but with the other cards they don't work, I was thinking that my problem maybe it's for the loop because maybe it's taking only one element but I don't know.
This is my code:
const cardArray = [
{name: 'fries'},
{name: 'pizza'},
{name: 'hotdog'},
{name: 'cheeseburger'},
{name: 'milkshake'},
{name: 'ice-cream'}
]
const emptyCard = [
{name: 'white'},
{name: 'blank'}
]
// the format of the img
const format = '.png'
// I select the place where I gonna put the board
const grid = document.querySelector('.grid');
const cardsChosen = [];
const cardsChosenId = [];
const createBoard = () =>{
for(let n = 0; n < cardArray.length*2; n++)
{
// I create the img
let card = document.createElement('img');
card.src = `images/${emptyCard[1].name}${format}`;
card.id = `card-${n}`
card.addEventListener('click',flipCard)
grid.appendChild(card)
}
}
function flipCard(){
// I get the id, just the number
let cardId = parseInt(this.getAttribute('id').slice(5,7));
const v1 = checkRepeat(cardsChosenId,cardId);
console.log("Value: ",v1)
//console.log("Values in the array: ",cardsChosenId)
}
function checkRepeat(array,value){
if(array.length === 0){// if the array is empty
array.push(value);//push in the array the value
return true;// and return true
}
else{// if isn't
for(let i = 0; i < array.length; i++){// walk through the array
if(array[i] === value){// check if the values of the array === value
return false;
}
else{// if the value and the array values are different
array.push(value);//push the value
return true;
}
}
}
}
createBoard();
I found the error in the code, the problem was the logic.
Because when it traversed the array, it finds an equal value, but it continues traversing the array and the other values ​​do not resemble the compared value, so it adds the same values ​​to me later in the array.
I explain:
When I click on each of the cards, they save the id in an arrangement, and if I click again on a card that I had previously given it, it would compare with each element and when it found the same one, it would return false, but continued scrolling the whole arrangement and added more elements to the arrangement when I shouldn't have.
Example:
I click on the 1st element, [0] is saved, I click on the second [0,1] and I give the second element again and when comparing 0 with 1 I find that they are different and it remains like this [0,1,1] when it should return only [0,1]
I resolve with includes:
function checkRepeat(array,value){
if(array.includes(value)){//return true if value it's in the array
return false;
}
else{
array.push(value);
return true;
}
}

Unexpected object change

I am implementing end of round function for a board game. Each players state is represented with an object that is in turn stored in array playerStates:
const [playerStates, setPlayerStates] = useState(getInitialPlayerStates);
const [playerIndex, setPlayerIndex] = useState(0);
const playerState = playerStates[playerIndex];
function setPlayerState(playerState) {
let tPlayerStates = [...playerStates];
tPlayerStates.splice(playerIndex, 1, playerState);
setPlayerStates(tPlayerStates);
}
End of round function checks whether all players have finished their actions, and if so, resets global state
/** END OF ROUND **/
function handleEndRound() {
let nextPlayerIndex = playerIndex + 1 < GLOBAL_VARS.numOfPlayers ? playerIndex + 1 : 0;
let haveAllFinished = true;
while (playerIndex !== nextPlayerIndex) {
if (!playerStates[nextPlayerIndex].finishedRound) {
haveAllFinished = false;
}
nextPlayerIndex = nextPlayerIndex + 1 < GLOBAL_VARS.numOfPlayers ? nextPlayerIndex + 1 : 0;
}
if (haveAllFinished) {
...
/* reset player states */
let tPlayerStates = [];
for (let i = 0; i < GLOBAL_VARS.numOfPlayers; i++) {
let tPlayerState = {...playerStates[i]};
console.log("RESETTING PLAYER STATE:");
console.log(tPlayerState);
tPlayerState.availableAdventurers = GLOBAL_VARS.adventurers;
/* remove active card */
if (tPlayerState.activeCard !== false) {
tPlayerState.discardDeck.push(tPlayerState.activeCard);
tPlayerState.activeCard = false;
}
/* move cards from hand to discard */
for (let card of tPlayerState.hand) {
tPlayerState = addCardToDiscardDeck(card, tPlayerState);
tPlayerState.hand = [];
}
console.log("tPlayerState before:");
console.log(tPlayerState);
/* draw a new hand */
for (let i = 0; i < GLOBAL_VARS.handSize; i++) {
if (tPlayerState.drawDeck.length === 0) {
console.log("tPlayerState after:");
console.log(tPlayerState);
tPlayerState = addDiscardToDrawDeck(tPlayerState);
}
if (tPlayerState.drawDeck.length > 0) {
tPlayerState = addCardToHand(tPlayerState.drawDeck[0], playerState);
tPlayerState.drawDeck.splice(0, 1);
}
}
...
The problem is that wrong player state is stored, as evidenced by the console outputs:
tPlayerState before: App.js:315
Object { finishedRound: true, ... color: "#FFD41A" }
tPlayerState after: App.js:320
Object { finishedRound: false, ... color: "#2A8CFF" }
The color identifies players, and for some reason state of the first player is exchanged by the state of the second player.
There is a lot going on with deep-nested objects and arrays and that might be the cause - however I do not see why exactly should these two outputs be different. What is the source of the change? How can I prevent it?
The complete code is hosted at https://github.com/faire2/loreHunters/.
Additional information:
The problem is pertinent to JS rather than to React. The problem was related to passing a shallow copy to of a deep object to a function. I still do not understand what exactly was going on: in the end, two strangely fused objects were being pushed by into an array even though I was pushing only one object.
The problem was passing a shallow copy of a deep nested object to a function and back. The problem was resolved by passing a Lodash deep clone of that object:
...
const result = addCardToHand(tPlayerState.drawDeck[0], cloneDeep(tPlayerState));
...
I would still like to understand what was happening, and why the two objects, both dealt with separately in a loop, were being merged into one.
EDIT: so it seems that console.log does not always show the proper state of an object. I used "debugger" to pause the run and check for the real state of the concerned objects, which cleared all the confusion. So the problem itself was caused by a shallow copy, which was remedied by using cloneDeep from Lodash. The correct state can be checked by using the debugger;.

Javascript reverse array of numbers and subtract 2, then 1, then 0 then add 1, add 2 etc

Sorry for the awful title. I've crashed enough browsers and asking for help.
Here's the specific problem I'm trying to solve.
Create a function called 'reversedLooper' that when passed an array will loop through it backwards and subtract 2 from the last element, 1 from the second to last, 0 from to the third to last, add one to the fourth to last, add 2 to the fifth to last, etc. until it reaches the front of the array. Return the list when you are done
It's easy with [].map:
myArray.map(function(item, index, arr) {
return item + arr.length - index - 3;
});
Here is a shorter, more concise version.
function reversedLooper(arr){
var increaseBy = -2;
for(var i = arr.length - 1; i >= 0; i--){
arr[i] += increaseBy;
increaseBy++
}
return arr;
}
It's real ugly, but appears to satisfy the test cases.
var array = [1,2,3,4,5,6,7,8,9,10,11,12,13];
function reversedLooper(array) {
var newArray = [];
var n = -3;
for (var i = array.length - 1; i >= 0; i--) {
n++;
if (array[i] === array.length) {
newArray.push(array[i] - 2);
}
else if (array[i] === array.length - 1) {
newArray.push(array[i] - 1);
}
else if (array[i] === array.length - 2) {
newArray.push(array[i]);
}
else {
newArray.push(array[i] + n)
}
}
return newArray;
}
console.log(reversedLooper(array));
Building on my comment, I will use the new fiddle plug in to make something to show you here.
let list = Immutable.List.of(1,2,3,4,5)
function createListOperationsMapping(list) {
// Maybe consider dynamically creating a mapping of methods to indexes
// If you return a Map from this that is something like:
/*
Map({
0: (item) => item - 2,
1: (item) => item - 1,
// since there's a case where you subtract 0, so no change
2: (item) => item,
3: (item) => item + 1,
4: (item) => item + 2,
5: (item) => item + 3,
// etc...
})
*/
// This would allow you to map the reversedList and based on the index you could just
// call the method from the map...
// Like this (where the map from above ^^ is called listOperationMap)
/*
var mutatedReversedList = reversedList.map((item, index) => {
return listOperationMap[index](item);
})
Notice I used the word "mutated" here. If you use Immutable,
you're actually returning a copy with updates rather than mutating,
but I wanted to make it clear that the result of mapping the
Immutable List will be a new Immutable List - not the mutated
previous list. Also, if you choose to work with Immutable, remember
you will need to set new variables for return values of updates to
the Immutable data structures.
*/
}
let reversedList = list.reverse()
let reversedListSize = reversedList.size
let newList = reversedList.map((listItem, index) => {
// Do stuff in here
})
console.log(list.toJS())
console.log(reversedList.toJS())
console.log(reversedListSize)
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.6/immutable.min.js"></script>
Since your question was a bit vague, I'm basically just throwing out some ideas based on what there was to work with. Hopefully this is useful in at least starting to explore how you might approach the problem you are trying to solve.
Either way, I recommend taking a look at Immutable.js.
PS: If you click on "Run code snippet", then crack open your dev tools and the console.log(s) will show up in your console.

JSON.stringify() causing an infinite loop (Edit: NO. Bad logic is.)

My product object looks somewhat like this:
{name: 'abc', description: 'def', price: 100, quantity: 1, comment: '', customizations: []}
The customizations key is an array that has other such product objects in it. You may ignore it for this question. As you might have noticed, the comment and customizations keys are the keys that make the (theoretically) same product (practically) different when adding to cart.
I want to make a function to add such products to an array called cart_items[]. If the (practically) same product is chosen, I only want to increment the quantity inside the cart_items[i], else add a new object.
This is my function:
$scope.add_to_cart = function(product) {
// if the cart is empty, skip the brouhaha
if ($scope.cart_items.length === 0) {
$scope.cart_items.push(angular.copy(product));
} else {
for (var i = 0; i < $scope.cart_items.length; i++) {
// copy the original quantity and set it to 1 for comparison
var qty = $scope.cart_items[i].quantity;
$scope.cart_items[i].quantity = 1;
if (JSON.stringify(product) === JSON.stringify($scope.cart_items[i])) {
$scope.cart_items[i].quantity = qty + 1;
} else {
$scope.cart_items[i].quantity = qty;
$scope.cart_items.push(angular.copy(product));
}
}
}
};
The problem: First product adds successfully. Adding another causes an infinite loop. I replaced if(JSON...) with if(1 === 1) and the infinite loop didn't occur. I don't know where am I going wrong. Any help?
The problem you have is that you're increasing the size of the array in the loop and the stop condition is i being $scope.cart_items.length.
If your goal is to add the object if it's not yet present, what you want is probably this :
boolean found = false;
for (var i = 0; i < $scope.cart_items.length; i++) {
var qty = $scope.cart_items[i].quantity;
$scope.cart_items[i].quantity = 1;
if (JSON.stringify(product) === JSON.stringify($scope.cart_items[i])) {
$scope.cart_items[i].quantity = qty + 1;
found = true;
break;
}
}
if (!found) {
var item = angular.copy(product);
item.quantity = 1;
$scope.cart_items.push();
}
Note that two identical objects (i.e. objects with same property values) should not give the same JSON string because the order of property iteration isn't specified. It usually works (especially if the cloning is done the obvious way) but there's no guarantee. You really should compare based on the properties, not using JSON stringification.
You probably enter in a recursive loop, because of objects contained in customizations...
A [ customizations = B ]
B [ customizations = C ]
C [ customizations = A ]
----------------------------
Infinite loop

removing of array elements an issue

I have a situation where i add tables on a click of button and each table is stored in array. Now when i remove 2 or 3 tables, wrong index are being removed.
addTable: function (obj) {
for (var i = 0; i < obj.length; i++) {
// Adding of table
array.push(obj)
// delete code of the table
(function (i) {
deleteButton.addEventListener('click', function (e) {
array.splice(i, 1);
});
})(i);
}
}
The problem i am facing is the value of i is always zero. each time i click on the button a the addTable function is called and the counter is always zero and that is passed to the function(i) too.
Any ideas on how can keep track of different i or counter so that it deletes the correct index in the array
Here is an update
this is the sample object i am sending each time.
Each time i click on the Add Table button, the same object is being passed. Now i am having difficulty in keeping track of the index of each item.
Once you've removed one table, all other tables have moved and their indexes that you installed in the delete Buttons will be wrong now. When you remove items from the array, all indexes shift.
So, suppose you remove table 3. Then, you press delete for table 4. It's got an index of 4, but since you already removed table 3, it's in spot 3 in the array now (after the previous delete), not spot 4. But, you're code still has i==4 associated with that table and is trying to delete it here, but it's not there any more.
What you are doing is just not a good way to do this. If you want to expand further on what you're really trying to do, we can help with much better solutions.
Given the limited info we have so far, all I know of to do is to find the item in the array (wherever it might have moved to) and delete it from there.
addTable: function (obj) {
for (var i = 0; i < obj.length; i++) {
// Adding of table
array.push(obj)
// delete code of the table
(function (item) {
deleteButton.addEventListener('click', function (e) {
// search through the array to find where this item is
// and remove it from the array
for (var j = 0; j < array.length; j++) {
if (array[j] === item) {
array.splice(j, 1); // remove it
break;
}
}
});
})(obj);
}
}
I do not know about deleteButton, but in case that obj is array with only one element (length equals 1): [{....}] and array.push is native Array.prototype.push method then:
addTable: function (obj) {
// Adding of table
var index=array.push(obj);
// delete code of the table
deleteButton.addEventListener('click', function (e) { array.splice(index, 1); });
}
if obj.length is undefined i will allways be 0
further more, then i < obj.length return false and the for loop will never execute
if obj passed in is this object:
var addObjectResponse = [{...}];
then addObjectResponse is an array of 1, hence i will allways be 0
i = 0
obj.length = 1
i < obj.length => 0 < 1 => true once

Categories

Resources