forEach objects value equals undefined - javascript

Data Received from firebase-realtime-database as following
{
"0": {
"id": 10250903,
...
},
"1": {
"id": 10810490,
...
},
...
}
Code to setProducts
const [products, setProducts] = useState();
const {isLoading, setIsLoading} = useData();
useEffect(async () => {
setIsLoading(true);
await firebase
.database()
.ref('events')
.once('value')
.then((events) => {
setProducts(events);
})
.finally(() => setIsLoading(false));
}, []);
I tried to iterate the object to get the values
products?.forEach((product) => {
console.log(product);
});
Result:
Object {
"id": 10250903,
...
}
Object {
"id": 10810490,
...
}
But when I try to access id values, console prints undefined
products?.forEach((product) => {
console.log(product.id); // undefined
});
undefined
undefined
I am stuck I tried everything.
Object.values(products) will not work since product will be undefined until data is received.
Creating a new Array and mapping into it also will not work.

You stated that:
Object.values(products) will not work since product will be undefined until data is received.
I think you are very close to the solution.
Using products || {} handles the case where products are undefined or null.
var products = {
"0": {
"id": 10250903,
},
"1": {
"id": 10810490,
},
}
Object.values(products || {}).forEach(p => console.log(p.id))
If you are transforming products into a new products collection, reduce may become useful:
Object.values(products || {}).reduce((acc, p) => {
acc[p.id] = p;
return acc;
}, {})
=>
{
"10250903": {
"id": 10250903,
...
},
"10810490": {
"id": 10810490,
...
}
}
Or:
Object.values(products || {}).reduce((acc, p) => {
acc.push(p.id)
return acc;
}, [])
=>
[10250903, 10810490]

Related

How to Receive cypress interception fixture twice but in different format?

I'm a beginner with Cypress and I am stuggeling with the following:
I am calling the following from my test file:
cy.SetupClassificationsStubFixture(1);
This refers to the following command:
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
}).as('classifications')
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications/*', slicedClassifications)
}).as('classifications') });
As you can see this customcommand is intercepting 2 api request. Namely:
** /api/classifications
** /api/classifications/ *
The first interception is with []
The second intercecption needs exactly the same response buth without brackets []
But you already understand that both respons are now with brackets '[]'. I tried to make a second fixture file without [], but the the slice function is not working.
So I need:
The second intercept like:
{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}
But I get:
[{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}]
How could I get this array back without []? Thankyou indeed!
UPDATE:
I am trying now the following:
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
}).as('classifications')
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
const arr2 = slicedClassifications
const obj5 = Object.fromEntries(arr2)
cy.intercept('GET', '**/api/classifications/*', obj5)
}).as('classification')});
But this give me a emtpy .json file. It the respons is not just ' {} '
There looks to be some brackets out of place in the code.
I would also recommend using different alias names, otherwise the calls to cy.wait('#classifications') may not work as you expect.
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
.as('classifications')
const firstClassification = slicedClassifications[0] // just first item
cy.intercept('GET', '**/api/classifications/*', firstClassification)
.as('firstClassification')
})
});
So in case, your data looks like this:
var data = [{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}]
So to extract the data with just curly braces you can do data[0].
{
"id": "9d4a9c14-ef37-4a64-a1eb-63ab45cdf530",
"name": "CypressTest",
"userRole": "Editor",
"childClassifications": []
}
Working example console screenshot:
Finally solved with:
Cypress.Commands.add("SetupClassificationsStubFixture", (amount) => {
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
const slicedClassifications = classificationsStub.slice(0, amount)
cy.intercept('GET', '**/api/classifications', slicedClassifications)
}).as('classifications')
cy.fixture('ClassificationsStub.json').then(classificationsStub => {
cy.intercept('GET', '**/api/classifications/*', (req) => {
const slicedClassifications = classificationsStub.slice(0, amount)
var selectedClassification = req.url.replace(new RegExp('.*api/classifications/'), '');
let foundClassification = FindChildClassification(selectedClassification, slicedClassifications);
//If not found return first always
req.reply({
statusCode: 200,
body: foundClassification ?? slicedClassifications[0]
})
})
}).as('classification')
And
export function FindChildClassification(id, classificationArray) {
for (let i = 0; classificationArray.length - 1 >= i; i++) {
if (classificationArray[i].id == id) {
return classificationArray[i];
} else {
if (classificationArray[i].childClassifications.length > 0) {
let childClassification = FindChildClassification(id, classificationArray[i].childClassifications);
if (childClassification != null) { return childClassification }
}
}
}
return null;
}

