arr.findIndex() returns -1 - arrays

I'm afraid it should be obvious since my affair is based on normal Vanille JS. Anyhow, for any reason I cannot get my issue fixed. Anyhone who can help me out?
Snapshot of my code in reducer:
> case TOGGLE_PRODUCT:
> const newProducts = [...state.allProducts];
> console.log("All products: ", newProducts);
> console.log("Passed product: ", action.productId);
> console.log("Should have found: ", newProducts[1]);
> const toggledProduct = newProducts.findIndex(
> (el) => el.id === action.productId
> );
> console.log("Found: ", toggledProduct);
Output in console:
All products: Array [
Product {
"amount": 0,
"department": "Molkereiprodukte",
"id": "id1",
"product": "Milch 3,5%",
"status": false,
},
Product {
"amount": 0,
"department": "Molkereiprodukte",
"id": "id2",
"product": "Yoghurt",
"status": false,
},
Product {
"amount": 0,
"department": "Ceralien",
"id": "id3",
"product": "Müsli",
"status": false,
},
]
Passed product: Object {
"id": "id2",
}
Should have found: Product {
"amount": 0,
"department": "Molkereiprodukte",
"id": "id2",
"product": "Yoghurt",
"status": false,
}
Found: -1
Why does the find() method not return a result???
Thx in Advance!

your action.productId is an objectnot a string
const toggledProduct = newProducts.findIndex(
(el) => el.id === action.productId.id /** <--here */
);

findIndex is used to find desire index of the element you need Array.find to get element data. Reason you are getting -1 is because action.productId is an object. You need to compare action.productId.id
const toggledProduct = newProducts.find(el => el.id === action.productId.id );

Related

Update object value in array within array React

