Javascript angular parse queries synchronously (in sequence) - javascript

I am trying to use Parse in javascript to make two queries synchronously in sequence:
var innerQuery = new Parse.Query(Attendees);
innerQuery.equalTo("user_id",$localStorage.username);
innerQuery.equalTo("status","confirmed")
innerQuery.equalTo("code_verified",false)
var innerQuerytrue = new Parse.Query(Attendees);
innerQuerytrue.equalTo("user_id",$localStorage.username);
innerQuerytrue.equalTo("status","confirmed")
innerQuerytrue.equalTo("code_verified",true)
innerQuery.find({})
innerQuerytrue.find({})
var eventDetails = []
var queryfalse = new Parse.Query(Events)
queryfalse.matchesKeyInQuery("id_event","event_id",innerQuery);
var querytrue = new Parse.Query(Events)
querytrue.matchesKeyInQuery("id_event","event_id",innerQuerytrue);
queryfalse.find().then(function(results){
for (var i in results) {
var object = results[i];
var eventId = object.get("id_event");
var eventname = object.get("event_name");
var datestart = object.get("date_start");
var location = object.get("location");
var eventimagefile = object.get("event_image");
var eventimageurl = eventimagefile.url();
eventDetails.push({'name':eventname,'eventId':eventId, 'location':location, 'datestart':datestart, 'eventphoto':eventimageurl,'verified':false})
}
}).then(function(){
querytrue.find().then(function(results1){
for (var i in results1) {
var object = results1[i];
var eventId = object.get("id_event");
var eventname = object.get("event_name");
var datestart = object.get("date_start");
var location = object.get("location");
var eventimagefile = object.get("event_image");
var eventimageurl = eventimagefile.url();
eventDetails.push({'name':eventname,'eventId':eventId, 'location':location, 'datestart':datestart, 'eventphoto':eventimageurl,'verified':true})
}
})
}).then(function(){
$scope.events = eventDetails;
})
The second query, queryfalse, is not always executed. I am using promises and not sure if it is the right way to use them.

Just add return to pass the promise returned by querytrue.find().then() down the chain so the next then() won't execute until the promise is resolved. This also keeps your code flatter to avoid deeply nested promises.
queryfalse.find().then(function(results){
// code clipped for brevity
}).then(function(){
return querytrue.find().then(function(results1){
// code clipped for brevity
});
}).then(function(){
$scope.events = eventDetails;
});
Here's a working plunker that demonstrates this: https://plnkr.co/edit/SwPIC1K6yEhEgpIlxoEo?p=preview

You have to move the angular result to the 2nd promise.
var innerQuery = new Parse.Query(Attendees);
innerQuery.equalTo("user_id",$localStorage.username);
innerQuery.equalTo("status","confirmed")
innerQuery.equalTo("code_verified",false)
var innerQuerytrue = new Parse.Query(Attendees);
innerQuerytrue.equalTo("user_id",$localStorage.username);
innerQuerytrue.equalTo("status","confirmed")
innerQuerytrue.equalTo("code_verified",true)
innerQuery.find({})
innerQuerytrue.find({})
var eventDetails = []
var queryfalse = new Parse.Query(Events)
queryfalse.matchesKeyInQuery("id_event","event_id",innerQuery);
var querytrue = new Parse.Query(Events)
querytrue.matchesKeyInQuery("id_event","event_id",innerQuerytrue);
queryfalse.find().then(function(results){
for (var i in results) {
var object = results[i];
var eventId = object.get("id_event");
var eventname = object.get("event_name");
var datestart = object.get("date_start");
var location = object.get("location");
var eventimagefile = object.get("event_image");
var eventimageurl = eventimagefile.url();
eventDetails.push({'name':eventname,'eventId':eventId, 'location':location, 'datestart':datestart, 'eventphoto':eventimageurl,'verified':false})
}
}).then(function(){
querytrue.find().then(function(results1){
for (var i in results1) {
var object = results1[i];
var eventId = object.get("id_event");
var eventname = object.get("event_name");
var datestart = object.get("date_start");
var location = object.get("location");
var eventimagefile = object.get("event_image");
var eventimageurl = eventimagefile.url();
eventDetails.push({'name':eventname,'eventId':eventId, 'location':location, 'datestart':datestart, 'eventphoto':eventimageurl,'verified':true})
}
}).then(function(){
$scope.events = eventDetails;
});
})

