Cannot access a key value pair of a changed object - javascript

Please excuse my code
From an external source , I am given the following external data which I name loxAP3
to which I am trying to firstly retrieve svg data related to the rooms.image property and then change the incoming svg data to work with react, using the following code.
createRoomData(loxAPP3, socket) {
console.log(loxAPP3)
let rooms = []
let rawRooms = loxAPP3.rooms
for (const rawRoom in rawRooms) {
rooms.push(rawRooms[rawRoom])
}
//add svg property with blank property value
rooms.forEach((room) => {
room.svg = ''
})
//fetch image data for each room in loxApp3.rooms
rooms.forEach((room) => {
const image = room.image
socket
.send(image)
.then(function(respons) {
//console.log("Successfully fetched svg image " + respons ); // success
room.svg = respons
//console.log(room.svg) // success console returns room.svg data
},
function(err) {
console.error(err);
}
);
})
this.setState({
rooms: rooms
}, () => {
console.log(rooms) // success rooms[0].svg is shown as having been populated
this.adjustSvGImageToReact()
})
}
console.log(rooms) // success rooms[0].svg is shown as having been populated
However the problem comes when I try and manipulate the room object, if I log a property that already existed from the original data, there is no problem, however if I try an fetch the .svg property it comes back not as undefined but as the empty string I first set it to be.
adjustSvGImageToReact() {
this.state.rooms.forEach((room)=>{
console.log(room.name) // success
console.log(room.uuid) // success
console.log(room.svg) //empty
})
}

Create an array of the socket.send() promises instead of calling them inside forEach
Then you can use Promise.all() to set the state and call adjustSvGImageToReact() after the socket requests have completed
const svgPromises = rooms.map((room) => {
const image = room.image
return socket
.send(image)
.then((respons)=> room.svg = respons)
})
Promise.all(svgPromises).then(() => {
this.setState({rooms: rooms}, () => {
console.log(rooms) // success rooms[0].svg is shown as having been populated
this.adjustSvGImageToReact()
});
}).catch(err=>console.log('One of the socket requests failed'))

Related

Filter Array of objects (API response) based on flag in database

I am receiving a large array of objects using the below method:
const GetList = async () => {
const [data, error] = await GetList();
console.log(response);
This gives me back an array of 1000 elements, there is an isActive flag on every element and I need to filter out the elements that are not active.
I am not able to use
var resultFiltered = response.filter(obj =>{
return obj.isActive === 'true'
});
As it gives me an error message
The entire array is stored in the data variable, how can I filter out all elements that are not active?
I'm not sure why you are using response variable, since the value is fetched variable data, try filtering as shown below
const GetList = async () => {
const data = await GetList();
const resultFiltered = data.filter(obj => Boolean(obj.isActive) === true);
console.log(resultFiltered);
}
According to the error, the response variable is not an array-type variable please check that out. If it's an object then convert it into an array and then apply the filter function.
const resultFiltered = Object.values(response).filter(obj => obj.isActive === true);
Test the bellow code:
response.data.filter()

Electron webContents.send does not always work

I use the following to send some data to another window;
try{
win.webContents.once('dom-ready', () => win.webContents.send('send-data', data));
}
catch(err){
console.log("Caught ",err);
}
And for receivig;
ipcRenderer.on('send-data', function (event,data) {
console.log("Loaded ", data);
});
The thing is, the "data" here is sometimes assembled very quickly and it works fine. However, sometimes it takes a while and the other window is already loaded at this point. No data is received in that case, and no error message either. But then I can simply use the following to send it without problems;
win.webContents.send('send-data', data)
I couldn't find a way to apply for both cases. Any suggestions?
The short answer is no.
Electron doesn't have a function to wait for the window to load, then send a message, or send a message right away if the window's already loaded.
However this can be done with some simple code:
var hasWindowLoaded = false;
var hasDataBeenSent = false;
var data = {};
win.webContents.once('dom-ready', () => {
hasWindowLoaded = true;
if (!hasDataBeenSent && data) {
win.webContents.send('send-data', data);
hasDataBeenSent = true;
}
});
// Now add this where you build the `data` variable.
function loadData () {
data = {'sampleData': 'xyz'};
if (!hasDataBeenSent && hasWindowLoaded) {
win.webContents.send('send-data', data);
hasDataBeenSent = true;
}
}
Once the data's loaded in loadData it'll check if the window's finished loading and if it has then it sends the data right away.
Otherwise it stores the data in a varible (data) and once the window loads it sends it to the window.
Another approach that you may want to consider is sending data to the browserWindow using query strings.
const data = { hello: "world" }; // sample data
// send it using query strings
browserWindow.loadFile(YOUR_HTML_FILE_PATH, {
query: { data: JSON.stringify(data) },
});
// parse this data in the browserWindow
const querystring = require("querystring");
const query = querystring.parse(global.location.search);
const data = JSON.parse(query["?data"]);
console.log(data); // { hello: "world" }

How to synchronise my code execution in angular

I'm performing multiple task and each task is dependent on previous task execution. So in my example what I want is after getting all the Id, i should get their respective blob value and then finish the execution by storing it in a variable. I'm very new to javascript and angular, please help me out. Here's what I'm trying
//this method will get the response from the rest api
async getIDFromAssets(){
this.blobDataArray=[];
this.service.getAssetsData().subscribe(async (res: JSON) => {
//after getting the response I'm filtering through it to get sepcific Id using this.getFileId() method
this.getFileId(res).then((data)=>{
console.log("blob "+data)
})
})
}
//below method will get one Id at a time and will call another method to get it's blob value
async getFileId(res){
this.fileId = [];
Object.keys(res).forEach(keys => {
if (keys == 'emb') {
let responseValue = res[keys];
Object.keys(responseValue).forEach(async (keys1) => {
if (keys1 === 'file') {
let responseArray = responseValue[keys1];
for (let file of responseArray) {
let temp: string = file.metadata.contentType;
if (temp.startsWith('image')) {
//Here I'm getting id value 'file._id' and using that I'm calling another method 'getBlobData()' to get its blob value
let data=await this.getBlobData(file._id);
this.blobDataArray.push(data);
}
}
return this.blobDataArray
}
});
}
});
}
// method to get the blob value
async getBlobData(fileId){
this.articleDetailService.getBlobDataFromAssets(fileId).subscribe(async (res)=>{
let imageObj={
'id':fileId,
'blob':res
}
return imageObj;
})
}
You need to use RxJs to avoid the nested subscription to chain your calls, possible methods to use are mergeMap and filter
Please take a look at this answer here.

How do I destructure this deep nested object?

I have this function below:
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
clearNotice();
};
the data parameter is an API from https://randomuser.me/api/
The assignment has the instructions below:
Locate the displayUserPhotoAndName function and do the follwing within it:
After the first if(!data) return; statement that terminates the
function if the expected data parameter is not provided, create a
statement that de-structures the data parameter and obtains the
results property from it;
Create a second statement in the next line that de-structures the
results variable you just created, and obtain the first item from it
(it is an Array! See https://randomuser.me/api/). Your de-structured
array item should be declared as profile. This represents the profile
data for the user gotten from the API call that you want to display
in your app.
Step 3
Still within the displayUserPhotoAndName function :
Set the HEADING element in your app to display the title, last name,
and first name (in that order, separated by a single space) of the
user profile returned by the API.
Set the IMG in your app to display the large photo of the user
profile returned by the API.
what I have done:
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
const {results} = data.results;
const [profile] = results;
const {title, First, Last} = results;
const [,,,,,,,,,picture] = results;
const largeImage = picture.large;
userImage.src = largeImage;
headerUserInfo.innerText = title + ' ' + First + ' ' + Last;
clearNotice();
displayExtraUserInfo(profile);
};
The error I get:
You have not de-structured the 'results' property from the 'data'
parameter passed to 'displayUserPhotoAndName' function
I'm in dire need of assistance. Thanks in anticipation
I'm not going to provide you the full answer but giving you the hints:
const { results } = data
const { profile } = results
console.log(profile)
Can be written as:
const { results: { profile } } = data
console.log(profile)
Here are my some posts from which you may go further:
destructure an objects properties
how is this type annotation working
why source target when destructuring

