var latLon = "40.8,-77.8"; //Lat/lon
var cityCode = ""; //City code
var cityName = "";
var latLongCityCodeURL = ("http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=" + weatherKey + "&q=" + latLon);
//Current Conditions Vars
var ccWeatherText = ""; //Text for weather at location
var ccTemp = 0; //Degrees Farenheit
var ccIcon = 0; //weather icon number https://developer.accuweather.com/weather-icons
var ccURL = "test"; //URL for get
//12 hour forecast Conditions Vars
//5 day forecast conditions Vars
//Get city code
http.get(latLongCityCodeURL, (resp) => {
var that = this;
resp.on("data", (chunk) => {
var result = JSON.parse(chunk);
var cityCode = result.Key;
var cityName = result.EnglishName;
console.log(cityCode + " " + cityName);
that.cityName = cityName;
that.cityCode = cityCode;
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
console.log(cityCode + " " + cityName);
So my issue is, I am making an http request using require('http'), what I want to do is parse the data and store it in my global variables so that I can use them for other requests. I have tried using var that=this and I have tried just assigning my global variables to the data. I am not sure how to do it, i just keep getting undefined. I know it has something to do with ASYNC and also something to do with the scope. Please help
You can save your result to a variable at various levels of scope.. just remember that most i/o calls in Node.js are asynchronous.
Here's an example:
var latLon = "40.8,-77.8"; //Lat/lon
var cityCode = ""; //City code
var cityName = "";
var latLongCityCodeURL = ("http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=" + weatherKey + "&q=" + latLon);
//Current Conditions Vars
var ccWeatherText = ""; //Text for weather at location
var ccTemp = 0; //Degrees Farenheit
var ccIcon = 0; //weather icon number https://developer.accuweather.com/weather-icons
var ccURL = "test"; //URL for get
var savedResult = null;
//Get city code
http.get(latLongCityCodeURL, (resp) => {
var jsonData = '';
resp.on("data", (chunk) => {
jsonData += chunk;
});
resp.on("end", () => {
savedResult = JSON.parse(jsonData);
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
// Display saved result once available.
setTimeout(displaySavedResult, 2000);
function displaySavedResult() {
if (!savedResult) {
console.log('Last result is null!');
} else {
console.log('Last result: City Code: ' + savedResult.Key + " Name" + savedResult.EnglishName);
console.log('Last result (all properties): ', JSON.stringify(savedResult, null, 2));
}
}
You can use Promise to make http request, here is code that may help you
const httpGet = url => {
return new Promise((resolve, reject) => {
http.get(url, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
body = JSON.parse(body);
} catch (err) {
reject(new Error(err));
}
resolve({
cityCode: body.Key,
cityName: body.EnglishName
});
});
}).on('error', reject);
});
};
httpGet(latLongCityCodeURL).then(data => {
console.log(data.cityCode + " " + data.cityName);
}).catch(err => console.log('Got error ', err));
var latLon = "40.8,-77.8";
var latLongCityCodeURL = ("http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=" + weatherKey + "&q=" + latLon);
//Current Conditions Vars
var ccWeatherText = ""; //Text for weather at location
var ccTemp = 0; //Degrees Farenheit
var ccIcon = 0; //weather icon number https://developer.accuweather.com/weather-icons
var ccURL = "test"; //URL for get
//12 hour forecast Conditions Vars
//5 day forecast conditions Vars
//Get city code
function getCityCode(latLongCityCodeURL){
return new Promise((resolve, reject) => {
http.get(latLongCityCodeURL, (resp) => {
resp.on("data", (chunk) => {
var result = JSON.parse(chunk);
var cityCode = result.Key;
var cityName = result.EnglishName;
resolve({cityCode, cityName});
});
}).on("error", (err) => {
reject(err);
console.log("Error: " + err.message);
});
})
}
getCityCode(latLongCityCodeURL)
.then((result) => {
console.log(result.cityCode, result.cityName)
}).catch((err) => console.log(err))
Another way is to use async-await API interface which is supported in node 8.
async function getCityCode(latLongCityCodeURL){
const result = await http.get(latLongCityCodeURL, (resp) => {
resp.on("data", (chunk) => {
var result = JSON.parse(chunk);
var cityCode = result.Key;
var cityName = result.EnglishName;
return {cityCode, cityName};
});
}).on("error", (err) => {
return err;
console.log("Error: " + err.message);
});
return result;
}
getCityCode(latLongCityCodeURL)
.then((res) => {
console.log(res.cityCode, res.cityName)
})
Your code block runs in a synchronized way and console.log part hits just after http.get call. The thing is http.get is an async function and its callback part will be called future ticks of NodeJS when your response has arrived.
var http = require('http');
var latLon = "40.8,-77.8"; //Lat/lon
var cityCode = ""; //City code
var cityName = "";
var latLongCityCodeURL = ("http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=" + "fmKWSgaG5EAA0diCP2lSREEOYG6PC5q9" + "&q=" + latLon);
var that;
//Current Conditions Vars
var ccWeatherText = ""; //Text for weather at location
var ccTemp = 0; //Degrees Farenheit
var ccIcon = 0; //weather icon number https://developer.accuweather.com/weather-icons
var ccURL = "test"; //URL for get
//12 hour forecast Conditions Vars
//5 day forecast conditions Vars
//Get city code
getWeather = url => {
return new Promise((resolve, reject) => {
http.get(url, res => {
let body = '';
res.on('data', chunk => resolve(JSON.parse(chunk)));
}).on('error', reject);
});
};
getWeather(latLongCityCodeURL).then( weather => {
console.log(weather.Key + " " + weather.EnglishName);
})
You must wait for the response, then send the other requests or log into. The scope isn't really the issue here, it's the order of operations that you're missing. You define a variable, then wait for a HTTP request, meanwhile you're immediately logging a value, then the request finishes (or times out or other error), and you can log again the value - at which point you see data.
In other words, to fix the issue, other requests must be made from within a function of resp.on("end", which says when you've finished getting all data chunks
And by "within", the code can still be in a separate method, outside those brackets, but you must call that particular function from within that response body.
You should pass such asynchronous returned data through parameter variables, not update some external, global state in most cases
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 array of objects with addresses with the four field, field1 is the current location(store) and the rest are address info.
My problem is how do I make sure that I have an result with key:value (store:cords) at the end so I know which store has which cords.
This is the code I have written so far:
var NodeGeocoder = require('node-geocoder')
const csv=require('csvtojson')
const csvFilePath='location.csv'
csv({noheader:true})
.fromFile(csvFilePath)
.then((jsonObj)=>{
convertAddressesToCoords(jsonObj, function(coords){
console.log('converting finished.');
console.log(coords.length);
console.log(coords);
});
});
function convertAddressesToCoords(addresses, callback) {
var coords = [];
var options = {
provider: 'google',
httpAdapter: 'https',
apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxx',
formatter: null
};
var geocoder = NodeGeocoder(options);
for(var i = 0; i < addresses.length; i++) {
currAddress = addresses[i].field2 + ' ' + addresses[i].field3 + ' ' + addresses[i].field4;
geocoder.geocode(currAddress, function(err, results) {
coords.push(results);
if(coords.length == addresses.length) {
if( typeof callback == 'function' ) {
callback(coords);
}
}
});
}
}
Current code works fine, I can get for each address the coordinates but the problem is at the end I dont know which store has which coords, since the google geocoding cal is asynchronous so I cannot find a way how to make this work.
Looping over an array and then calling a callback at the end will work, but its hard to read and can cause some problems, therefore i would use Promises here:
const getCoords = geocoder => address => new Promise((resolve, reject) => {
address = [address.field2, address.field3, address.field4].join(" ");
geocoder.geocode(address, function(err, coords) {
if(err) reject(err) else resolve({ address, coords });
});
});
So now to get a certain coordinate, you can just do:
getCoords(NodeGeocoder(options))({field2: "Unknown Location"})
.then(({ address, coords }) => console.log(adress + " is at " + coords));
Now gettig that from your csv is easy too:
csv({noheader:true})
.fromFile(csvFilePath)
.then(data => Promise.all(data.map(getCoords(NodeGeocoder(options)))
.then(positions => {
//...
})
And positions is now an array of coord / address pairs.
If you want to go with your code instead, just add
const currAddress = addresses[i].field2 + ' ' + addresses[i].field3 + ' ' + addresses[i].field4;
to keep it in the closure, then you can push it to the results:
coords.push({ coords: results, address: currAddress });
Use Promise. Something like
function convertAddressesToCoords(addresses, callback) {
var coords = [];
var options = {
provider: 'google',
httpAdapter: 'https',
apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxx',
formatter: null
};
var geocoder = NodeGeocoder(options);
return Promise.all(
adresses.map(
(address)=>new Promise((resolve,reject)=>{
geocoder.geocode(addresses[i].field2 +
' ' + addresses[i].field3 +
' ' + addresses[i].field4,
function(err, results) {
if (err) {
return reject(err);
}
return resolve(results);
}
);
})
)
);
}
Then you can use it like
csv({noheader:true})
.fromFile(csvFilePath)
.then((jsonObj)=>convertAddressesToCoords(addresses))
.then((coords)=>console.log(coords))
I'm trying to get a report from MOZ API to work. Unfortunately this is the response I'm getting:
{
"status" : "503",
"error_message" : "Service Temporarily Unavailable"
}
This is my code:
function MozCall(callback) {
var mozCall = '';
// Set your expires times for several minutes into the future.
// An expires time excessively far in the future will not be honored by the Mozscape API.
// Divide the result of Date.now() by 1000 to make sure your result is in seconds.
var expires = Math.floor(Date.now() / 1000) + 300;
var accessId = 'mozscape-b3978adbec';
var secretKey = '5f95cb81c5f121904d012488e28e05e';
// `bitFlagExampleValues` is a list of bitFlag values as strings that we'll
// loop over and sum together using helper function: `sumColumnValues`
var bitFlagExampleValues = [
'144115188075855872',
'68719476736',
'34359738368',
];
var sumColumnValues = function(bitFlagValues) {
return bitFlagValues.reduce(function(accu, bitFlag) {
var accuValBig = new bigJs(accu);
var bitFlagBig = new bigJs(bitFlag);
var bigSum = accuValBig.plus(bitFlagBig);
return bigSum.toString();
}, 0);
};
// 'cols' is the sum of the bit flags representing each field you want returned.
// Learn more here: https://moz.com/help/guides/moz-api/mozscape/api-reference/url-metrics
// returns "144115291155070976"
var cols = sumColumnValues(bitFlagExampleValues);
// Put each parameter on a new line.
var stringToSign = accessId + '\n' + expires;
//create the hmac hash and Base64-encode it.
var signature = crypto
.createHmac('sha1', secretKey)
.update(stringToSign)
.digest('base64');
//URL-encode the result of the above.
signature = encodeURIComponent(signature);
var postData = JSON.stringify(['www.moz.com']);
var options = {
hostname: 'lsapi.seomoz.com',
path: '/linkscape/url-metrics/?Cols=' +
cols +
'&AccessID=' +
accessId +
'&Expires=' +
expires +
'&Signature=' +
signature,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': postData.length,
},
};
var responseData = '';
var req = http.request(options, function(response) {
response.setEncoding('utf8');
response.on('data', function(chunk) {
responseData += chunk;
});
response.on('end', function() {
console.log(responseData);
});
});
req.end();
}
// if (req.user.isPremium == false) {
let freeReportCalls = [MozCall];
// Free user - Single report
// let website = req.body.website0;
async.parallel(freeReportCalls, function(err, results) {
if (err) {
console.log(err);
} else {
console.log(results);
res.render('reports/report', {
title: 'Report',
// bw: JSON.parse(results[0]),
// ps: JSON.parse(results[0]),
// bw: results[1],
// al: results[2],
// moz: results[2],
user: req.user,
});
}
});
I'm using basically an example code from the moz docs (found here: https://github.com/seomoz/SEOmozAPISamples/blob/master/javascript/node/batching-urls-sample.js). I'm not sure what the issue is. I waited since yesterday but the problem persists so it's not temporary.
Edit: Breaking the API key results in a different issue, so I'm guessing it's connecting to Moz servers.
Turns out the example code didn't work for me. Instead of passing options I just passed the whole url and this worked. Like this:
var postData = JSON.stringify([website, 'www.google.com']);
console.log(postData);
var options = {
hostname: 'lsapi.seomoz.com',
path: '/linkscape/url-metrics/' + postData + '?Cols=' +
'4' + '&AccessID=' + accessId +
'&Expires=' + expires + '&Signature=' + signature,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': postData.length
}
};
var responseData = "";
// 'http://lsapi.seomoz.com/linkscape/url-metrics/google.com?Cols=4&AccessID='+accessId+'&Expires='+expires+'&Signature='+signature
var req = http.get(`http://lsapi.seomoz.com/linkscape/url-metrics/${website}?Cols=${cols}&AccessID=${accessId}&Expires=${expires}&Signature=${signature}`,function(response) {
response.setEncoding('utf8');
response.on('data', function(chunk) {
responseData += chunk;
});
response.on('end', function() {
console.log(responseData);
});
});
req.end();
Website is a variable passed to the router through a view.
In trying to get a hang of node.js asynchronous coding style, I decided to write a program that would read a text file containing a bunch of URLS to download and download each file. I started out writing a function to download just one file (which works fine), but having trouble extending the logic to download multiple files.
Here's the code:
var http = require("http"),
fs = require("fs"),
input = process.argv[2],
folder = "C:/Users/Wiz/Downloads/",
regex = /(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/,
urls = null,
url = "",
filename = "";
fs.readFile(input, "utf8", function(e, data) {
console.log("Reading file: " + input);
if (e) console.log("Got error:" + e.message);
urls = data.split("\n");
for (var i = urls.length; i--;) {
url = urls[i];
if (!url.match(regex)) continue;
filename = folder + url.substring(url.lastIndexOf('/') + 1);
downloadQueue.addItem(url, filename);
}
});
var downloadQueue = {
queue: [],
addItem: function(p_sSrc, p_sDest) {
this.queue.push({
src: p_sSrc,
dest: p_sDest
});
if (this.queue.length === 1) {
this.getNext();
}
},
getNext: function() {
var l_oItem = this.queue[0];
http.get(l_oItem.src, function(response) {
console.log("Downloading: " + l_oItem.dest);
var file = fs.createWriteStream(l_oItem.dest);
response.on("end", function() {
file.end();
console.log("Download complete.");
downloadQueue.removeItem();
}).on("error", function(error) {
console.log("Error: " + error.message);
fs.unlink(l_oItem.dest);
});
response.pipe(file);
});
},
removeItem: function() {
this.queue.splice(0, 1);
if (this.queue.length != 0) {
this.getNext();
} else {
console.log("All items downloaded");
}
}
};
How do I structure the code so that the completion of the first download can signal the initiation of the next one. Please note that this exercise is just for learning purposes, to understand how asynchronous coding works. In practice, I'm sure there are much better tools out there to download multiple files.
Try simple at first, it look like you copy paste codes and quite don't understand what they do.
Do a simple loop, that get the url, and print something.
var http = require('http');
URL = require('url').parse('http://www.timeapi.org/utc/now?format=%25F%20%25T%20-%20%25N')
URL['headers'] = {'User-Agent': 'Hello World'}
// launch 20 queries asynchronously
for(var i = 0; i < 20; i++) {
(function(i) {
console.log('Query ' + i + ' started');
var req = http.request(URL, function(res) {
console.log('Query ' + i + ' status: ' + res.statusCode + ' - ' + res.statusMessage);
res.on('data', function(content){
console.log('Query ' + i + ' ended - ' + content);
});
});
req.on('error', function(err) {
console.log('Query ' + i + ' return error: ' + err.message);
});
req.end();
})(i);
}
All the urls will be fetched asynchronously. You can observe that the response does not arrive in order, but are still processed correctly.
The difficulty with async is not to do the things is parallel, because you just write like a single task, and execute multiple time. It becomes complicated when you need for instance to wait for all tasks to finished before continuing. And for that, have a look at promises
Here is what I started out with. Figuring that each download was invoked asynchronously, they would all be independent of each other.
var http = require("http"),
fs = require("fs"),
input = process.argv[2],
folder = "C:/Users/Wiz/Downloads/",
regex = /(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/,
urls = null,
url = "",
filename = "";
fs.readFile(input, "utf8",
function(e, data) {
console.log("Reading file: " + input);
if (e) console.log("Got error:" + e.message);
urls = data.split("\n");
for (var i = urls.length; i--;) {
url = urls[i];
if (!url.match(regex)) continue;
filename = folder + url.substring(url.lastIndexOf('/') + 1);
http.get(url, function(response) {
var file = fs.createWriteStream(filename);
response.on("end", function() {
file.end();
});
response.pipe(file);
})
}
});
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);
});