How can I retrieve elements and properties from the given JSON

How can I access each of the properties in the given JSON?
I would also like to filter the particular objects based on their IDs. How to do that using array.filter method in javascript?
{
"records": [
{
"id": "abcd",
"fields": {
"term": [
"xyz"
],
"groupId": 888,
"url": "https://www.facebook.com",
"url_c": [
"https://www.google.com"
],
"pID": [
"1800"
],
"location": [
"mumbai"
],
"url_location": [
"https://www.mumbai.com/"
]
},
"createdTime": "2021-05-12T10:18:33.000Z"
}
]
}
Currently I'm trying to do this:
const [info, setInfo] = useState({});
useEffect(() => {
fetch(
"https://apiurl//"
)
.then((res) => res.json())
.then((data) => {
setInfo(data.records);
console.log(data);
})
.catch((error) => {
console.log(error);
});
}, []);
let resultInfo = info.filter((x) => x.groupId == gid);
console.log(resultInfo[0].fields.groupId);
But it shows error
You're initializing your info as an empty object. So your code is trying to run filter on an object which will return an error. Also in your filter check is wrong based on the json example you shared
You should change
const [info, setInfo] = useState({});
let resultInfo = info.filter((x) => x.groupId == gid);
to
const [info, setInfo] = useState([]);
let resultInfo = info.filter((x) => x.fields.groupId == gid);
Since it's asynchronous either define things in .then() method or you can simply use asyn await to let things work for you.
Something like
const [info, setInfo] = useState([]);
useEffect(() => {
fetch(
"https://apiurl//"
)
.then((res) => res.json())
.then((data) => {
if(data && data.records){
console.log(data);
const records = data.records.filter((x) => x.fields.groupId == gid);
setInfo(records);
// if you will log info here most probably it might log default value so check in your render method for the latest value
}
})
.catch((error) => {
console.log(error);
});
}, []);
Make sure gid is same as your groupId. For surity you can just pass static number just to test.
Now try to access info in your render method like:
return
<div>
{JSON.stringify(info)}
</div>

Removing an object from an array by a property

I'm writing an endpoint to delete a record from a dummy database. The dummy database right now is written as an array of objects (it will then be changed to a class, then an actual database).
I have a dbHelpers.js file:
module.exports = {
createId(data) {
// ...
},
findById(data, recordId) {
// ...
},
deleteById(data, recordId) {
data.splice(data.findIndex(item => item.id === recordId), 1)
return data;
}
};
And i'm calling it in controllers/envelope.js
exports.deleteEnvelope = async (req, res) => {
try {
const { id } = req.params;
const envelopes = await dbEnvelopes;
const envelope = findById(envelopes, id);
if (!envelope) {
return res.status(404).send({
message: 'Envelope Not Found',
});
}
const updatedEnvelopes = deleteById(envelopes, id);
return res.status(200).send(updatedEnvelopes);
} catch (err) {
res.status(500).send(err)
}
};
However, for some reason, my findIndex function is not working and it's always returning -1. What is wrong with the function?
Below is the dummy db in config/db.js:
const envelopes = [
{
"id": 1,
"title": "Rent",
"budget": 1000
},
{
id: 2,
"title": "Groceries",
"budget": 300
},
{
id: 3,
"title": "Entertainment",
"budget": 400
}
]
module.exports = envelopes;
I think you can use array.filter to remove the object in array by matching the id.
deleteById(data, recordId) {
return data.filter(item => item.id !== recordId)
}

