So, I'm adding an establishment to the database, then adding a special to the database. An establishment can have 1 to Many specials, so I'm trying to create a relation under the 3rd .then()
. The thing is, then 3rd .then()
is executing before an establishment and special is added to the database. I need to add the establishment and special to the database first because I need to obtain their objectIds, var establishmentObjectId;
and var specialObjectId;
How can I go about making sure the the establishment and special objectIds are retrieved before the relation is made?
//Save the establishment objectId
var establishmentObjectId;
//Save the special objectID
var specialObjectId;
//Save establishment
.then(() => {
//Get the add form data
var addName = document.getElementById('add_name');
var addCountry = document.getElementById('add_country');
var addEstablishmentType = document.getElementById('add_establishment_type');
var addCuisineType = document.getElementById('add_cusine_type');
//Create establishment from user's enteries
var establishment = {
Name: addName.value,
Address: addAddress.value,
Suburb: addSuburb.value,
Country: addCountry.value,
Cuisine_Type: addCuisineType.value,
Establishment_Type: addEstablishmentType.value
}
//Save establishment to db
Backendless.Data.of('Establishment').save( establishment )
.then( function( savedObject ) {
establishmentObjectId = savedObject.objectId;
console.log( "new Establishment instance has been saved" );
})
.catch( function( error ) {
console.log( "an error has occurred " + error.message );
});
})
//Save special
.then(() => {
//Get the add form data
var addCategory = document.getElementById('add_category');
var addTypeOfSpecial = document.getElementById('add_type_of_special');
var addDescription = document.getElementById('add_description');
//Create special from user's enteries
var special = {
Category: addCategory.value,
Type_Of_Special: addTypeOfSpecial.value,
Description: addDescription.value
}
//Save special to db
Backendless.Data.of('Special').save( special )
.then( function( savedObject ) {
specialObjectId = savedObject.objectId;
console.log( "new Special instance has been saved" );
})
.catch( function( error ) {
console.log( "an error has occurred " + error.message );
});
})
//Add special to establishment/form relation
.then(() => {
//These are undefined even though they are declared above
console.log(establishmentObjectId);
console.log(specialObjectId);
var parentObject = { objectId:establishmentObjectId };
var childObject = { objectId:specialObjectId };
var children = [ childObject ];
Backendless.Data.of( "Establishment" ).addRelation( parentObject, "establishmentSpecials", children )
.then( function( count ) {
console.log( "relation has been set" );
})
.catch( function( error ) {
console.log( "server reported an error - " + error.message );
});
})
Many thanks
Whenever you're in a Promise chain, 99% of the time, when you create a new Promise (with an API call, or with new Promise
, etc), you should return it, or otherwise put it together with something else (like a Promise.all
and return that). This will mean that possible rejections can be handled at a higher level, and will mean that the next .then
in a chain will start only once the prior .then
finishes.
Change every
Backendless.Data.of(
to
return Backendless.Data.of(
Also, you probably don't want to be catch
ing at every level, like you're doing currently - whenever you catch
, you turn a rejected Promise into a resolved Promise, and subsequent .then
s may be running on the assumption that everything in the prior .then
finished successfully. With sequential asynchronous operations like these, if there's an error anywhere, you probably want to stop the whole process, rather than try to continue anyway (which could result in bugs).
For example, if Backendless.Data.of('Establishment').save
fails, then establishmentObjectId
never gets assigned to, and trying to use it later in the final .then
won't work. Same sort of thing with specialObjectId
.
For this code, there's also a better pattern to follow: instead of using two separate .then
s, one to get the establishmentObjectId
and one to get the specialObjectId
, consider letting those operations run in parallel, and run the final .then
after they're done via Promise.all
. Something along the lines of:
const getEstablishmentObjectId = () => {
//Get the add form data
// ...
//Create establishment from user's enteries
var establishment = {
// ...
}
//Save establishment to db
return Backendless.Data.of('Establishment').save(establishment)
.then(savedObject => savedObject.objectId);
};
const getSpecialObjectId = () => {
// ...
return Backendless.Data.of('Special').save(special)
.then(savedObject => savedObject.objectId);
};
Promise.all([
getEstablishmentObjectId(),
getSpecialObjectId(),
]).then(([establishmentObjectId, specialObjectId]) => {
console.log(establishmentObjectId);
console.log(specialObjectId);
var parentObject = {
objectId: establishmentObjectId
};
// etc
})
.catch((error) => {
console.log('Error', error);
});