I am trying to update my product attributes and i came to a solution only for one attribute.
this is my carrtItems state
this.state = {
cartItems: [],
selectedAttributes: []
Json Object
{
"__typename": "Product",
"name": "iPhone 12 Pro",
"inStock": true,
"attributes": [
{
"__typename": "AttributeSet",
"id": "Capacity",
"name": "Capacity",
"type": "text",
"items": [
{
"__typename": "Attribute",
"id": "512G",
"value": "512G"
},
{
"__typename": "Attribute",
"id": "1T",
"value": "1T"
}
]
},
{
"__typename": "AttributeSet",
"id": "Color",
"items": [
{
"__typename": "Attribute",
"id": "Black",
"value": "#000000"
},
{
"__typename": "Attribute",
"id": "White",
"value": "#FFFFFF"
}
]
}
],
"id": "product1",
"quantity": 1,
"selectedAttributes": [
{
"value": "512G",
"type": "Capacity",
"id": "product1"
},
{
"value": "#44FF03",
"type": "Color",
"id": "product1"
}
]
}
This is my update function:
updateCartItem = (cart, product, selectedAttribute, newAttributes) => {
const existingCartItem = cart.find(
(cartItem) => cartItem.id === product.id
);
const thisCart = cart.filter((cartItem) => cartItem.id !== product.id)
if (existingCartItem) {
cart.map((cartItem) =>
cartItem.selectedAttributes.map((attr)=> attr.type===selectedAttribute.map((newAttr)=>newAttr.type
? newAttributes= [{
...attr,
value: newAttr.value,
}]
: [newAttributes = attr]
)));
return [
...thisCart,
{ ...product, selectedAttributes: newAttributes },
];
}
};
This is update state function
updateItemToCart = (product, selectedAttributes) => {
this.setState({
cartItems: this.updateCartItem(this.state.cartItems, product, selectedAttributes),
});
};
This my is my selected attributes functions
selectAttribute = (attribute, newAttribute, type, id) => {
const existingAttribute = attribute.find(
(attr) => attr.type === type && attr.id === id
);
if (existingAttribute) {
return attribute.map((attr) =>
attr.type === type && attr.id === id
? { ...attr, value: newAttribute }
: attr
);
}
return [...attribute, { value: newAttribute, type, id }];
};
selectedAttributesHandler = (newAttribute, type, id) => {
this.setState({
selectedAttributes: this.selectAttribute(
this.state.selectedAttributes,
newAttribute,
type,
id
),
});
};
What i want here is to update selectedAttributes if color or size changes but to remain the other attribute.
Example:
Color: white, Size: M
Here i change the size to L on click
Result:
Color: white, Size:L
How to update updateCartItem function to achieve this result.
You can use the spread operator
It allows you to easily populate an object or array with a shallow copy of the contect of another object or array.
The syntax is three dots followed by the name of the object or array that we want to copy.
Example:
this.setState({
...this.state,
selectedAttributes: this.selectAttribute(
this.state.selectedAttributes,
newAttribute,
type,
id
),
});
There are other ways of achieving this, but this is the likely the simplest way and is a common pattern when working with state in React.

I can't use filter when I have objects inside an array and find last id, angular

I need your opinion in this situation:
I get from API with this function:
getRS(
idProject: string
): Observable<ResponseModel<RSModel>> {
return this.http.get<ResponseModel<RSModel>>(
ApiUrlsConfig.getRS(
idProject
)
);
}
this response:
{
"data": [
{
"id": "id1",
"state": 1,
"note": null
},
{
"id": "id1",
"state": 2,
"note": "Reason 1"
},
{
"id": "id2",
"state": 2,
"note": "Reason updated3",
}
],
"result": null
}
I need to use filter in this response because I should be get the last state for each id. For example, I want to display state 2 in item with id: id1. For this I want to use filter. The problem is because I can't use filter on it, I don't understand why.
I tried to write this code:
#Input() set jobId(jobId: string) {
this.optionsService
.getRS(
this.idProject
)
.pipe()
.subscribe((res) => {
let resId = res.filter((aaa)=>{
if(aaa.id === jobId){
res.slice(-1)[0].id
}
}
)
});
}
Not function.
Please can you share with me any idea?
Thank you
Try this logic:
Loop backwards throw it.
Loop backwards over index to the start.
Splice duplicates.
let response = {
"data": [
{
"id": "id1",
"state": 1,
"note": null
},
{
"id": "id1",
"state": 2,
"note": "Reason 1"
},
{
"id": "id2",
"state": 2,
"note": "Reason updated3"
}
],
"result": null
}
let data = response.data;
for (let i = data.length - 1; i >= 0; i--) {
for (let j = i - 1; j >= 0; j--) {
if (data[i].id === data[j].id) {
data.splice(j, 1);
j++;
}
}
};
console.log(data);
try this:
if(aaa.id == jobId){
return res.slice(-1)[0].id
}

add to array if not already available Typescript

I have a two arrays:
Users [
{ "id": 0, "name": "Scott" },
{ "id": 0, "name": "Jan" },
{ "id": 0, "name": "Jack" },
]
Users2Add [
{ "id": 0, "name": "Scott" },
{ "id": 0, "name": "Andy" },
{ "id": 0, "name": "John" },
]
I want to check if new users in Users2Add are already in Users array. If yes don't push(add to array) else add the new User(From User2Add) to Users array. Like:
forEach(var u in Users2Add ) {
if(!(Users.containts(x => x.id == User2Add.idx))) Users.push(u);
}
The problem is that there's no straightforward way to check object equality in JS, and of course:
{a: 1} === {a: 1} //false
A possible solution is to use lodash:
Users2Add.forEach(user => {
if (!Users.some(existingUser = > _.isEqual(existingUser, user))) {
Users.push(user);
}
});

Mongoose-MongoDb : doc.pull inconsistent when multiple pull