querytrue.find() -> returns a promise, and that promise eventually returns a list of results that you're interested in.
.then() sets up some action after a promise, and returns another promise immediately. You can also pass a success handler & error handler function
so, when you say
var p = querytrue.find().then(onSuccess, onError)
p is a promise that will become the return value of the success or failure function, whichever one runs. You can chain another promise by adding another .then()
This chained promise gets the return value of the first promise.
If the first promise success function ran, the second chained success one will also run, likewise with error functions.
If your success handler creates another promise (like your question), you can return that promise from the success handler, and any subsequent chained promises will wait for that promise. Sort of adding a link to the chain.
var p = query1.find();
p.then( function(){
... // runs after query1.find()
var q = query2.find().then(...);
return q;
})
.then( function() {
... // runs after query1.find() and query2.find()
});

Related

wait for arrays to be filled with ajax results

I'm trying to make my page wait untill all data is loaded and put into the right arrays. I load the data using 3 seperate ajax calls but since the loading sometimes takes a little too long, the page continues while having empty arrays, and I need this data before I can do anything on the page.
I've been looking into the jQuery.when function but I can't seem to get it working.
this is 1 of the ajax calls:
function getWerktijden(){
var AllArrays = [];
var dagen = [];
var start = [];
var end = [];
$.ajax({
type: "GET",
url: '#Url.Action("getWerktijden")',
data: {
id: #Model.ID,
dag: d,
maandNr: m,
jaarNr: y,
getJson: true,
},
success: function (result) {
//console.log(result);
for(var v = 0; v < result.length; v++){
var resultItem = result[v];
var ingangsDatum = resultItem.activatieDatum;
var uitgangsDatum = resultItem.stopDatum;
if(ingangsDatum != ""){
ingangsDatum = new Date(changeDateTimeFormat(ingangsDatum));
ingangsDatum = ingangsDatum.toString('yyyy-MM-dd HH:mm:ss');
};
if(uitgangsDatum != ""){
uitgangsDatum = new Date(changeDateTimeFormat(uitgangsDatum));
uitgangsDatum = uitgangsDatum.toString('yyyy-MM-dd HH:mm:ss');
};
dagen.push({
werktijdenID: resultItem.id,
ingang: ingangsDatum,
uitgang: uitgangsDatum,
maandag: resultItem.maandag,
dinsdag: resultItem.dinsdag,
woensdag: resultItem.woensdag,
donderdag: resultItem.donderdag,
vrijdag: resultItem.vrijdag,
zaterdag: resultItem.zaterdag,
zondag: resultItem.zondag
});
start.push({
werktijdenID: resultItem.id,
ma_van: resultItem.ma_van,
di_van: resultItem.di_van,
wo_van: resultItem.wo_van,
do_van: resultItem.do_van,
vr_van: resultItem.vr_van,
za_van: resultItem.za_van,
zo_van: resultItem.zo_van,
})
end.push({
werktijdenID: resultItem.id,
ma_tot: resultItem.ma_tot,
di_tot: resultItem.di_tot,
wo_tot: resultItem.wo_tot,
do_tot: resultItem.do_tot,
vr_tot: resultItem.vr_tot,
za_tot: resultItem.za_tot,
zo_tot: resultItem.zo_tot,
})
}
}
});
AllArrays.push(dagen, start, end);
return AllArrays;
};
Then I call the function on a variable to return those results into that variable and check wether it's done with the jQuery.when function but the page continues no matter if the function has completed.
var allArrays = getWerktijden();
var event = getMeldingen(); //I put this here to show I have more ajax calls
var ziektedatums = getZiektedatums(); //I put this here to show I have more ajax calls
$.when.apply($, allArrays, event, ziektedatums).then(function(){
dagenPerWeek = allArrays[0];
startPerDag = allArrays[1];
endPerDag = allArrays[2];
}).done(function(){
console.log(dagenPerWeek, startPerDag, endPerDag, event, ziektedatums);
});
Can somebody explain to me what I am doing wrong?
Thanks!
Return the $.ajax promise instead of the array from each function
The array will be immediately returned before the ajax is complete as it is asynchronous. Also an array is not a promise so $.when won't wait for it to be populated
It's also easier to use Promise.all() vs $.when() in modern browsers
So it will look something like:
function getWerktijden() {
var AllArrays = [];
var dagen = [];
var start = [];
var end = [];
// return the promise
return $.ajax({ /* config options*/ })
.then(function(result) {
// do the processing into various arrays
// return to be used in next part of promise chain
return AllArrays;
});
}
Promise.all([getWerktijden(), getMeldingen(), getZiektedatums()])
.then(function(results){
// results will be array of whatever is returned from `then()`
// in each function and is in same order as they are called
var getWerktijden_Arrays = results[0],
dagenPerWeek = getWerktijden_Arrays[0]
console.log(dagemPerWeek);
})