Pre and post hooks for factory - scope issue

I'm attempting to build a simple factory that will pass "props" to modifiers registered to the parent.
However, in the code below, the props object is undefined by the time posthooks() gets called.
const factory = function({ collection = [], modifiers = [] }) {
let props = { collection, timesRan: 0 };
const registerRun = () => {
props.timesRan = props.timesRan + 1;
}
const prehooks = function() {
modifiers.forEach((modifier) => {
modifier.prehook(props);
registerRun();
});
};
const posthooks = function(props) {
modifiers.forEach((modifier) => {
modifier.posthook(props);
registerRun();
});
};
prehooks();
posthooks();
return props;
};
// test case
const collection = [
{
"name": "Jimmy",
"id": 1
},
{
"name": "Johnny",
"id": 2
},
]
// modifier
const modifier = {
prehook: (props) => {
if (props && props.collection) {
console.log('pre hook ran');
props.collection = props.collection.map(item => Object.assign({}, { points: 100 }, item));
}
return props;
},
posthook: (props) => {
if (props && props.collection) {
console.log('post hook ran');
props.collection = props.collection.map(item => Object.assign({}, { id: String(item.id) }, item));
}
return props;
}
}
// test the factory
const modifiers = [ modifier ];
const returnValue = factory({ collection, modifiers } );
console.log('returnValue', returnValue);

Getting null in values from Promise.all

I am using promises. This is in continuation to my question here
The issue I am having is that in response, i.e. an array of objects is having null values. I will try to explain this
First I get the userId
Get user whishlist products from the userId
Then using userId I get stores/shop list
Then I iterate over store list and call another API to check if this store is user favourite store.
Then I get the products of each store and append in an object and return.
function getStoresList(context) {
const userID = common.getUserID(context)
let userWishListProd = []
return userID
.then(uid => Wishlist.getUserWishlistProducts(uid).then((products) => {
userWishListProd = products.data.map(product => +product.id)
return uid
}))
.then(uid => api.getOfficialStoresList(uid).then((response) => {
if (!response.data) {
const raw = JSON.stringify(response)
return []
}
const shops = response.data
return Promise.all(
shops.map((shop) => {
const id = shop.shop_id
const shopobj = {
id,
name: shop.shop_name,
}
return favAPI.checkFavourite(uid, id)
.then((favData) => {
shopobj.is_fave_shop = favData
// Fetch the products of shop
return getProductList(id, uid)
.then((responsedata) => {
shopobj.products = responsedata.data.products.map(product => ({
id: product.id,
name: product.name,
is_wishlist: userWishListProd.indexOf(product.id) > -1,
}))
return shopobj
})
.catch(() => {})
})
.catch(err => console.error(err))
}))
.then(responses => responses)
.catch(err => console.log(err))
})
.catch(() => {}))
.catch()
}
The response I get is
[{
"id": 1001,
"name": "Gaurdian Store",
"is_fave_shop": "0",
"products": [{
"id": 14285912,
"name": "Sofra Cream",
"is_wishlist": false
}]
},
null,
null,
{
"id": 1002,
"name": "decolite",
"is_fave_shop": "1",
"products": [{
"id": 14285912,
"name": "Denca SPF",
"is_wishlist": false
}]
}
]
The actual store are coming as 4 but instead of it null gets appended. What is wrong I am doing with Promises here.
This appears to have to do with your .catch(() => {}) and .catch(err => console.error(err)) invocations. If one promise in your loop has an error, it will be transformed to an undefined value (optionally being reported before), so that Promise.all will fulfill with an array that might contain undefined values. If you JSON.stringify that, you'll get null at those indices.
Drop the .catch(() => {}) statements that do nothing (or replace them with logging ones), and check your error logs.
Have you debug your code?
I would debug on Chrome and add some break points on the code to see what the actual response is.

Categories

Resources