I have an Object like;
players: {
'1': {id:1, name:'', ....},
'2': {id:2, name:'', ....},
...
}
I want to desctruct an object by its key as currentPlayer. (playernumber is passed as props).
const currentPlayer = Object.keys(players).filter(
obj => obj.id === playerNumber
);
this did not work, also I do not want to use id attribute.
The easiest way to get a specific player is with bracket notation:
const currentPlayer = players[playerNumber];
This assumes that playerNumber is a valid key in the players object.
Could you not just use Object.values() to achieve this?
The Object.values() will return the values of your players object ({id:1, name:'', ....}, etc) as an array. You can then use the .filter() method to select the player value by playerNumber.
So for instance, something like this:
const currentPlayer = Object.values(players).filter(
obj => obj.id === playerNumber
);
You will find that this works in most browsers
Alternativly, if you have your players object organised so that the keys are player id's, you can access a player in this way:
const currentPlayer = players[playerNumber];
Object.keys() will give you an array of keys rather than the object stored under those keys (i.e. Object.keys(players) returns ['1', '2', ...]).
If you want to get the objects, you can map the result array like so:
// Use map to turn the array of keys into the array of objects
const currentPlayer = Object.keys(players).map(id => players[id])
// be careful: filter returns an array, but you probably just want the one object
.filter(obj => obj.id === playerNumber)[0]
Depending on what you're targeting, you may also have access to Object.values() which does the same thing (i.e. you'd replace the first line with just Object.values(players)), just be aware that browser support is a little more limited.
Related
I have an array, which is from redux-store, contains list of object. I use delete operator to delete some certain property of object in the array in a function, but return an errors "Cannot delete property 'message' of #"
Below as my codes:
const transactionSuccess = (data) => {
notifySuccess("payment success");
console.log("products", products);
for (const item of products) {
delete item.message;
delete item.sizes;
}
const userLocal = JSON.parse(localStorage.getItem("user"));
const { token } = userLocal;
const object = {
products: products,
isPaid: data.paid,
description: "paypal;",
};
postAPICart(object, token, history);
};
console.log('products', products) returns 3 objects in an array
Firstly, I really appreciate andres and phry for trying to help me with that question.
I finally reach out the key problem in my code, it's all about shadow and deep copy
const products = [{item1},{item2}] // an array contains list of object
const copiedProducts = [...products] or const copiedProducts = products.map(item => item) will return SHADOW COPPY of products. Spread operator and map dont actually create new item1 and item2 object. Therefore, if you try to delete or add new property in item1 or item2 of copiedProducts, item1 and 2 in original products also be override, then complier then return an error
I came up with this solution:
const productsCopy = JSON.parse(JSON.stringify(products)); // create a deep copy, all objects are totally separated from original one
Below is a link help me above solution:
https://www.javascripttutorial.net/object/3-ways-to-copy-objects-in-javascript/#:~:text=A%20deep%20copying%20means%20that,connected%20to%20the%20original%20variable.
Happy coding day guys
You cannot change values in your store outside of a reducer. And now you may say "hey, this is not a store value", but it most likely is just a reference to the store - and changing any of your products here would in turn also change the store.
You can do something like this:
const newProducts = products.map(({ message, sizes, ...rest }) => rest)
this will leave the original objects alone and create an array of new objects with everything except messages and size for you to work with
My issue is that when i call the function getAllFlashCardsFromQuest(), its call all flash cards ever created in all the pages, i wanna only the objects that comes from a specific pathname, or a way to filter the cards array.
async function getCards() {
let cardsValues = await getAllFlashCardsFromQuest() as FlashCard[]
let cardsFiltered = cardsValues.filter(()=>{
return history.location.pathname === 'CriarAlternativaQuest'
})
console.log(cardsFiltered)
setCards(cardsFiltered)
}
the object look like this:
There's not much context with your code, so I can only help so much, but one thing's for sure, and that is history.location.pathname isn't changing and you're comparing it with another constant. So cardsFiltered will be either a list of true or a list of false.
Whenever you're filtering a list, you need to take each item or a property of each item and use that in your comparison.
Ex.
async function getCards() {
let cardsValues = await getAllFlashCardsFromQuest() as FlashCard[]
let cardsFiltered = cardsValues.filter((cardValueItem) => {
return cardValueItem.pathname === 'CriarAlternativaQuest'
})
}
The thing is that you need to figure out what value or property inside of your cardsValues list that you need to compare it with 'CriarAlternativaQuest'
In one component I can filter my array using the following:
// Array of product objects
const result = products.filter(p => p.name.includes('val'));
and value of products remains same as the first value but filtered value stores in result.
But in the following code, filter() filters array of strings itself:
// Array of strings
const result = strs.filter(s => s.includes('val'));
The question is how can I filter strings and return result without modifying the strs itself?
Note: I tried with array.filter(function() { return res; }); but didn't make any change.
It returns the filtered ones and don't change the actual array. You are doing something wrong
const strs = ['valval', 'bal', 'gal', 'dalval'];
const result = strs.filter(s => s.includes('val'));
console.log(strs);
console.log(result);
First thing we need to know is, if we filter our list we loose our original data
products: any[] = [
{
"productId": 1,
"productName": "foo-bar",
"price": 32.99
}
]
and can't get it back without re-getting the data from it's source so we have to make another list to store the filtered list.
filteredProduce: any[];
Next if you are working to show a list of filtered product on a grid or something like this we need a way to know when the user changes the filter criteria. we could use event binding and watch for key presses or value changes, but an easier way is to change our _listFilter property into a getter and setter, like this
get listFilter: string {
return this._listFilter;
}
set listFilter(value:string) {
this._listFilter= value;
}
next we want to set our filteredProducts array to the filtered list of products like this
set listFilter(value:string) {
this._listFilter= value;
this.filteredProducts = this._listFilter? this.performFilter(this._listFilter) : this.products;
}
in preceding code we are using js conditional operator to handle the posibility that _listFilterstring is empty, null or undefined.
Next we use this.performFilter(this._listFilter) to filter our list.
performFilter(filterBy: string): any[] {
filterBy = filterBy.toLocaleLowerCase();
return this.products.filter((product: any) =>
product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}
Finally we should assign the main list of products to the filteredProducts and _listFilter to what we want.
constructor() {
this.filteredProducts = this.products;
this._listFilter= 'foo-bar';
}
last step is to change our template to bind to our filteredProducts property.
I have an Object:
Object{
"field1":"fill this field!",
"field1":"fill this field!",
"field1":"fill this field!"
}
I need to access the key and value of this Object.
How can I transform this Object in Array to use forEach.
No need to "transform" it, you can loop on the keys directly.
Object.keys(yourObject).forEach( key => {
console.log(yourObject[key]); //value
console.log(key); //key
});
You can list the object's keys and place the values in a new array.
const _versions = [];
Object.keys(versions).forEach(v => _versions.push(versions[v]));
this.versions = _versions;
I have a prop that is a list of objects. My reducer is meant to update a certain field of the object and append it to the list, the value to update is provided via action.payload (which is another prop of the store).
I know that for simply adding the object in the list I can use the spread operator like this
function myReducer(state=[],action){
case something:
return [...state,action.payload];
case default:
return state;
}
but say I have a change action.payload.aCertainField and then append this to the list of objects. When I did something like this:
action.payload.aCertainField = aCertainValue;
return [...state,action.payload];
But it actually changed the other prop's aCertainField as well. I do not want that. Is there a solution to this ?
You can do it as following, using ES6:
let { aCertainField, id } = action.payload.obj;
//find the index of object in that array hoping the id is unique for the object
let indexOfObject = state.findIndex( (item) => item.id === id );
let actualObject = Object.assign({}, state[indexOfObject], { aCertainField });
return [
...state.slice(0, indexOfObject),
actualObject,
...state.slice(indexOfObject+1)
]
NOTE: Thinks that id is the unique key for the object structure and aCertainField is the value to update