Retrieve SP List Data Deferred Promise - javascript

I am still struggling with getting a chain of deferred promises working on a Visual Web Part. The end goal is to change the colour of some DIV tags to colours referenced in a SPList.
I originally had this code working with a single request to lookup data from a list, but I am now looking for a chain of requests. The first is finding name of the Sub Site from the window.location.href property. Although this code is retrieving the sub site name thinking about this as if type this might be my first mistake and perhaps I should be getting this from the SPWeb object instead. The second then uses this value in a where clause to retrieve the correct data from the second call to a different list.
So the code if have at the moment works, but is intermittent. I think I'm not calling .resolve() in the correct place, and it is just luck as to if the async code has completed before the calling thread uses the expected result. It is therefore in the lap of the processor gods and probably works 50:50. This at least proves my jQuery code is producing the desired result.
I have two functions doing almost exactly the same thing to two different DIV elements. This is what I have at the moment.
function alterMenuColour(id) {
getMenuItemfromURLValue(window.location.href).done(function (urlSelection) {
var colkey = 0; //this is the key for the list collection array. This needs to be uneque for each different call to retrieveListItems.
var promise = retrieveListItems('/sites/OMGIntranet/OMGCentral/', 'MenuItemList', '<View><Query><Where><Eq><FieldRef Name=\'MenuItem\'/><Value Type=\'Text\'>' + urlSelection + '</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>', 'Id,MenuColour,BarColour', colkey);
var collMenuListItem = collListItem[colkey];
promise.done(
function (collMenuListItem) {
var listItemEnumerator = collMenuListItem.getEnumerator();
var oListItem;
while (listItemEnumerator.moveNext()) {
oListItem = listItemEnumerator.get_current();
}
var menus = getChildElementsByType(document, id, 'div');
jQuery(menus).children("div").each(function () {
jQuery(this).css("background", oListItem.get_item('MenuColour'));
});
},
function (sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
);
});
}
function alterBarColour() {
getMenuItemfromURLValue(window.location.href).done(function (urlSelection) {
var colkey = 1; //this is the key for the list collection array. This needs to be uneque for each different call to retrieveListItems.
var barpromise = retrieveListItems('/sites/OMGIntranet/OMGCentral/', 'MenuItemList', '<View><Query><Where><Eq><FieldRef Name=\'MenuItem\'/><Value Type=\'Text\'>' + urlSelection + '</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>', 'Id,MenuColour,BarColour', colkey);
var collBarListItem = collListItem[colkey];
barpromise.done(
function (collBarListItem) {
var listItemEnumerator = collBarListItem.getEnumerator();
var oListItem;
while (listItemEnumerator.moveNext()) {
oListItem = listItemEnumerator.get_current();
}
var bar = document.getElementsByClassName('SectionMenuBar');
jQuery(bar).each(function () {
jQuery(this).css("background", oListItem.get_item('BarColour'));
});
},
function (sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
);
});
}
I have created a function getMenuItemfromURLValue(url) which is the method if described earlier to get the Sub Site name.
function getMenuItemfromURLValue(url) {
var colkey = 2; //this is the key for the list collection array. This needs to be uneque for each different call to retrieveListItems.
var promise = retrieveListItems('/sites/OMGIntranet/OMGCentral/', 'SectionMenuAssignmentList', '<View><Query><OrderBy><FieldRef Name=\'ID\'/></OrderBy></Query></View>', 'MenuItemLookup', colkey);
var collSelectionMenuAssignemntListItem = collListItem[colkey];
return promise.then(
function (collSelectionMenuAssignemntListItem) {
var listItemEnumerator = collSelectionMenuAssignemntListItem.getEnumerator();
var oListItem;
while (listItemEnumerator.moveNext()) {
oListItem = listItemEnumerator.get_current();
if (isStringMatch(decodeURI(url), oListItem.get_item('MenuItemLookup').$2d_1)) {
return oListItem.get_item('MenuItemLookup').$2d_1;
}
}
},
function (sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
);
}
I am trying to write reusable code but it strikes me that it makes it harder to comprehend when using the deferred methods like .then()
I have a function to get the list data from SharePoint SPList which again on the same theme is reusable:
//http://www.shillier.com/archive/2013/03/04/using-promises-with-the-javascript-client-object-model-in-sharepoint-2013.aspx
function retrieveListItems(siteUrl, list, calm, include, collkey) {
var deferred = $.Deferred();
var clientContext
if (siteUrl == null) {
clientContext = sharePointCurrentClientContext();
} else {
clientContext = new SP.ClientContext(siteUrl);
}
var oList = clientContext.get_web().get_lists().getByTitle(list);
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(calm);
if (typeof this.collListItem === 'undefined') {
this.collListItem = [];
}
this.collListItem.add(collkey, oList.getItems(camlQuery));
if (include == null) {
clientContext.load(collListItem[collkey]);
} else {
clientContext.load(collListItem[collkey], 'Include(' + include + ')');
}
clientContext.executeQueryAsync(Function.createDelegate(this, function () { deferred.resolve(collListItem[collkey]) }), Function.createDelegate(this, function (sender, args) { deferred.reject(sender, args); }));
return deferred.promise();
}
Originally when I wrote this function the only way if could figure out how to return data successfully was in a global list collection object called collListItem. This is horrible I hate this and have been trying to remove it but so far unsuccessfully. It does work though, and having read and read and read, some people suggest that objects cannot be returned via deferred methods and that they have to be chained to pass on data. This again brings me back to being able to have reusable code.

I have got it working 100% of the time now, which is the goal, but I'm still not happy with it it doesn't seem to be elegant code and I'm still strugling with the concept.
I have changed,
function alterMenuColour(id) {
- getMenuItemfromURLValue(window.location.href).done(function (urlSelection) {
+ getMenuItemfromURLValue(window.location.href, 3).done(function (urlSelection) {
and
function alterBarColour() {
- getMenuItemfromURLValue(window.location.href).done(function (urlSelection) {
+ getMenuItemfromURLValue(window.location.href, 4).done(function (urlSelection) {
and
-function getMenuItemfromURLValue(url) {
-
- var colkey = 2; //this is the key for the list collection array. This needs to be uneque for each different call to retrieveListItems.
+function getMenuItemfromURLValue(url, colkey) {

Related

Wait until multiple asynchronous functions complete before executing

I have a Javascript for loop which runs through an array of database records (that have been extracted already).
I want to know when all the subsequent asynchronous actions have completed but I can't seem to do it.
For each record, the code runs a number of functions which return promises and then resolve (which then triggers another function to get more information, etc). This all works ok, but I can't figure out how to gather up each "FOR" iteration and detect when all records have been processed. Basically, I want to use a "throbber" and have the throbber remain until all processing has been completed.
Code is below (I've removed some extraneous info)...
for (var i = 0; i < systemArray.length; i++) {
// ***** FOR EACH SYSTEM ***** //
var currRecord = systemArray[i];
// SECTION REMOVED //
// GET SYSTEM LINES
var thisSystem = AVMI_filterArray("8.9", currRecord);
var thisSystemName = thisSystem[1].value;
var thisSystemRID = thisSystem[0].value;
// GET CHILDREN RIDS
AVMI_getChildren(systemLinesTable, thisSystemRID, systemLinesFID).done(function(ridList, sysRID)
{
var thisDiv = "div#" + sysRID;
// GET RECORD INFO FOR EACH RID
AVMI_getMultipleRecordInfoFromArray(ridList, systemLinesTable).done(function(systemLinesArray)
{
if (systemLinesArray != "" && systemLinesArray != null) {
systemLinesArray = systemLinesArray.sort(propComparator("10"));
x = AVMI_tableCombiner("System Lines", systemLinesArray, systemLinesCLIST, "skip3Right hbars xsmallText");
$(thisDiv).append(x);
} else {
$(thisDiv).append("<p>No System Lines...</p>");
}
}
);
}
);
} // ***** FOR EACH SYSTEM ***** //
AVMI_throbberClose(); // THIS, OF COURSE, EXECUTES ALMOST IMMEDIATELY
Here is function 1
///////////////////////////////////////////////////////////////
// Get related records using master
///////////////////////////////////////////////////////////////
function AVMI_getChildren(AVMI_db, AVMI_rid, AVMI_fid, AVMI_recText) {
var AVMI_query = "{" + AVMI_fid + ". EX. " + AVMI_rid + "}";
var AVMI_ridList = [];
var dfd2 = $.Deferred();
$.get(AVMI_db, {
act: "API_DoQuery",
query: AVMI_query,
clist: "3",
includeRids: "1"
}).then(function(xml1) {
$(xml1).find('record').each(function(){
var AVMI_record = $(this);
var AVMI_childRID = AVMI_record.attr("rid");
AVMI_ridList.push(AVMI_childRID);
});
AVMI_throbberUpdate("Found " + AVMI_ridList.length + " " + AVMI_recText + "...");
dfd2.resolve(AVMI_ridList, AVMI_rid);
});
return dfd2.promise();
};
And function 2
///////////////////////////////////////////////////////////////
// Get record info for each array member
///////////////////////////////////////////////////////////////
function AVMI_getMultipleRecordInfoFromArray(ridList, AVMI_db, AVMI_recType) {
var promises = [];
var bigArray = [];
$.each(ridList, function (index,value) {
var def = new $.Deferred();
var thisArray = [];
$.get(AVMI_db, { //******* ITERATIVE AJAX CALL *******
act: 'API_GetRecordInfo',
rid: value
}).then(function(xml2) {
AVMI_throbberUpdate("Got " + AVMI_recType + " " + value + "...");
$(xml2).find('field').each(function() {
var $field = {};
$field.fid = $(this).find('fid').text();
$field.name = $(this).find('name').text();
$field.value = $(this).find('value').text();
thisArray.push($field);
});
thisArray = thisArray.sort(AVMI_ArrayComparator);
bigArray.push(thisArray);
def.resolve(bigArray);
});
promises.push(def);
});
return $.when.apply(undefined, promises).promise();
};
Any ideas of how to structure this? I've tried all sorts of things with $.Deferred but I can't quite figure it out...
You do exactly the same thing you did in AVMI_getMultipleRecordInfoFromArray: Collect the promises in an array and use $.when (or Promise.all) to wait until they are resolved.
You can simply use .map in here which also takes care of the "function in a loop" problem:
var promises = systemArray.map(function(currRecord) {
// ...
return AVMI_getChildren(...).done(...);
});
$.when.apply(undefined, promises).done(function() {
AVMI_throbberClose();
});
You should have to disable the async property of ajax. By default it is set to true. It means that your doesn't wait for your ajax response. That why it is returning you undefined value and you have to set it to false. So your code will wait your request to complete.
So all you have to do is.
$.ajax({
url: '',
type: '',
async: false,
success: function(data){
}
});

Next iteration of $.each when received AJAX-content

The question has been asked before, but it is almost four years ago and maybe there is a better solution.
I have a $.each-loop where sometimes additional data is being fetched via ajax.
I am bulding an object with the fetched data, after the loop there is a function that generates HTML from the object. The problem is that the loop finishes before the ajax data arrives. If I place an alert in the HTML-generating-function the content is loading properly.
I am searching for a solution that calls the HTML-generator-function only when the loop and all ajax calls are finished. Maybe it is a solution to count the started Ajax requests and wait if all of them are finished?
I believe jQuery deferred is the right solution for me but I do find only examples where everything stays inside the loop. Can someone help?
I have stripped down my code to the most important things:
//goes through each testplace -->main loop
$.each(jsobject, function(key, value)
{
//build object together...
for (var i = 0, numComputer = jenkinsComputer.contents.computer.length; i < numComputer; i++)
{
//If the testplace is in both objects then fire AJAX request
if (jenkinsComputer.contents.computer[i].displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
{
//next $.each-iteration should only happen when received the JSON
var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
$.when($.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1")).done(function(jenkinsUser)
{
//build object together...
});
}
}
}); //End of main Loop ($.each)
generateHTML(builtObject);
It would be great if someone could give me an advice how to do it.
I would do something like this:
var thingstodo = $(jsobject).length;
var notfired = true;
$.each(jsobject, function(key, value)
{
//build object together...
for (var i = 0, numComputer = jenkinsComputer.contents.computer.length; i < numComputer; i++)
{
//If the testplace is in both objects then fire AJAX request
if (jenkinsComputer.contents.computer[i].displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
{
//next $.each-iteration should only happen when received the JSON
var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
$.when($.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1")).done(function(jenkinsUser)
{
//build object together...
thingstodo--;
if(thingstodo === 0 && notfired){
notfired = false;
generateHTML(buildObject);
}
});
}else{
thingstodo--;
}
}
}); //End of main Loop ($.each)
if(thingstodo === 0 && notfired){
generateHTML(buildObject);
}
This is short untested example about the solution. I hope this to give you idea.
// I guess that jsobject is array ..
// if it is not object you can use something like:
// var keys = Object.getOwnPropertyNames(jsobject)
(function () {
var dfd = $.Deferred();
function is_not_finished() {
return jsobject.length > 0 && jenkinsComputer.contents.computer.length > 0;
}
(function _handleObject() {
var key = jsobject.shift();
var displayName = jenkinsComputer.contents.computer.shift().displayName;
if (displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
{
//next $.each-iteration should only happen when received the JSON
var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
$.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1").done(function(jenkinsUser)
{
//build object together...
if(is_not_finished()) {
setTimeout(_handleObject,0);
} else {
dfd.resolve();
}
});
} else if (is_not_finished()) {
setTimeout(_handleObject,0);
} else {
dfd.resolve();
}
}());
return dfd.promise();
}()).done(function () {
generateHTML(builtObject);
});

The collection has not been initialized - Sharepoint Javascript

I'm getting the following error when attempting to get an enumerator for a collection of lists: "Uncaught Error: The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested."
It happens on the line var listEnumerator = lists.getEnumerator(); it seems to me that there is an issue in my attempt to load lists into the client object with context.load(lists);
Here's the portion of my code that's causing the problem. I've marked the place just before the error is thrown.
//____________________________Required function for accessing the host site's info.___________________________________
function getQueryStringParameter(param) {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == param) {
return singleParam[1];
}
}
}
//____________________________Begin checking for list_________________________
function checkForList(listToFind, typeOfListToCreateIfTheListIsMissing)
{
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostcontext = new SP.AppContextSite(context, hostUrl);
var hostweb = hostcontext.get_web();
var lists = hostweb.get_lists();
context.load(lists);
context.executeQueryAsync(checkIfListExistsUsingEnumerator(listToFind, lists, hostweb, typeOfListToCreateIfTheListIsMissing), onQueryFailed);
}
//Failed to get lists for some reason
function onQueryFailed(sender, args) {
alert('We failed to retrieve lists. \n' + args.get_message() + '\n' + args.get_stackTrace());
}
//____________________________Does list exist?____________________________
function checkIfListExistsUsingEnumerator(listToFind, lists, hostweb, typeOfList)
{
var listExists = false;
//!!!!!!!!!!!!!!! ERROR HERE !!!!!!!!!!!!!!!!
var listEnumerator = lists.getEnumerator();
var title;
while (listEnumerator.moveNext())
{
title = listEnumerator.get_current().get_title();
if (title == listToFind)
{
listExists = true;
}
}
if (!listExists)
{
alert("It appears that a required list does not already exist. \nClick ok, and we'll automatically create one for you.");
//Create a new list
createList(listToFind, hostweb, typeOfList);
}
else if (listExists)
{
//Do nothing.
}
}
//____________________________If it doesn't, create one on the local site____________________________
function createList(nameOfNewList, hostweb, typeOfList) {
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(nameOfNewList);
if (typeOfList === "events")
{
listCreationInfo.set_templateType(SP.ListTemplateType.events);
}
else if (typeOfList === "contacts")
{
listCreationInfo.set_templateType(SP.ListTemplateType.contacts);
}
var lists = hostweb.get_lists();
var newList = lists.add(listCreationInfo);
context.load(newList);
context.executeQueryAsync(onListCreationSuccess, onListCreationFail);
}
function onListCreationSuccess() {
alert('List created successfully!');
}
function onListCreationFail(sender, args) {
alert('Failed to create the list. ' + args.get_message());
}
I've looked at this question sharepoint javascript collection not initialized error which seems to be fairly similar to mine, but I'm having trouble implementing the solution provided there, making me think my error may be have a different cause.
I've also tried querying for the lists inside of the function that is throwing the error, but that doesn't seem to solve anything.
For a little background, these functions are attempting to read all lists from the app's host site, check to see if a specified list exists, and create a list if no matching list exists. If there's a better way of doing that than what I'm attempting, I'd be open to that too.
Any pointers?
Some things I've tried that don't seem to work:
Changing the Asynchronous query
context.executeQueryAsync(checkIfListExists(listToFind, hostweb, typeOfListToCreateIfTheListIsMissing), onQueryFailed);
to a Synchronous one.
context.executeQuery(checkIfListExists(listToFind, hostweb, typeOfListToCreateIfTheListIsMissing), onQueryFailed);
I've figured out an alternate, and shorter way to method of achieving the same goal I was trying to achieve before.
Instead of checking to see if a list does not already exist, I just try to create a list, and the Query fails to create a list if one is already there. (That's good because I don't want to overwrite the list if it is already there.)
I'm not totally sure if there are any undesired side effects of what I'm doing here, but in my tests it produced the desired behavior.
//____________________________Required function for accessing the host site's info.___________________________________
function getQueryStringParameter(param) {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == param) {
return singleParam[1];
}
}
}
//____________________________Create a list if one does not already exist_________________________
function createList(listToCreate, typeOfList)
{
// Create an announcement SharePoint list with the name that the user specifies.
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostContext = new SP.AppContextSite(currentContext, hostUrl);
var hostweb = hostContext.get_web();
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(listToCreate);
if (typeOfList === "events")
{
listCreationInfo.set_templateType(SP.ListTemplateType.events);
}
else if (typeOfList === "contacts")
{
listCreationInfo.set_templateType(SP.ListTemplateType.contacts);
}
var lists = hostweb.get_lists();
var newList = lists.add(listCreationInfo);
currentContext.load(newList);
currentContext.executeQueryAsync(onListCreationSuccess, onListCreationFail);
}
function onListCreationSuccess() {
alert("We've created a list since one doesn't exist yet." );
}
function onListCreationFail(sender, args) {
alert("We didn't create the list. Here's why: " + args.get_message());
}

Anonymous function causing ids to not be set after AJAX success

I'm making an AJAX call from within an Anonymous function. When the success callback takes place I'm then able to set my custom JS objects ids and other important info that has arrived from the data server.
After I set the a.target.id to the returned data.id everything looks fine.
On the step where I'm calling a function to do some work with the newly updated custom JS object, that I just updated with the response data from the server. I am passing the parent of that object to the method to do some work on all the children of that object.
However, as you can see on the last example in the snap shot photos the a.target.parent.children[0].id is not in the collection and/or it's ids where never set.
I must be losing a reference to that object during the AJAX call when using an Anonymous function.
Here is all of the code. How am I losing the reference? Or how can I maintain a reference to that parent's children when the AJAX call returns?
I've never had this happen before, makes me believe that it has something to do with the Anonymous function.
var horizontalPositioner = function (horizontals) {
var hpa = ['?horPositions='];
for (var i = 0; i < horizontals.children.length; i += 1) {
hpa.push(horizontals.children[i].id + ':' + horizontals.children[i].position + ',');
};
hpa[i] = hpa[i].replace(',', '');
dataBase.update(dbPart('horizontal' + hpa.join('')));
};
this.subscribe.call(this, e.horizontaladded, function (a, fn) {
//
if (!a.extra.owner.id) {
return;
};
(function (a) {
dataBase.insert(
dbPart(
['horizontal?a=', a.extra.owner.instanceName, '&id=', a.extra.owner.id].join(''),
a.target
),
dbCB(
function (data, status) {
if (status === 'error') { return; };
a.target.id = data.id,
a.target.HTML().addClass('alum_' + data.id),
a.target.finish.id = data.finishID,
a.target.size.id = data.sizeID,
a.target.siteLine.id = data.sitelineID;
//
//reposition horizontals
// setTimeout(function () { horizontalPositioner(a.target.parent); }, 1000);
debugger
horizontalPositioner(a.target.parent);
if (fn) { processCallbacks(data, status, fn); };
//very last
events.publishDatabaseCallbacks(e.horizontaladded,
eArgs(a.bay, { data: data, instanceName: 'horizontal', ownerid: a.extra.owner.id, id: data.id }));
},
function (xhr, status, errorThrown) { console.log('ERROR adding horizontal'); })
);
}(a));
}, true);
I've added an anonymous function with a nested setTimeout to give everything time to build. I've got many events taking place at once, so for now this works.
var horizontalPositioner = function (horizontals) {
(function (hors) {
setTimeout(function () {
var hpa = ['?horPositions='];
for (var i = 0; i < hors.children.length; i += 1) {
hpa.push(hors.children[i].id + ':' + (hors.children[i].position ? hors.children[i].position : 1) + ',');
};
hpa[i] = hpa[i].replace(',', '');
dataBase.update(dbPart('horizontal' + hpa.join('')));
}, 1000);
}(horizontals));
};

How do I get the gender from a particular user when updating a different table? Azure mobile services

I have a table called Subscription and another table called Client I need the gender of the Client who owns the subscription every time I make an update. Here's my update script:
function update(item, user, request) {
var subscriptionId = item.id;
var subscriptionActivitiesTable = tables.getTable("SubscriptionActivity");
var userTable = tables.getTable("User");
var activityTable = tables.getTable("Activity");
var userGender = userTable.where({id: item.UserId}).select('Gender').take(1).read();
console.log(userGender);
activityTable.where({PlanId:item.PlanId, Difficulty: item.Difficulty}).read({
success: function(results){
var startDate = item.StartDate;
results.forEach(function(activity)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (activity.Week*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
})
}
});
var planWeeks = 12;//VER DE DONDE SACAMOS ESTE NUMERO
var idealWeight = 0;
if (userGender === "Male")
{
idealWeight = (21.7 * Math.pow(parseInt(item.Height)/100,2));
}
else
{
idealWeight = (23 * Math.pow(parseInt(item.Height)/100,2));
}
var metabolismoBasal = idealWeight * 0.95 * 24;
var ADE = 0.1 * metabolismoBasal;
var activityFactor;
if (item.Difficulty === "Easy")
{
activityFactor = 1.25;
}
else if(item.Difficulty === "Medium")
{
activityFactor = 1.5;
}
else
{
activityFactor = 1.75;
}
var caloricRequirement = ((metabolismoBasal + ADE)*activityFactor);
activityTable.where(function(item, caloricRequirement){
return this.PlanId === item.PlanId && this.Type != "Sport" &&
this.CaloricRequirementMin <= caloricRequirement &&
this.CaloricRequirementMax >= caloricRequirement;}, item, caloricRequirement).read({
success: function(results)
{
var startDate = item.StartDate;
results.forEach(function(activity)
{
for (var i=0;i<planWeeks;i++)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (i*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
}
})
}
})
request.execute();
}
I tried the code above and clientGender is undefined. As you can see I want to use the gender to set the idealWeight.
The read() method expects a function to be passed in on the success parameter - it doesn't return the result of the query like you'd think.
Try something like this instead:
function update(item, user, request) {
var clientTable = tables.getTable("Client");
var clientGender = 'DEFAULT';
clientTable.where({id: item.ClientId}).select('Gender').take(1).read({
success: function(clients) {
if (clients.length == 0) {
console.error('Unable to find client for id ' + item.ClientId);
} else {
var client = client[0];
clientGender = client.Gender;
// since we're inside the success function, we can continue to
// use the clientGender as it will reflect the correct value
// as retrieved from the database
console.log('INSIDE: ' + clientGender);
}
}
});
// this is going to get called while the clientTable query above is
// still running and will most likely show a value of DEFAULT
console.log('OUTSIDE: ' + clientGender);
}
In this sample, the client table query is kicked off, with a callback function provided in the success parameter. When the query is finished, the callback function is called, and the resulting data is displayed to the log. Meanwhile - while the query is still running, that is - the next statement after the where/take/select/read fluent code is run, another console.log statment is executed to show the value of the clientGender field outside the read function. This code will run while the read statement is still waiting on the database. Your output should look something like this in the WAMS log:
* INSIDE: Male
* OUTSIDE: Default
Since the log shows the oldest entries at the bottom, you can see that the OUTSIDE log entry was written sometime before the INSIDE log.
If you're not used to async or functional programming, this might look weird, but as far as I've found, this is now node works. Functions nested in functions nested in functions can get kind of scary, but if you plan ahead, it probably won't be too bad :-)

Categories

Resources