Chaining promises in while loop not correctly returning values

The code below does not throw a syntax error, but the THEN statement which renders the data on the datatable is executing first, before all lists have been queried
What is the intention of this code, there are many sharepoint lists with similar names: Bill Cycles, Bill Cycles Archive1....N.
I need to query all those lists for a specific query, and concatenate the results of all of them in the result variable and then use that variable with datatables plugin to render, but as explain on the first statement, the outer .then is executeed in the beginning and inner then is executed later when the page is already rendered.
function GetData(billCycleId, clientCode, jobCodes, engagementCode) {
var deferred = $q.defer();
var enhanceFunctions = [
function(searchResultRow) {
return spService.AddHyperLinkOnFields(searchResultRow, config.HyperLinks);
},
function(searchResultRow) {
return spService.AddPresenceOnFields(searchResultRow, config.UserFields);
},
function(searchResultRow) {
return spService.FormatDateFields(searchResultRow, config.DateFields, generalConfig.DateTimeFormat);
},
function(searchResultRow) {
return spService.AddImageMapping(searchResultRow, config.ImageFields);
},
function(searchResultRow) {
return spService.FormatNumberFields(searchResultRow, config.NumberFields);
}
];
var selectProperties = spService.TransformFieldsToSelectProperties(config.Fields);
var extendedSelectProperties = selectProperties.slice(); // copy array
var hyperLinkedProperties = spService.TransformFieldsToSelectProperties(config.HyperLinks)
extendedSelectProperties = extendedSelectProperties.concat(hyperLinkedProperties);
var result =[];
spService.GetAllListsFromWeb()
.then(function (lists) {
var listEnumerator = lists.getEnumerator();
return $q.all(
(function(){
var promises = [];
while (listEnumerator.moveNext()) {
var oList = listEnumerator.get_current();
var title = oList.get_title();
var id = oList.get_id();
if (title.indexOf('Bill Cycles') !== -1) {
// Get data from SP !!! this is also async and returns a promise
// add the promise to promises array and wait for all to finish
// look above in Promise.all
promises.push(
GetRelatedBillCyclesFromList(
id,
extendedSelectProperties,
billCycleId,
clientCode,
jobCodes,
engagementCode,
enhanceFunctions
)
.then(function (data) {
var trimmedData =
spService
.SpSearchQuery
.TrimSearchResultsToSelectProperties(
data,
selectProperties
);
trimmedData.forEach(function(item){ // loop over source array
result.push(item); //append to result array
});
})
);
}
}
//return promises
})() //IIFE returning an array of promises
);
})
.then( //The promise is used to execute something after all promises are resolved, but the results are build in the result array, no need to use data
function(data){
//var resultadata = data;
var dataTable = $(tableSelector).DataTable();
dataTable.clear().rows.add(result).columns.adjust().draw(); // Resize columns based on new data sizes
vm.ValidDataLoaded = true;
}
);
}
You pass undefined to $q.all , because //return promises is commented out. Uncommenting that should fix your issue.

Promise.map within a Promise.map

