I am trying to loop through an array called directions each index containing two arrays, latitude at index 1 and longitude at index 0 and add the results from the mapbox.getDirections to a route array to plot a route on the map. Below is my code:
I believe I am facing synchronicity issues and mapbox.getDirections callback doesn't respond in time, so I am getting weirdness routes, if the route is greater than 1.
for (let i = 0; i < directions.length - 1; i++) {
let fromIndex = i;
let toIndex = fromIndex + 1;
let directionParams = [
{ latitude: directions[fromIndex][1], longitude: directions[fromIndex][0] },
{ latitude: directions[toIndex][1], longitude: directions[toIndex][0] }
]
let self = this;
mapbox.getDirections(directionParams, getDirectionsParams).then(function (results) {
let routes = results.entity.routes[0].geometry.coordinates;
let newRoute = self.state.route.concat(routes);
self.setState({
route: newRoute,
})
});
}
This method is supposed to be array-size agnostic, so if the array is 4 indices, it will extract the directions from index 0 to 1, 1 to 2, 2 to 3, therefore displaying 3 routes in total.
Separate the logic, you can move the promises outside of the loop, and resolve them all together with Promise.All
const yourFunction = async () => {
const arrayOfDirections = [];
for (let i = 0; i < directions.length - 1; i++) {
const fromIndex = i;
const toIndex = fromIndex + 1;
const directionParams = [
{ latitude: directions[fromIndex][1], longitude: directions[fromIndex][0] },
{ latitude: directions[toIndex][1], longitude: directions[toIndex][0] }
];
arrayOfDirections.push(directionParams);
}
const promises = [];
arrayOfDirections.forEach((directionParams) => {
promises.push(mapbox.getDirections(directionParams, getDirectionsParams));
});
const arrayOfresults = await Promise.all(promises);
// here you have array of results returned by your promises
};
Related
I have a Promise statement in the JS file, and need it to iterate through the array of the objects (places). A the moment I only have results for the first one, London
Furthermore, the if statement only works for the first tile (there are 7 of them)
Could you please show me the mistake I make?
const places = [
{
place: 'London',
lat: 51.50853,
long: -0.12574
},
{
place: 'Edinburgh',
lat: 55.953251,
long: -3.188267
},
{
place: 'Birmingham',
lat: 52.489471,
long: -1.898575
},
];
Promise.all(places.map((item) => {
const {lat, long} = item;
console.log(item.place);
return fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${long}&cnt=7&appid=20fdf77c85c5a540e4c904a48c226659`)
.then(response => response.json())
}))
.then(response => {
response.forEach((place) => {
const {city, list} = place;
console.log(response);
loc.textContent = `${city.name}`;
for(i=0; i<8; i++) {
document.getElementById('day' + (i+1) + 'Max').innerHTML = 'Max: ' + Number(list[i].main.temp_max - 273.15).toFixed(1)+ '°C';
document.getElementById('day' + (i+1) + 'Min').innerHTML = 'Min: ' + Number(list[i].main.temp_min - 273.15).toFixed(1)+ '°C';
let maximTemp = Number(list[i].main.temp_max - 273.15).toFixed(1);
let minimTemp = Number(list[i].main.temp_min - 273.15).toFixed(1);
console.log(maximTemp, minimTemp);
if (maximTemp < 10 || minimTemp < 10) {
document.getElementById('tile').style.backgroundColor = backgroundColour;
}
}
})
})
changed map to forEach
tried while instead of if
It happens that I am creating an object in Node JS and mssq, however some arrays are put in position 0, 0, and other arrays are put in [0], 1, 2, How can I find out what is causing this behavior?
Behavior 1
Query
var branchOfficesDTO = [];
var branchs = await pool.request().input('idUser', idUser).query(queryGetBranchsByUser);
for (let i = 0; i < branchs.recordset.length; i++) {
var categories = await pool.request().input('id', branchs.recordset[i].id).query(queryGetCategoriesByBranch);
let userDTO = {
categories: categories.recordset
}
branchOfficesDTO.push(branchOfficeDTO);
}
Result
Behavior 2
Query
var usersDTOByID = [];
var users = await pool.request().input('id', id).query(queryGetUserById);
for (let i = 0; i < users.recordset.length; i++) {
var categories = await pool.request().input('idUser', users.recordset[i].id).query(queryGetCategoriesByUser);
let userDTO = { categories: categories.recordset }
}
usersDTOByID.push(userDTO);
Result
I need the second behavior, help
My code is used so it generates random rarities based on how many you want to generate but I keep getting the syntax error:
i is not defined
With this code:
var rarities = [
'Common',
'Uncommon',
'Rare',
'Epic',
'Legendary',
'Exotic',
'Mythic'
]
let rarity = rarities[Math.floor(Math.random() * rarities.length)
function generateRarity(length, times){
let numbers = [];
for(i=0; i < times; i++){
let number = Math.floor(Math.random() * length)
numbers.push(number)
}
return numbers;
}
let indexArray = generateRarity(rarities.length, args)
let generatedRarities = [];
indexArray.forEach(index => generatedRarities.push(rarities[index]))
sentrarities = "#".join(generatedRarities)
await message.reply(sentrarities)
You get this error only because of a typo. When you are declaring let rarities, you are missing an ] at the end of it. JS then tries to include the function in it but then finds out that it can't so the error comes. All you have to do is change your code to:
var rarities = [
'Common',
'Uncommon',
'Rare',
'Epic',
'Legendary',
'Exotic',
'Mythic'
]
let rarity = rarities[Math.floor(Math.random() * rarities.length)]
function generateRarity(length, times) {
let numbers = [];
for (i = 0; i < times; i++) {
let number = Math.floor(Math.random() * length)
numbers.push(number)
}
return numbers;
}
let indexArray = generateRarity(rarities.length, args)
let generatedRarities = [];
indexArray.forEach(index => generatedRarities.push(rarities[index]))
sentrarities = "#".join(generatedRarities)
await message.reply(sentrarities)
I have an array which is a state of the React component. This array is a checklist.
var units1 = this.state.units;
when I update units1, this.state.units changes without the this.setState({ units: units1 })
I use this.setState({ a: 2 }); just to see if the array was updated without this.setState({ units: units2 });
this.state.units gets its value from props so if the state changes the props also changes.
handleItemChange(e) {
var units1 = this.state.units.slice();
var unit_name = parseInt(e.target.attributes.getNamedItem('data-unit_name').value);
var new_unit;
if (!e.target.checked && this.state.units && this.state.units.length > 0) {
this.state.units.map((unit) => {
if (unit_name == unit.codpacunidad) {
if (unit.topics && unit.topics.length > 0) {
unit.topics.map((topic) => {
if (topic.codpacunidadtema == e.target.name) {
new_unit = unit;
var index = units1.indexOf(unit);
//units1.splice(index, 1);
units1 = update(units1, {$splice: [[index, 1]]})
var topics1 = unit.topics.slice();
index = topics1.indexOf(topic);
//topics1.splice(index, 1);
topics1 = update(topics1, {$splice: [[index, 1]]})
new_unit.topics = topics1;
}
});
}
}
});
} else {
var found_unit = false;
var name = parseInt(e.target.name);
var order = parseInt(e.target.attributes.getNamedItem('data-order').value);
var unit_order = parseInt(e.target.attributes.getNamedItem('data-unit_order').value);
if (this.state.units && this.state.units.length > 0) {
this.state.units.map((unit) => {
if (unit.codpacunidad == unit_name) {
found_unit = true;
new_unit = unit;
var index = units1.indexOf(unit);
units1.splice(index, 1);
var new_topic = {
codpacunidadtema: name,
orden: order
};
var topics2 = new_unit.topics;
new_unit.topics = update(topics2, { $push: [new_topic]});
}
});
}
if (found_unit == false) {
new_unit = {
codpacunidad: unit_name,
orden: unit_order,
topics: [{codpacunidadtema: name, orden: order }]
};
}
}
// var units2 = update(units1, { $push: [new_unit]});
// this.setState({ units: units2.sort(function(a, b) {
// return parseInt(a.orden) - parseInt(b.orden);
// })
// });
this.setState({ a: 2 }); //just to test if the array gets updated without this.setStaet({ units: units2 })
}
Anybody knows why this is happening?
As #Alexander van Oostenrijk said to make deep copy of array.
Because array are passed by reference which mean memory address of the array is passed not the value of array.
var units1 = this.state.units.slice();
Now units1 has the reference address of that array any change made to units1 or this.state.units.slice() will change value of both.As basically they are using address and if one change the value at address then both will read changed value.Hope you understand
To create deep copy you can create new object like
var units1 = Object.assign([],this.state.units)
This will create new object with data of this.state.units
extras I think you do not need .slice().
I have 2 API calls.
The second API call depends on the Property ID returned to make the second API call to check if each of these properties has parking.
If it does, then I add details of that property to an object and push the object into an Array.
The second API call is nested inside the first. After I've looped through all the properties, I check if the Array length is more than 0, if it is then I can display the returned properties in page, else it shows an error.
The problem is even when there are properties returned with parking, the else statement or error function executes, as well as displaying properties on the page.
Is there a way to complete the nested Promise before checking if my Array is more than 0?
Here's my code:
$scope.viewPropertyList = function(latlong) {
$scope.locationError = false;
var latlongArray = latlog.split('::');
var searchLat_scope = latlongArray[0];
var searchLon_scope = latlongArray[1];
if (searchLat_scope && searchLon_scope) {
var data = Property.getAllProperties({
dest: 'property',
apikey: API_KEY,
lat: encodeURIComponent(searchLat_scope),
limit: 10,
lon: encodeURIComponent(searchLon_scope)
}).$promise.then(function(success) {
var propertyMarkers = [];
$scope.dbMarkers = 0;
for (var i = 0, l = success.property.length; i < l; i++) {
(function(i) {
Property.getProperty({
dest: 'property',
propertyId: success.property[i].name,
apikey: API_KEY
}).$promise.then(function(propertyData) {
for (var j = 0, k = propertyData.services.length; j < k; j++) {
if (propertyData.services[j].name === "parking") {
var obj = {
"propertyName": success.property[i].propertyName,
"telephone": success.property[i].telephone,
"postcode": success.property[i].address.postcode,
"city": success.property[i].address.city,
"county": success.property[i].address.county,
"addressLine1": success.property[i].address.addressLine1
};
propertyMarkers.push(obj);
}
}
if (propertyMarkers.length != 0) {
$scope.dbMarkers = propertyMarkers;
$scope.selectedLat = searchLat_scope;
$scope.selectedlog = searchLon_scope;
} else {
$scope.locationErr = true;
$scope.errorMsg = "No properties found";
}
});
})(i);
}
}, function(error) {
$scope.locationErr = true;
$scope.errorMsg = "Something went wrong, please try again";
});
}
}
Two main things :
there's no attempt to aggregate multiple promises generated in a loop.
the if (propertyMarkers.length > 0) {...} else {...} is too deeply nested.
Minor :
the inner iteration can break as soon as 'parking' is found. If it continued and further 'parking' was found, then duplicate markers would be created.
$scope.viewPropertyList = function(latlong) {
$scope.locationError = false;
var latlongArray = latlog.split('::');
var searchLat_scope = latlongArray[0];
var searchLon_scope = latlongArray[1];
if (searchLat_scope && searchLon_scope) {
Property.getAllProperties({
dest: 'property',
apikey: API_KEY,
limit: 10,
lat: encodeURIComponent(searchLat_scope),
lon: encodeURIComponent(searchLon_scope)
}).$promise.then(function(success) {
var propertyMarkers = [];
$scope.dbMarkers = 0;
// create an array of promises by mapping the array `success.property`.
var promises = success.property.map(function(prop) {
return Property.getProperty({
dest: 'property',
propertyId: prop.name,
apikey: API_KEY
}).$promise.then(function(propertyData) {
for (var j=0, k=propertyData.services.length; j<k; j++) {
if (propertyData.services[j].name === 'parking') {
propertyMarkers.push({
'propertyName': prop.propertyName,
'telephone': prop.telephone,
'postcode': prop.address.postcode,
'city': prop.address.city,
'county': prop.address.county,
'addressLine1': prop.address.addressLine1
});
break; // 'parking' is found - no point iterating further
}
}
});
});
/* ******** */
// Aggregate `promises`
$q.all(promises).then(function() {
// This block is now un-nested from its original position,
// and will execute when all `promises` have resolved.
if (propertyMarkers.length > 0) {
$scope.dbMarkers = propertyMarkers;
$scope.selectedLat = searchLat_scope;
$scope.selectedlog = searchLon_scope;
} else {
$scope.locationErr = true;
$scope.errorMsg = 'No parking found';
}
});
/* ******** */
}).catch(function(error) {
$scope.locationErr = true;
$scope.errorMsg = 'Something went wrong, please try again';
});
} else {
$scope.locationErr = true;
$scope.errorMsg = 'Problem with lat/lng data';
}
}
Notes :
that the outer iteration is now coded as success.property.map(), which returns promises and avoids the need for an IIFE.
Extra error handling added
If I got your problem right, you want all Property.getProperty promises of success.property are resolved before going to the success function to check propertyMarkers length.
In that case, you need $q.all to resolve all the Property.getProperty promises for you.
In your for (var i = 0, l = success.property.length; i < l; i++) { appends all the promises into an array
Property.getProperty({
dest: 'property',
propertyId: success.property[i].name,
apikey: API_KEY
})
then use $q.all(arrPromises).then(function(propertyData) { to do the following check.
One more thing worth to mention, promise chaining can be easily achieved by $promise.then(successFn, failFn).then(successFn, failFn).then.... Every time you call then() will create another promise which allows you to chain to next promise and pass value to the next.