node v7.7.1
mongodb: 2.2.33,
mongoose: 4.13.7
Hello all,
i'm having this unexpected behaviour when trying to update a document with multiple pull request based on matching criterias. here is what i mean
my document schma looks like this
{
"_id": "5a1c0c37d1c8b6323860dfd0",
"ID": "1511781786844",
"main": {
"_id": "5a3c37bfc065e86a5c593967",
"plan": [
{
"field1": 1,
"field2": 1,
"_id": "5a3c30dfa479bb4b5887e56e",
"child": []
},
{
"field1": 1,
"field2": 2,
"_id": "5a3c30e1a479bb4b5887e5c",
"child": []
},
{
"field1": 1,
"field2": 3,
"_id": "5a3c37bfc065e86a5c593968",
"child": []
},
{
"field1": 1,
"field2": 4,
"_id": "5a3c37bfc065e86a5c593655",
"child": []
},
{
"field1": 1,
"field2": 5,
"_id": "5a3c30dfa479bb4b5887e56f",
"child": []
},
{
"field1": 1,
"field2": 6,
"_id": "5a3c30e1a479bb4b6887e545",
"child": []
},
{
"field1": 1,
"field2": 7,
"_id": "5a3c37bfc065e86a5c5939658",
"child": []
},
{
"field1": 2,
"field2": 2,
"_id": "5a3c37bfc065e86a5c593963",
"child": []
},
]
},
...
....
}
and this is my code to update the document:
Schema.findOne({ID: data.ID})
.then(function(doc) {
var array = doc.main.plan;
for (i = 0; i < array.length; i++) {
if ( array[i].field1=== 1 )) {
var id = array[i]._id;
console.log('pulling');
doc.pull( { _id: id });
}
}
doc.save().then(function(doc) {
console.log('saving');
// console.log(doc);
if (doc && doc.docID) {
return { success: true };
} else {
return { success: false, error: 'unknownError'}
}
})
}
now the issue is let's say my array has 7 objects that matches the test (array[i].theField === parseInt(updFields.theField)), when i run this and check the logs i see that it will basically pull half of the objects and do a save.
so i would get
pulling
pulling
pulling
pulling
save.
and then i have to run the code for the remaining 3 objects in the array and get
pulling
pulling
saving
so i have to run it a third time to completely clear the array.
need help get this working
thank you
So i created a little workaround by doing a recursive function to pull all with only one click using lodash functions. not pretty but it does the job.
const delObjArray = (doc, cond) => {
const checkField = cond.field;
const checkVal = cond.value;
_.forEach(doc, (value) => {
if (value && value[checkField] === checkVal) {
doc.pull({ _id: value._id });
}
});
const isFound = _.some(doc, { [checkField]: checkVal });
if (isFound) {
delObjArray(doc, cond);
} else {
return true;
}
return true;
};

How to modify a complex JSON Object in using Immutable

I have below JSON and wanted to update the value depending on Aid, Bid and Cid using Immutable.js
e.g.
Below input provided.
Aid= A, Bid = 1, Cid= 4, NewValue = 'FOUR'
If above input is provided the value "One" needs to be changed to "FOUR"
let sampleJson = {
Aid: 'A', detail:"sample", list: [
{
"Bid": "1",
"group": [
{
"name": "Group A",
"Cid": "4",
"value": "One"
},
{
"name": "Group A",
"Cid": "41",
"value": "1"
},
]
},
{
"Bid": "2",
"group": [
{
"name": "Group A",
"Cid": "4",
"value": "1"
},
{
"name": "Group A",
"Cid": "4",
"value": "1"
},
]
};
I was able to access the value using below code. How can i return the entire JSON with updated value?
let variale = Immutable.fromJS(sampleJson).
getIn(['list']).
find(allocation => allocation.get("Bid") === "1").
getIn(['group']).
find(fun => fun.get("Cid") === "4").set('value',"FOUR");
Anyone has any suggestions on how to resolve this problem?
I think you can try to do this like so:
let immutable = Immutable.fromJS(sampleJson);
immutable = immutable.setIn(['list', 0, 'group', 0, 'value'], 'FOUR');
This monstrosity is how I would do it:
const newData = originalData.update('list', list => {
const itemIndex = list.findIndex(item => item.get('Bid') === '2');
return list.update(itemIndex, listItem => {
return listItem.update('group', groupList => {
const groupIndex = list.findIndex(group => group.get('Cid') === '4');
return groupList.update(groupIndex, group => {
return group.set('value', 'FOUR');
});
});
});
});
https://jsbin.com/latupo/7/edit?html,js,console
Personally I stopped using Immutable, I always found it a bit painful (not to mention those docs!). I now use redux and good old cloning to not mutate state. Less performant in theory but if you've got nothing that runs over a few milliseconds anyway, save yourself the trouble...

Resources