I'm trying to do a return of JSON object using a Bluebird's Promise.mapSeries/Promise.map within a Promise.mapSeries/Promise.map but I am unable to return them correctly. The function is as follows:
function getMovieDetails(link){
return new Promise(function(resolve, reject) {
request(link, function(error, response, body){
var request = Promise.promisifyAll(require("request"), {multiArgs: true});
var $ = cheerio.load(body);
var movieYears = "Years";
var movieYearLinks = [];
movieYearLinks.each(function(index, item) {
var movieYear = $(item).text();
var movieYearLink = $(item).attr("href");
movieYearLinks.push(movieYearLink);
});
Promise.mapSeries(movieYearLinks, function(url) {
return request.getAsync(url).spread(function(response,body) {
var $ = cheerio.load(body);
var movie = {};
var year = "YEAR".text();
movie["year"] = year;
var movieActorsArray = [];
movieActors.each(function(index, item){
var movieActor = $(item).text();
movieActorsArray.push(movieActor);
});
movie["movieActors"] = movieActorsArray;
var recommendedMovies = //SOME ROWS;
var recommendedMoviesLinks = [];
recommendedMovies.each(function(jndex, jtem){
var recommendedRowObject = {};
var recommendedText = .text();
var recommendedLink = .attr("href");
recommendedRowObject["recommendedText"] = recommendedText
recommendedRowObject["recommendedLink"] = recommendedLink
recommendedMoviesLinks.push(recommendedLink);
});
Promise.mapSeries(recommendedMoviesLinks, function(url) {
return request.getAsync(url).spread(function(response,body) {
var $ = cheerio.load(body);
var obj = {};
// GET SOME OTHER DESCRIPTION FROM THE RECOMMENDED MOVIE LINK
return obj;
});
}).then(function(results) {
// results here returns an array of recommended movie links objects.
}).catch(function(err) {
});
return main;
});
}).then(function(results) {
// results here returns an array of movies
// I want to be able to link each movie with its recommended movies.
}).catch(function(err) {
console.log("Big Error " + err);
});
});
});
}
Some explanation of my code and context.
The home page is a page with movie years. I've looped through them to get the links of the years and put into an array movieYearLinks.
Next, I've used Promise.mapSeries to get some basic info on the movies. Within that basic info, there is are recommended movie link listed in a table. I've looped them through and put them into an array, recommendedMoviesLinks.
After which, I'm going in to grab some other recommended movie (recommendedMovieObject) info before.
I want to create a JSON object with all these info. The JSON object should be something like
{ movieYear: 2017, movieLink: ..., recommendedMovies (This is an array
of recommendedMovieObjects): }
I'm open to any solution to achieve this. Thank you in advance.
You don't need to nest promises, the whole point of promises is not having to nest callbacks. A new promise need to either be rejected with an error or resolved with a value. Your code should be something like :
let getMovieDetails = function(link){
return new Promise(function(resolve,reject){
request(link,function(err,response,body){
err ? reject(err):resolve(body)
}
}).then(function(body){
// do some cherio stuff
return dataList
}).then(function(dataList){
return Promise.all(dataList.map(function(d){return // a promise of d})
})
}
let finalData = getMovieDetails(link).then(function(data){
//do some computation
}).catch(function(e){ // handle errors })
Depending on your version of node there is no need for bluebird at all. Javascript supports promises.

For loop is returning promises in the wrong order

I'm calling a function a certain amount of times to fetch individual src attributes from an array of lists. The src attributes are coming back in the wrong order. I've tried using setTimeout but that returns an array of nulls and my own pause function just returns the same order of list just a certain amount of milliseconds later.
The function is called here:
myLoopingFunction: function(links) {
var pause = function sleep(milliseconds) {
var currentTime = new Date().getTime();
while (currentTime + milliseconds >= new Date().getTime()) {
}
}
var deferred = $q.defer();
var promise = deferred.promise;
var src = [];
for (var i = 0;i < links.length;i++) {
getSrc(links[i]).then(function(response) {
src.push(response)
});
}
deferred.resolve(src);
return deferred.promise;
}
EDIT:
This is the function:
var getSrc = function(links) {
return $q.all(links.map(function(link){
return $http.get(link.Address);
})).then(function(results){
var src = results.map(function(result){
var tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = result.data;
var video = $(tmp.body.children).find('#definitionblock iframe');
var video_src = $(video[0]).attr("src");
return video_src;
});
})
};
It's being called here:
bslLogin.getSrc($scope.links).then(function(response) {
$scope.videos = response;
console.log($scope.videos);
})
It's now returning undefined. I can see via console.logs that the chain of functions is producing the right result till the end where it returns undefined. It doesn't even recognise the return value as an array.
You have to use $q.all() to get the results of your "http-promises" in the expected order. In your code the http calls are running asynchronous (concurrently) and the callback handlers, which add responses to the array, too.
This could be a solution with an array of promises (be careful, the code is untested):
$q.all(links.map(function(link){
return $http.get(link.Address);
})).then(function(results){
var src = results.map(function(result){
var tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = response.data;
var video = $(tmp.body.children).find('#definitionblock iframe');
var video_src = $(video[0]).attr("src");
console.log(video_src);
return video_src;
});
return src;
})

ECMAScript Callback method executed after PreSaveAction method

My requirement is to get value from another list and set it to SharePoint list form and then save the item.
I wrote ECMAScript and PreSaveAction(). However, PreSaveAction() return true is executed before ECMAScript call back method, which is why my field value is not saved when I click Save button. Please note that my call back function has no error and I get correct value in alert. I don't know where I am doing wrong. Below is my code for you reference.
function PreSaveAction()
{
ExecuteOrDelayUntilScriptLoaded(GetTotalAmtAlloted, "sp.js");
return true;**//This line will execute before my callback function onListItemsLoadSuccess or onQueryFailed execute. Because of this, my field value not able to save it.**
}
function GetTotalAmtAlloted()
{
var clientContext = null;
var web = null;
var vID;
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
var list = web.get_lists().getByTitle("Investment");
var camlQuery = new SP.CamlQuery();
var q = "<View><Query><Where><Eq><FieldRef Name='InvestmentSubject' /><Value Type='Text'>abc</Value></Eq></Where></Query></View>";
camlQuery.set_viewXml(q);
listItems = list.getItems(camlQuery);
clientContext.load(listItems);
clientContext.executeQueryAsync(onListItemsLoadSuccess,onQueryFailed);//After this line "return true" in PreSaveAction() will execute and then CallBackMethods will run.
}
function onListItemsLoadSuccess(sender, args)
{
$("input[Title='Total Amount']").val("1000");
}
function onQueryFailed(sender,args)
{
alert("error");
}
You are performing an asynchronous function call but expect it to act synchronous. Instead, you have to wait for your asynchronous function to finish before your PreSaveAction can return true.
Since you're using jQuery, this can easily be achieved using the deferred/promise that jQuery provides.
function PreSaveAction() {
//Get the promise from the function
var promise = GetTotalAmtAlloted();
//This is run when the promise is resolved
promise.done(function(){
return true;
});
//This is run when the promise is rejected
promise.fail(funtion(){
});
}
function GetTotalAmtAlloted() {
var d = $.Deferred();
var clientContext = null;
var web = null;
var vID;
clientContext = new SP.ClientContext.get_current();
web = clientContext.get_web();
var list = web.get_lists().getByTitle("Investment");
var camlQuery = new SP.CamlQuery();
var q = "<View><Query><Where><Eq><FieldRef Name='InvestmentSubject' /><Value Type='Text'>abc</Value></Eq></Where></Query></View>";
camlQuery.set_viewXml(q);
listItems = list.getItems(camlQuery);
//An object to pass to the success and failure handlers
var data = {d: d, list: listItems}
clientContext.load(listItems);
//Execute the query and pass the data with our deferred object
clientContext.executeQueryAsync(Function.createDelegate(data, onListItemsLoadSuccess), Function.createDelegate(data, onQueryFailed));//After this line "return true" in PreSaveAction() will execute and then CallBackMethods will run.
//Return a promise that can either resolve or reject depending on if the async function is a success or failure
return d.promise();
}
function onListItemsLoadSuccess() {
//Access the listItems
var listItems = this.list;
//Do something with the list items
//On success, resolve the promise
this.d.resolve();
}
function onQueryFailed() {
//On failure, reject the promise
this.d.reject("Something went wrong!");
alert("error");
}

Categories

Resources