Should spread operator behave differently in asynchronous conditions? - javascript

I am trying to replace an instance of hardcoding in a web application with 2 very similar API calls, as I don't have time to rewrite a whole new procedure and endpoint to handle the same functionality right now. I am able to get the data from the 2 individual calls fine with Promise.all. But the template for this page (it is using handlebars) is expecting a single object to loop through and display the options in a drop down.
I have been trying to use spread operators to bring the contents of the results together with no duplicates, and it does work as expected if I mock it up synchronously in the console, but in practice the results get nested into another object as if it were an array.
This is the code actually running:
Promise.all([
this.isUsers = GetUsersByRole("Inside Sales", app.user.id),
this.asmUsers = GetUsersByRole("Area Sales Managers", app.user.id)
]).then((is, asm) => {
// is and asm contain the correct data here, I just want to merge it
this.users = {...is, ...asm};
var dummy = {...is, ...asm};
console.log("dummy", dummy);
});
In the console, manually copying the data from each successful data grab into its own object and then combining with the spread operator as above gives the expected result. But this code returns some sort of nesting of it instead:
If the spread operator (or using Object.attach, which I have also tried) worked as expected, I believe I would have the result I'm looking for. I don't know how many little hacks I've tried to merge the objects properly, but none seem to have the right behavior in this context.
I may just need some more reading on Promises and async operations, so feel free to link me
EDIT
Destructuring the results of the Promise with array brackets like so:
Promise.all([
this.isUsers = GetUsersByRole("Inside Sales", app.user.id),
this.asmUsers = GetUsersByRole("Area Sales Managers", app.user.id)
]).then(([is, asm]) => {
this.users = {...is, ...asm};
var dummy = {...is, ...asm};
console.log("Dummy", dummy);
});
...leaves the dummy object completely empty as far as I can tell:
empty dummy object
Trying to spread the data objects with square brackets:
var dummy = [...is, ...asm];
Results in a type error, as they as Objects:
Uncaught (in promise) TypeError: is is not iterable
EDIT
Thank you to everyone for their help, I had to convert the function I was using to make the api calls to return a Promise and then the code worked as expected

Related

Realm object list functions are undefined, even though object is defined and list is populated

