I have a query against a sharepoint list that returns some data, but then for each item I have to make another query to get its document type (content type), the problem is that this part of the code is executed after the page has been rendered.
var cname = getContentTypeOfCurrentItem(listItemValues['ID'].toString());
listItemsWithValues['Document Type'] = cname;
function GetRelatedBillingDocumentsFromList(selectProperties, currentBillCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions) {
$log.info('Retrieving related billing documents for bill cycle with name [' + currentBillCyclePath + ']');
var deferred = $q.defer();
var webUrl = _spPageContextInfo.webAbsoluteUrl;
var viewFields = spService.ConvertSelectPropertiesToViewFields(selectProperties);
// query must return the documents for the same client but in other bill cycles not the current one
var camlQuery = '<View Scope="RecursiveAll">' + viewFields +
'<Query>' +
'<Where>' +
'<And>' +
'<Eq>' +
'<FieldRef Name="ClientCode" />' +
'<Value Type="Text">' + clientCode + '</Value>' +
'</Eq>' +
'<Neq>' +
'<FieldRef Name="ContentType" />' +
'<Value Type="Computed">Bill Cycle</Value>' +
'</Neq>' +
'</And>' +
'</Where>' +
'</Query>' +
'</View>';
var billCyclesListId = '{c23bbae4-34f7-494c-8f67-acece3ba60da}';
spService.GetListItems(billCyclesListId, camlQuery, selectProperties)
.then(function (listItems) {
var listItemsWithValues = [];
if (listItems) {
var enumerator = listItems.getEnumerator();
var promises = [];
while (enumerator.moveNext()) {
var listItem = enumerator.get_current();
var listItemValues = [];
selectProperties
.forEach(function (propertyName) {
var value = listItem.get_item(propertyName);
if (propertyName === 'PwC_JobCodesMulti') {
jobvalue = '';
value.forEach(function (jobvalues) {
jobvalue += jobvalues.get_lookupValue() + ';';
});
listItemValues[propertyName] = jobvalue;
} else {
listItemValues[propertyName] = value;
}
//listItemValues[propertyName] = value;
});
listItemsWithValues.push(listItemValues);
}
var cname = getContentTypeOfCurrentItem(listItemValues['ID'].toString());
listItemsWithValues['Document Type'] = cname;
}
listItemsWithValues.forEach(function (listItem) {
var fileDirRef = listItem['FileRef'];
var id = listItem['ID'];
var title = listItem['Title'];
var serverUrl = _spPageContextInfo.webAbsoluteUrl.replace(_spPageContextInfo.webServerRelativeUrl, '');
var dispFormUrl = serverUrl + '/sites/billing/_layouts/15/DocSetHome.aspx?id=' + fileDirRef;
//listItem["FileRef"] = dispFormUrl;
//listItem["Bill Cycle"] = dispFormUrl;
var parentLink = listItem['FileRef'];
arrayofstrings = parentLink.split('/');
var billCycleFolderName = arrayofstrings[arrayofstrings.length - 2];
arrayofstrings.pop();
var hyperLink = '' + billCycleFolderName + '';
listItem['Bill Cycle'] = hyperLink;
});
var enhancedListItemValues = spService.SpSearchQuery.EnhanceSearchResults(listItemsWithValues, enhanceFunctions);
deferred.resolve(listItemsWithValues);
})
.catch(function (message) {
deferred.reject();
});
return deferred.promise;
}
function getContentTypeOfCurrentItem(id) {
var clientContext = new SP.ClientContext.get_current();
var oList = clientContext.get_web().get_lists().getByTitle('Bill Cycles');
listItem = oList.getItemById(id);
clientContext.load(listItem);
listContentTypes = oList.get_contentTypes();
clientContext.load(listContentTypes);
clientContext.executeQueryAsync(
Function.createDelegate(this, getContentTypeOfCurrentItemSucceeded),
function (error, errorInfo) {
$log.warn('Retrieving list item result failed');
deferred.reject(errorInfo);
}
);
}
function getContentTypeOfCurrentItemSucceeded(sender, args) {
var ctid = listItem.get_item('ContentTypeId').toString();
var ct_enumerator = listContentTypes.getEnumerator();
while (ct_enumerator.moveNext()) {
var ct = ct_enumerator.get_current();
if (ct.get_id().toString() == ctid) {
var contentTypeName = ct.get_name();
return contentTypeName;
}
}
}
How do I chan promises here to make sure that the content type call is done right?
I've refactored your example to understand the intent of your code. I think that you need to understand better the async nature of promises and the idea of scope / closures (I don't think your code works at all, in many ways, i've included a review in the oldscript.js file).
https://embed.plnkr.co/3YcHZzxH4u6ylcA2lJZl/
My example uses a Stub object to simulate your provider, but to keep it short I'd say: the key is Promise.all, a factory that generates a new Promise that gets fulfilled when all the promises are resolved.
You need to store one promise for each item holding the future value for each ID (your original snippet only stores the last ID, it seemed to be a bug), and when all of them are resolved you can keep working with your data (later on time, aka async or deferred).
Hope it helps
A relevant snippet...
function addContentType(listItem){
var promise = getContentTypeOfCurrentItem(listItem.ID.toString());
promise.then(function(cname){
listItem['Document Type'] = cname;
});
return promise;
}
function processListItems(listItems) {
var listItemsWithValues = listItems.map(listItemToValue);
var promises = listItemsWithValues.map(addContentType);
Promise.all(promises).then(youCanUseTheData);
function youCanUseTheData(){
/*
At this point, each listItem holds the 'Document Type' info
*/
listItemsWithValues.forEach(function (listItem) {
console.log(listItem);
});
}
Related
I'm attempting to run two separate queries in a NodeJS Lambda Function. The first inserts a single record, and will return an order number used in the subsequent queries. The second query needs to insert n records (order items), so I've been trying to execute those utilizing the async node library as you can see below.
I'm running into issues where it's either not executing those queries at all, or is only inserting a single record versus n records. I'm feeding it right now with an API request, so the referenced items array should have two indexes in it, resulting in two iterations.
const sql = require('mssql');
const async = require('async');
(function() {
// ——- Database support ——- //
exports.handler = function(event, context, callback)
{
const config = {
user: 'my_user',
password: 'my_pass',
server: 'my_serv',
database: 'my_db',
options: {
encrypt: true
}
};
// Request Body
var body = event;
var items = body[1]["items"];
var addDateTimeRaw = body[1]["created_at"];
var splitDateTime = addDateTimeRaw.split(" ");
// SPROC params
var CustomerNumber = "1234";
var OrderDateString = splitDateTime[0];
var ShipVia = "UPS";
var FOB = "null";
var PaymentTerms = "CREDIT CARD";
var Discount = "0";
var OrderAmount = body[1]["total_price"].cents;
var PONumber = body[1]["_id"];
var Comment = "I am a comment";
var SalesPerson = "WA";
var IsShippingSameAsBilling = "X";
var TaxableAmount = body[1]["total_value"].cents;
var TaxState = "my_state";
var AddDate = splitDateTime[0];
var AddTime = splitDateTime[1];
var WebOrderNumber = body[1]["_id"];
sql.connect(config, (err) => {
if (err) {
console.log(err);
callback(err);
} else {
const req = new sql.Request();
req.query('EXEC InsertOrder #CustomerNumber = "' + CustomerNumber + '", #OrderDateString = "' + OrderDateString + '", #ShipVia = "' + ShipVia + '", #FOB = "' + FOB + '", #PaymentTerms = "' + PaymentTerms + '", #Discount = "' + Discount + '", #OrderAmount = "' + OrderAmount + '", #PONumber = "' + PONumber + '", #Comment = "' + Comment + '", #SalesPerson = "' + SalesPerson + '", #IsShippingSameAsBilling = "' + IsShippingSameAsBilling + '", #TaxableAmount = "' + TaxableAmount + '", #TaxState = "' +TaxState + '", #AddDate = "' + AddDate + '", #AddTime = "' + AddTime + '", #WebOrderNumber = "' + WebOrderNumber + '";', (error, result) => {
if (error) {
console.log(error);
callback(error);
} else {
var OrderNumber = result.recordset[0].sono;
insertOrderItems(OrderNumber);
sql.close();
context.succeed(result.recordset)
return JSON.stringify(items);
}
});
function insertOrderItems(OrderNumber) {
async.forEachOf(items, function (item, i, inner_callback){
//var itemNumber = item["sku"];
var ItemNumber = "5678";
var DiscountPercent = "0";
var TaxRate = "6";
var Quantity = item["quantity"];
var ItemSequence = i + 1;
var CustomerMemo = "I am a memo";
var UnitPrice = "6.00";
var ssql = 'EXEC InsertOrderItems #OrderNumber = "' + OrderNumber + '", #ItemNumber = "' + ItemNumber + '", #DiscountPercent = "' + DiscountPercent + '", #TaxRate = "' + TaxRate + '", #Quantity = "' + Quantity + '", #ItemSequence = "' + ItemSequence + '", #CustomerMemo = "' + CustomerMemo + '", #UnitPrice = "' + UnitPrice + '";';
req.query(ssql, function(err, members, fields){
if(!err){
console.log(members);
//context.succeed(members.recordset)
inner_callback(null);
} else {
console.log("Error while performing Query");
inner_callback(err);
};
});
}, function(err){
if(err){
//handle the error if the query throws an error
callback(err);
}else{
//whatever you wanna do after all the iterations are done
callback(null);
}
});
}
}
});
sql.on('error', (err) => {
console.log(err);
callback(err);
});
};
}());
Why might that function call to the async SQL query not be executing? I'm attempting to keep the same SQL connection open for both of the executed queries.
The async is not a main issue. I patched some places but it still worse.
Why do you not learn step-by-step?
const sql = require('mssql');
const async = require('async');
const config = { ... };
exports.handler = function(event, context, callback) {
// Use default object with props or check existing of every props
var body = (event && event[1]) instanceof Object ? event[1] : {items: [], created_at: ' ', _id: ...};
var items = body.items || []; // Always use default value
var [addDate, addTime] = (created_at || '').split(' '); // Use destructuring assignment
// SPROC params
var CustomerNumber = "1234";
var OrderDateString = splitDateTime[0];
var ShipVia = "UPS";
var FOB = "null";
var PaymentTerms = "CREDIT CARD";
var Discount = "0";
var OrderAmount = parseFloat((body.total_price || {}).cents) || 0; // total_price can be non-object and it'll fall your app
var PONumber = body[1]["_id"];
var Comment = "I am a comment";
var SalesPerson = "WA";
var IsShippingSameAsBilling = "X";
var TaxableAmount = body[1]["total_value"].cents;
var TaxState = "my_state";
var WebOrderNumber = body._id;
sql.connect(config, (err) => {
// Early quit to avoid {}-ladder
if (err)
return callback(err);
const req = new sql.Request();
// Never do like this. Read about sql-injection. Use placeholders.
req.query('EXEC ost_InsertOrder #CustomerNumber = "' + ..., (err, result) => {
if (err)
return callback(err);
var OrderNumber = result.recordset.length && result.recordset[0].sono; // You must be sure that result has rows
// You should read about async-code
insertOrderItems(OrderNumber); // Here you start to insert items
sql.close(); // But before it'll success you close connection.
context.succeed(result.recordset);
// I didn't see definition of items.
// Return? For what?
return JSON.stringify(items);
});
...
}
});
sql.on('error', callback);
};
I have an if statement that when I print the result in the console, I can see sometimes its true, and sometimes its false.
However, whats inside the IF, its never executed and the resulting array is always empty.
var createQuery = function(viewFields,clientCode) {
return '<View Scope="RecursiveAll">' + viewFields +
'<Query>' +
'<Where>' +
'<And>' +
'<Eq>' +
'<FieldRef Name="ClientCode" />' +
'<Value Type="Text">'+ clientCode + '</Value>' +
'</Eq>' +
'<Neq>' +
'<FieldRef Name="ContentType" />' +
'<Value Type="Computed">Bill Cycle</Value>' +
'</Neq>' +
'</And>' +
'</Where>' +
'</Query>' +
'</View>';
};
var createListItemValues = function(filter) {
return function(listItems,selectProperties) {
var listItemsWithValues = [];
if (listItems) {
var enumerator = listItems.getEnumerator();
while (enumerator.moveNext()) {
var listItem = enumerator.get_current();
var listItemValues = [];
selectProperties
.forEach(function (propertyName) {
var value = listItem.get_item(propertyName);
if (propertyName === "JobCodesMulti") {
jobvalue = "";
value.forEach(function (jobvalues) {
jobvalue += jobvalues.get_lookupValue() + ";";
})
listItemValues[propertyName] = jobvalue;
} else {
listItemValues[propertyName] = value;
}
});
if(filter(listItemValues)){//only push if filter returns true
listItemsWithValues.push(listItemValues);
}
}
}
return listItemsWithValues;
};
};
var processListItemWithValue = function(listItemsWithValues) {
return function(listItem) {
var fileDirRef = listItem["FileRef"];
var id = listItem["ID"];
var title = listItem["Title"];
var serverUrl = _spPageContextInfo.webAbsoluteUrl.replace(_spPageContextInfo.webServerRelativeUrl, "");
var dispFormUrl = serverUrl + "/sites/billing/_layouts/15/DocSetHome.aspx?id=" + fileDirRef;
var parentLink = listItem["FileRef"];
//!!!PLEASE NOTE: made arrayofstrings a local variable
var arrayofstrings = parentLink.split("/");
var billCycleFolderName = arrayofstrings[arrayofstrings.length - 2];
arrayofstrings.pop();
var hyperLink = '' + billCycleFolderName + '';
listItem["Bill Cycle"] = hyperLink;
listItemsWithValues["Document Type"] = getContentTypeOfCurrentItem(listItem.ID.toString());
}
};
function GetRelatedBillingDocumentsFromList(selectProperties, currentBillCyclePath, clientCode, jobCodes, engagementCode, enhanceFunctions) {
$log.info("Retrieving related billing documents for bill cycle with name [" + currentBillCyclePath + "]");
//pass filter function to createListItemValues to get a new function that
// creates filtered list item values
var createFilteredListItemsWithValues = createListItemValues(
function(listItemValues) {
var x1=listItemValues && typeof listItemValues.FileRef === "string" && listItemValues.FileRef.split("/")[4];
var x2= currentBillCyclePath.split("/")[8]
console.log(x1===x2);
return !(//pass filter function to createListItemValues
listItemValues &&
typeof listItemValues.FileRef === "string" &&
listItemValues.FileRef.split("/")[4]
) === currentBillCyclePath.split("/")[8];
}
);
var webUrl = _spPageContextInfo.webAbsoluteUrl;
selectProperties = selectProperties.concat("ContentTypeId");
var viewFields = spService.ConvertSelectPropertiesToViewFields(selectProperties);
// query must return the documents for the same client but in other bill cycles not the current one
var camlQuery = createQuery(viewFields,clientCode);
var billCyclesListId = "{c23bbae4-34f7-494c-8f67-acece3ba60da}";
//return a promise like here so the caller knows if something went wrong
return spService.GetListItems(billCyclesListId, camlQuery, selectProperties)
.then(
function(listItems){
console.log("currentBillCyclePath:",currentBillCyclePath);
var listItemsValues = createFilteredListItemsWithValues
(listItems,selectProperties);
return $q.all(listItemsValues.map(addContentType))
.then(function(){ return listItemsValues; })//finished asynchronously mutating array of listItems
}
).then(
function(listItemsWithValues) {
listItemsWithValues.forEach(processListItemWithValue(listItemsWithValues));
return $q.all(
spService.SpSearchQuery.EnhanceSearchResults(listItemsWithValues, enhanceFunctions)
)
}
)
}
the important lines are: var createFilteredListItemsWithValues and if(filter(listItemValues))
You filter function will always return false because you're checking if a String value equals a boolean value.
!(
listItemValues &&
typeof listItemValues.FileRef === "string" &&
listItemValues.FileRef.split("/")[4]
)
Is a boolean, while
currentBillCyclePath.split("/")[8];
is a string.
I am working in a javascript function that takes all of the id's from a HTML table and sends each iteration of a loop and sends the info to a PLSQL procedure to update. I concat a number on each id to make each one unique. If I add an alert in the loop and click through one by one it works. If I let it go on its own with no alert it skips some iterations. Is there something that I am doing wrong?
function process_update() {
var nDataCount = document.getElementById("v_nDataCount").value;
var p_cc_no = document.getElementById("p_cc_no").value;
var p_orient = document.getElementById("p_orient").value;
var p_ot = document.getElementById("p_ot").value;
var p_buy = document.getElementById("p_buy").value;
var x = 0;
if (nDataCount == 0) {
x = 0;
} else {
x = 1;
}
for (i = nDataCount; i >= x; i--) {
var p_pc_no = ("p_pc_no[" + i + "]");
var p_pc_no2 = document.getElementById(p_pc_no).value;
var p_tm_name = ("p_tm_name[" + i + "]");
var p_tm_name2 = document.getElementById(p_tm_name).value;
var p_tm_no = ("p_tm_no[" + i + "]");
var p_tm_no2 = document.getElementById("p_tm_no").value;
var p_status = ("p_status[" + i + "]");
var p_status2 = document.getElementById(p_status).value;
var p_hrs_per_week = ("p_hrs_per_week[" + i + "]");
var p_hrs_per_week2 = document.getElementById(p_hrs_per_week).value;
var p_shift = ("p_shift[" + i + "]");
var p_shift2 = document.getElementById(p_shift).value;
var p_open = ("p_open[" + i + "]");
var p_open2 = document.getElementById(p_open).value;
var p_vacant = ("p_vacant[" + i + "]");
var p_vacant2 = document.getElementById(p_vacant).value;
var p_comments = ("p_comments[" + i + "]");
var p_comments2 = document.getElementById(p_comments).value;
var p_delete = ("p_delete[" + i + "]");
var p_delete2 = document.getElementById(p_delete).value;
window.location.href = "https://server.server.com/db/schema.package.p_process2?p_cc_no=" + p_cc_no + "&p_pc_no=" + p_pc_no2 + "&p_tm_name=" + p_tm_name2 + "&p_tm_no=" + p_tm_no2 + "&p_status=" + p_status2 + "&p_hrs_per_week=" + p_hrs_per_week2 + "&p_shift=" + p_shift2 + "&p_open=" + p_open2 + "&p_vacant=" + p_vacant2 + "&p_comments=" + p_comments2 + "&p_delete=" + p_delete2 + "&p_orient=" + p_orient + "&p_ot=" + p_ot + "&p_buy=" + p_buy + "";
}
Try the below code. I am using an AJAX GET request within the loop with request params, so as to not change the interface as much as possible. It uses only plain JS since I am not sure if you have jquery.
The actual changes start from line 48. Of course, I could test this code only in a limited way, so it might have possible bugs (please let me know). Also this can be possibly refined further, but as a quick fix it should do.
A word of caution: This could make a lot of calls in quick succession. So if you have too many loop iterations you might end up bringing down the server. Use wisely! :-) There should be some kind of batching to avoid this, but that will need the call interface to be changed.
Lines 48-61: I am creating a plain JS object out of all your parameters. The key is parameter name, value is the value to be passed.
Line 63: Here I am defining a self-invoking function, which makes the AJAX call in its body. This way, even though AJAX is asynchronous in nature, it will run in sync with the for loop outside.
Line 64-66: I am serializing the object created in the loop, into query parameters.
Lines 68,69: Framing the URL to which request will be made.
Lines 71-77: Actually making the request. This is just boilerplate AJAX-invoking code you can find anywhere (jQuery would've made life so much simpler :-)).
function process_update(){
var nDataCount = document.getElementById("v_nDataCount").value;
var p_cc_no = document.getElementById("p_cc_no").value;
var p_orient = document.getElementById("p_orient").value;
var p_ot = document.getElementById("p_ot").value;
var p_buy = document.getElementById("p_buy").value;
var x = 0;
if (nDataCount == 0) {
x = 0;
} else {
x = 1;
}
for (i = nDataCount; i >= x; i--) {
var p_pc_no = ("p_pc_no[" + i + "]");
var p_pc_no2 = document.getElementById(p_pc_no).value;
var p_tm_name = ("p_tm_name[" + i + "]");
var p_tm_name2 = document.getElementById(p_tm_name).value;
var p_tm_no = ("p_tm_no[" + i + "]");
var p_tm_no2 = document.getElementById("p_tm_no").value;
var p_status = ("p_status[" + i + "]");
var p_status2 = document.getElementById(p_status).value;
var p_hrs_per_week = ("p_hrs_per_week[" + i + "]");
var p_hrs_per_week2 = document.getElementById(p_hrs_per_week).value;
var p_shift = ("p_shift[" + i + "]");
var p_shift2 = document.getElementById(p_shift).value;
var p_open = ("p_open[" + i + "]");
var p_open2 = document.getElementById(p_open).value;
var p_vacant = ("p_vacant[" + i + "]");
var p_vacant2 = document.getElementById(p_vacant).value;
var p_comments = ("p_comments[" + i + "]");
var p_comments2 = document.getElementById(p_comments).value;
var p_delete = ("p_delete[" + i + "]");
var p_delete2 = document.getElementById(p_delete).value;
var dataObj = {p_cc_no:p_cc_no,
p_pc_no:p_pc_no2,
p_tm_name:p_tm_name2,
p_tm_no:p_tm_no2,
p_status:p_status2,
p_hrs_per_week:p_hrs_per_week2,
p_shift:p_shift2,
p_open:p_open2,
p_vacant:p_vacant2,
p_comments:p_comments2,
p_delete:p_delete2,
p_orient:p_orient,
p_ot:p_ot,
p_buy:p_buy};
(function(paramsObj){
var paramsStr = Object.keys(paramsObj).map(function(key) {
return key + '=' + paramsObj[key];
}).join('&');
var url = "https://server.server.com/db/schema.package.p_process2?";
url += paramsStr;
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('GET', url);
xhr.onreadystatechange = function() {
if (xhr.readyState>3 && xhr.status==200) {/*Handle Call Success*/};
};
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send();
})(dataObj);
}
}
I'm trying to create a weather app, sending Ajax requests to OpenWeatherMap. I've got an error in w.getWeatherFunc, when I'm giving the function sendRequest the parameter of w.weather and then giving the same parameter to the function displayFunc, which I'm calling next.
Here is what I've got in the console:
Uncaught TypeError: Cannot read property 'weather' of undefined
at displayFunc (weather.js:46)
at weather.js:78
How can I fix this and make it work?
function Weather () {
var w = this;
var weatherUrl = 'http://api.openweathermap.org/data/2.5/weather?';
var appid = '&appid=c0a7816b2acba9dbfb70977a1e537369';
var googleUrl = 'https://maps.googleapis.com/maps/api/geocode/json?address=';
var googleKey = '&key=AIzaSyBHBjF5lDpw2tSXVJ6A1ra-RKT90ek5bvQ';
w.demo = document.getElementById('demo');
w.place = document.getElementById('place');
w.description = document.getElementById('description');
w.temp = document.getElementById('temp');
w.humidity = document.getElementById('humidity');
w.getWeather = document.getElementById('getWeather');
w.addCityBtn = document.getElementById('addCity');
w.rmCityBtn = document.getElementById('rmCity');
w.icon = document.getElementById('icon');
w.wind = document.getElementById('wind');
w.time = document.getElementById('time');
w.lat = null;
w.lon = null;
w.cityArray = [];
w.weather = null;
function sendRequest (url, data) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.send();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
data = JSON.parse(request.responseText);
console.log(data);
return data;
} else {
console.log(request.status + ': ' + request.statusText);
}
}
}
function displayFunc (obj) {
console.log('obj ' + obj);
w.icon.src = 'http://openweathermap.org/img/w/' + obj.weather[0].icon + '.png';
var timeNow = new Date();
var hours = timeNow.getHours();
var minutes = timeNow.getMinutes() < 10 ? '0' + timeNow.getMinutes() : timeNow.getMinutes();
w.time.innerHTML = hours + ':' + minutes;
w.place.innerHTML = 'Place: ' + obj.name;
w.description.innerHTML = "Weather: " + obj.weather[0].description;
w.temp.innerHTML = "Temperature: " + w.convertToCels(obj.main.temp) + "°C";
w.humidity.innerHTML = "Humidity: " + obj.main.humidity + '%';
w.wind.innerHTML = 'Wind: ' + obj.wind.speed + ' meter/sec';
}
w.convertToCels = function(temp) {
var tempC = Math.round(temp - 273.15);
return tempC;
}
w.getWeatherFunc = function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(location){
w.lat = location.coords.latitude;
w.lon = location.coords.longitude;
var url = weatherUrl + 'lat=' + w.lat + '&lon=' + w.lon + appid;
var result = sendRequest(url, w.weather);
console.log(result);
displayFunc(result);
});
} else {
alert('Browser could not find your current location');
}
}
w.addCityBtn.onclick = function() {
var newCity = prompt('Please insert city', 'Kiev');
var gUrl = googleUrl + newCity + googleKey;
var newCityWeather = null;
sendRequest(url, newCityWeather);
var location = newCityWeather.results[0].geometry.location;
var newUrl = weatherUrl + 'lat=' + location.lat + '&lon=' + location.lng + appid;
sendRequest(newUrl, w.weather);
displayFunc(newCity);
w.cityArray.push(newCity);
}
window.onload = w.getWeatherFunc;
setInterval(function() {
w.getWeatherFunc();
}, 900000);
}
Your ajax return returns into the browsers engine. As its async you need to create a callback:
function sendRequest(url,data,callback){
//if the data was received
callback(data);
}
Use like this
sendRequest("yoururl",data,function(data){
displayFunc(data);
});
The first time you pass the obj to the function it will save it one scope higher. after that, if you don;t pass the object the one you saved earlier will be used.
var objBkp;
function displayFunc (obj) {
if(undefined === obj) obj = objBkp;
else objBkp = obj;
// rest of code here
}
In your sendRequest you are passing only the value of w.weather, not its reference. JavaScript doesn't pass variables by value or by reference, but by sharing. So if you want to give the value to your variable you should do this inside your function sendRequest:
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
w.weather = JSON.parse(request.responseText);
console.log(data);
return data;
} else {
console.log(request.status + ': ' + request.statusText);
}
}
Also, if you are using the attributes, you don't have to pass them in the function as arguments. Besides that fact, it would be good if you also create get() and set()
What does the console.log(result); in getWeatherFunc gives you?
The problem as I see it is that in the displayFunc the parameter passed is undefined.
This is very early in my Node and JavaScript learning. Ideally, what I am attempting to do is create a small module querying a specific type of rest endpoint and returning a specific feature based on an attribute query. The module is correctly logging out the result, but I am struggling to get the .findById function to return this result. Although aware it has something to do with how the callbacks are working, I am not experienced enough to be able to sort it out yet. Any help, advice and direction towards explaning the solution is greatly appreciated.
// import modules
var restler = require('restler');
// utility for padding zeros so the queries work
function padZeros(number, size) {
var string = number + "";
while (string.length < size) string = "0" + string;
return string;
}
// create feature service object
var FeatureService = function (url, fields) {
// save the parameters
this.restEndpoint = url;
this.fields = fields;
var self = this;
this.findById = function (idField, value, padZeroLength) {
var options = {
query: {
where: idField + '=\'' + padZeros(value, padZeroLength) + '\'',
outFields: this.fields,
f: "pjson"
},
parsers: 'parsers.json'
};
var url = this.restEndpoint + '/query';
restler.get(url, options).on('complete', function(result){
if (result instanceof Error){
console.log('Error:', result.message);
} else {
console.log(result); // this log result works
self.feature = JSON.parse(result);
}
});
return self.feature;
};
};
var restEndpoint = 'http://services.arcgis.com/SgB3dZDkkUxpEHxu/ArcGIS/rest/services/aw_accesses_20140712b/FeatureServer/1';
var fields = 'nameRiver,nameSection,nameSectionCommon,difficulty,diffMax';
var putins = new FeatureService(restEndpoint, fields);
var feature = putins.findById('awid_string', 1143, 8);
console.log(feature); // this log result does not
//console.log('River: ' + feature.attributes.nameRiver);
//console.log('Section: ' + feature.attributes.nameSection + ' (' + feature.attributes.nameSectionCommon + ')');
//console.log('Difficulty: ' + feature.attributes.difficulty);
So, I sorted out how to insert a callback from a previous thread. It appears it is just passed in as a variable and called with expected parameters. However, I now wonder if there is a better way to accept parameters, possibly in the form of options. Any advice in this regard?
// import modules
var restler = require('restler');
// utility for padding zeros so the queries work
function padZeros(number, size) {
var string = number + "";
while (string.length < size) string = "0" + string;
return string;
}
// create feature service object
var FeatureService = function (url, fields) {
// save the parameters
this.restEndpoint = url;
this.fields = fields;
var self = this;
// find and return single feature by a unique value
this.findById = function (idField, value, padZeroLength, callback) {
// query options for
var options = {
query: {
where: idField + '=\'' + padZeros(value, padZeroLength) + '\'',
outFields: this.fields,
f: "pjson"
},
parsers: 'parsers.json'
};
var url = this.restEndpoint + '/query';
restler.get(url, options)
.on('success', function(data, response){
var dataObj = JSON.parse(data).features[0];
console.log(dataObj);
callback(dataObj);
})
.on('fail', function(data, response){
console.log('Error:', data.message);
});
return self.feature;
};
};
var restEndpoint = 'http://services.arcgis.com/SgB3dZDkkUxpEHxu/ArcGIS/rest/services/aw_accesses_20140712b/FeatureServer/1';
var fields = 'nameRiver,nameSection,nameSectionCommon,difficulty,diffMax';
var putins = new FeatureService(restEndpoint, fields);
putins.findById('awid_string', 1143, 8, function(dataObject){
console.log('River: ' + dataObject.attributes.nameRiver);
console.log('Section: ' + dataObject.attributes.nameSection + ' (' + dataObject.attributes.nameSectionCommon + ')');
console.log('Difficulty: ' + dataObject.attributes.difficulty);
});