Calling then function after fetching data from firebase in ionic 3

I want fetch data from firebase after that I want to execute another function. Second function have to wait until first one is complete .
this.oAngularFireDatabase.database.ref('Users').orderByKey()
.on('value', snapshot => {
if (snapshot.hasChildren()) {
snapshot.forEach(innerSnap => {
if (innerSnap.hasChild(user.uid)) {
//User role key
this.loggedInUserUserRoleKey = innerSnap.key;
//User id
this.loggedInUserId = user.uid;
//User name
this.loggedInUserName = innerSnap.child(user.uid).child("user_name").val();
if (innerSnap.child(user.uid).hasChild("user_image")) {
//User Image
this.loggedInUserImage = innerSnap.child(user.uid).child("user_image").val();
}
return false;
}
})
}
})
I can't call then function after on it gives me an error.
In my above code, I want call another function after all data are fetch from firebase.
The Firebase on() method can fire multiple times: once when it initially loads the data, and again whenever the data changes. Since a promise (the thing you call then() on) can only resolve once, on() can't return a promise.
There are two options here:
You want to only load the data once.
If this is the case, you should use Firebase's once() method, which does return a promise.
this.oAngularFireDatabase.database.ref('Users').orderByKey()
.once('value').then(snapshot => {
if (snapshot.hasChildren()) {
snapshot.forEach(innerSnap => {
if (innerSnap.hasChild(user.uid)) {
//User role key
this.loggedInUserUserRoleKey = innerSnap.key;
//User id
this.loggedInUserId = user.uid;
//User name
this.loggedInUserName = innerSnap.child(user.uid).child("user_name").val();
if (innerSnap.child(user.uid).hasChild("user_image")) {
//User Image
this.loggedInUserImage = innerSnap.child(user.uid).child("user_image").val();
}
return false;
}
})
}
}).then(value => {
// TODO: perform subsequent action on boolean value
})
You want to listen for changes on the data too.
If this is the case, you should put the subsequent action you want to take into the on() callback:
this.oAngularFireDatabase.database.ref('Users').orderByKey()
.on('value', snapshot => {
if (snapshot.hasChildren()) {
snapshot.forEach(innerSnap => {
if (innerSnap.hasChild(user.uid)) {
//User role key
this.loggedInUserUserRoleKey = innerSnap.key;
//User id
this.loggedInUserId = user.uid;
//User name
this.loggedInUserName = innerSnap.child(user.uid).child("user_name").val();
if (innerSnap.child(user.uid).hasChild("user_image")) {
//User Image
this.loggedInUserImage = innerSnap.child(user.uid).child("user_image").val();
}
}
})
// TODO: perform subsequent action on data
}
})
Note that both of these operations look pretty expensive for what they're trying to accomplish: scanning a JSON tree for a specific value is an anti-pattern in Firebase, and typically means you should modify/augment your JSON to allow a direct lookup or query.
For example, I suspect you now have a structure like /Users/$randomkey/$uid: { ..user data... }. For better performance, consider storing the user data directly under their UID: /Users/$uid: { ..user data... }. This removes the need for a query, and allows you to directly load the data for a user from this.oAngularFireDatabase.database.ref('Users').child(user.uid).

Categories