Trying to push a new int into an int realm list. I can get the Realm object, I can print it and when I print the object it shows the list with it's content, I can use Realm Studio to edit, add numbers to the list, etc.. But when I try to call any methods form the list it says it is undefined.
Have tried async, await, then, though it was a synchronization issue, but doesn't seem like it.
The code below is similar to mine, but edited to hide the original names, etc, and does not have all the properties from the original, but it does not change the behave for the specific list I am trying to edit. Everything else works fine.
I have an schema like
let mySchema={
name:'MySchema',
properties:{
my_schema_id: 'string',
numbers: 'int[]'
}
The function to create a new object is
Realm.open({schema: [mySchema]})
.then(realm => {
realm.write(() => {
realm.create('MySchema', {my_schema_id: `${my_schema_id}`, numbers: [parseInt(number, 10)]});
});
I try to add a number with:
Realm.open({schema: [mySchema]})
.then((realm) => {
let fetchedSchema = realm.objects('MySchema').filtered(`my_schema_id ="${my_schema_id}"`);
console.log(fetchedSchema);
realm.write(()=>{
fetchedSchema.numbers.push(parseInt(number, 10));
});
And it gives an error:
(node:73249) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'length' of undefined
I expected to push the item to the list, or to be able to call the list functions. Instead, when I try to use the list it shows as undefined even though I can see it and it's content when I print the object...
Found a solution.
Querying let fetchedSchema = realm.objects('MySchema').filtered(my_schema_id ="${my_schema_id}"); actually returns an array of elements, so I just had to select the first with [0]at the end

Loop through nested dataLayer array to return pipe delimited strings

We have a nested dataLayer variable on our booking platform. Users can make one or multiple variables are we want to pull out a string containing each of the product types contained within the array. I am hitting a error when debugging this however.
The location of the variable I would like to collect is:
dataLayer.booking.products[i].travelType
try{
var productList = {};
for(i=0;i<dataLayer.booking.products.length;i++){
productList[dataLayer.booking.products[i].travelType];
}
return productList.join('|');
}
catch(err){}
I am naive with JS so I apologies for a basic question.
M
Your code shows that you're setting a new property of the object productList, but you're not defining a value, e.g. {foo: } instead of {foo: "bar"}. It looks like what you want is an array that you can add strings to. For example:
var productList = dataLayer.booking.products.map(function(product) {
return product.travelType;
});
return productList.join('|');
Note that this is using the Array's map method as opposed to your for loop. You could also define productList as an array in a previous line, and then use the forEach method on the products Array to loop through every item, but I think this is cleaner and still legible. You can reduce the code further with ES6 syntax, but for your question it's probably better to show code that is more clearly defined.

Nested Map loop async/await vs nested for loop async/await

I have a nested map loop with async awaits where I do 2 promise.all statements.
The data is formatted in 1 large array in which contains possibly multiple arrays of objects.
The inner loop will map through the objects in an array, and the outer loop will map through the arrays within the main array.
I'm using map since it is easy to keep this functioning with parallel performance versus sequential. I'm not sure if it is worth keeping it parallel or if there is a better way of doing this (maybe a for-each loop).
Here is the code (simplified/summarized) that I am using currently.
const outerPromise = information.map(async order => {
const innerPromise = order.moreInformation.map(async singleOrder => {
if (something) {
const response = await axios({ ... });
return response.specificDataField;
}
});
const orders = await Promise.all(innerPromise);
return orders.filter((obj) => obj);
});
const orders = await Promise.all(outerPromise);
return orders;
Sorry if the formatting is slightly off, the indentation might be off, I couldn't get it to format properly.
Any help will be greatly appreciated. Thank you!
P.S. This is being written in JS/NodeJs (ExpressJs)
Edit:
I don't think the issue is with me filtering afterwards since it is the objects that would possibly come out null; I would need to filter after getting back the innerPromise (to see which are null?).
That being said, it is really the 2 map statements that make me feel as if there is a better way of doing this.

What is the difference between these two array assignments in Typescript?

I am working on Angular 4 application.
I found below code in my application but unable to find exact purpose of below code.
getManagementView(groupField: string) {
this.auditList = [...this.auditList.filter(this.filterByRevisit)];
}
I changed it to below code both are working fine.
getManagementView(groupField: string) {
this.auditList = this.auditList.filter(this.filterByRevisit);
}
Could any one help me to understand what is the difference in above two code blocks.
There is noting different. The spread (...) operator destroys the array and gives back the elements one by one and then in the [] put them into the making again an array. Which is actually extra operation.
So this.auditList.filter(this.filterByRevisit) returns an array,
and this [...this.auditList.filter(this.filterByRevisit)] returns an array which is spread and again makes an array.
I don't think there is a difference between the two. ... would create a new array, filter already did it.
However if I take the title:
this.array = this.array // does nothing, same object
this.array = [...this.array] // creates a new array, though the same content

Javascript Rsjx: sorting chunks of data by date

[{"creationDate":"2011-03-13T00:17:25.000Z","fileName":"IMG_0001.JPG"},
{"creationDate":"2009-10-09T21:09:20.000Z","fileName":"IMG_0002.JPG"}]
[{"creationDate":"2012-10-08T21:29:49.800Z","fileName":"IMG_0004.JPG",
{"creationDate":"2010-08-08T18:52:11.900Z","fileName":"IMG_0003.JPG"}]
I use a HTTP get method to receive data. Unfortunately, while I do receive this data in chunks, it is not sorted by creationDate DESCENDING.
I need to sort these objects by creationDate my expected result would be.
[{"creationDate":"2012-10-08T21:29:49.800Z","fileName":"IMG_0004.JPG"},
{"creationDate":"2011-03-13T00:17:25.000Z","fileName":"IMG_0001.JPG"}]
[{"creationDate":"2010-08-08T18:52:11.900Z","fileName":"IMG_0003.JPG"},
{"creationDate":"2009-10-09T21:09:20.000Z","fileName":"IMG_0002.JPG"}]
Here's what I tried:
dataInChunks.map(data => {
return data.sort((a,b)=> {
return new Date(b.creationDate).getTime() - new Date(a.creationDate).getTime();
});
})
.subscribe(data => {
console.log(data);
})
This works only but only 1 object at a time which results in giving me the very top result. I need some way to join these chunks together and sort them and in some way break the whole object again into chunks of two.
Are there any RSJX operators I can use for this?
If you know the call definitely completes (which it should) then you can just use toArray which as the name suggests returns an array, which you can then sort. The point of toArray is that it won't produce a stream of data but will wait until the observer completes and return all values:
var allData = dataInChunks.toArray().sort(/*sorting logic*/);
However, if you are required to show the data in the browser as it arrives (if the toArray() approach makes the UI feel unresponsive), then you will have to re-sort the increasing dataset as it arrives:
var allData =[];
dataInChunks
.bufferWithCount(4)
.subscribe(vals => {
allData = allData.concat(vals);
allData.sort(/* sort logic*/);
})
This is slightly hacky as it's relying on a variable outside the stream, but yet get the idea. It uses a buffer bufferWithCount which will allow you to limit the number of re-sorts you do.
TBH, I would just go with the toArray approach, which begs the question why it's an observable in the first place! Good luck.

Categories

Resources