PlacesService's text search not consistent with Autocomplete - javascript

We're seeing an issue where the PlacesService's textSearch is not returning any results for the "Strood Station Car Park, Rochester", whereas the Autocomplete is. I've created this JS Fiddle that shows the demonstrates this behavior: http://jsfiddle.net/anero/b5jh56gy/6/
Is there a way to have a consistent result set for both API calls?
var client = new google.maps.places.PlacesService($("#google-attributions")[0]);
var query = "Strood Station Car Park, Rochester";
var textSearchRequest = {
query: query
};
client.textSearch(textSearchRequest, function (response, status) {
if (status === google.maps.GeocoderStatus.OK && response.length > 0) {
alert('Found place!');
} else {
alert('Did not find place!');
}
});

Related

searchBox Google Maps with pagination

So what I am trying to do is implement Google Maps with a search box. Currently, the search box retrieves 20 of the top places based on the search result.
What I noticed is there is no pagination with this. Such as if I type in “pizza”, it will give me the top 20 results in the current location bounds. But when I use the google.maps.places.PlacesService(map) textSearch function to obtain a list of pizza searches, I get more than 20 results with pagination.
Is there a way to get pagination on your searchBox or use the textSearch function to provide pagination after you used searchBox?
What I have here is a snippet:
var canvas = element.find('div')[0];
var mapOptions = {
zoom: 5,
minZoom: 2,
};
var searchBox = new google.maps.places.SearchBox('pizza');
var placeService = new google.maps.places.PlacesService(map);
google.maps.event.addListener(searchBox, 'places_changed', locationChange);
function locationChange() {
var places = searchBox.getPlaces();
//Determine if there are additional places not provided by searchbox. Using text
var request = {
query: input.value,
};
var textSearchPlaces = placeService.textSearch(request, callback);
function callback(results, status, pagination) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var hi = places;
for (var i = 0; i < results.length; i++) {
var place = results[i];
}
}
}
if (places.length === 0) {
return;
}
};
As you can see this is not the most ideal solution to looking using a pagination as I would have to filter through the textSearchPlaces to see if those places are not duplicates of the searchBox results.
I also thought about just removing the searchBox and just going with the textSearch function but I realized I wouldn’t have the autoComplete function that provides suggestions that searchBox provides.
Most likely you are getting OVER_QUERY_LIMIT.
if (status == google.maps.places.PlacesServiceStatus.OK) {
Try queuing the details requests for after you have all the list completed, adding the same timeout logic to check for google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT on this line.
if (pagination.hasNextPage) {
//add all places to the list
setTimeout('pagination.nextPage()',2000);
} else {
createMarkers(placesList);
}
You should use google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT when using Places.

Looping Multiple Origins for Google Maps Direction Services

I'd like to find the shortest driving distance for multiple origins to multiple destinations. Say I have 5 customers and 10 stores, I'd like to find the shortest distance for each customer to a store.
My problem now is the 10 query per second limit on the google direction service. For each customer it takes less than 1 second to finish querying the API, so I will reach the query limit for each customer.
I tried to implement a delay between each customer, but the callback function from the google direction service is not blocked...
// A function to calculate the route between our current position and some desired end point.
function calcRoute(end, callback) {
var request = {
origin: currentPosition,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
callback(response);
} else {
size--;
}
});
}
// Stores a routing result from the API in our global array for routes.
function storeResult(data) {
routeResults.push(data);
if (routeResults.length === size) {
findShortest();
}
}
// Goes through all routes stored and finds which one is the shortest. It then
// sets the shortest route on the map for the user to see.
function findShortest() {
var i = routeResults.length;
var shortestIndex = 0;
var shortestLength = routeResults[0].routes[0].legs[0].distance.value;
while (i--) {
if (routeResults[i].routes[0].legs[0].distance.value < shortestLength) {
shortestIndex = i;
shortestLength = routeResults[i].routes[0].legs[0].distance.value;
}
}
directionsDisplay.setDirections(routeResults[shortestIndex]);
}
Is there a way to block the callback after each iteration? Or is there another way to do this?
The below code should do the job for you.
// A function to calculate the route between our current position and some desired end point.
function calcRoute(end, callback) {
var request = {
origin: currentPosition,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
callback(response);
}
//Handle the limit of 10 queries per sec
else if (status === google.maps.DirectionsStatus.OVER_QUERY_LIMIT) {
setTimeout(function () {
calcRoute(end, callback);
}, 1100);
}
else {
// a result could not found due to any one of the following errors:
//UNKNOWN_ERROR or REQUEST_DENIED or INVALID_REQUEST or MAX_WAYPOINTS_EXCEEDED
size--;
}
});
}
// Stores a routing result from the API in our global array for routes.
function storeResult(data) {
routeResults.push(data);
if (routeResults.length === size) {
findShortest();
}
}
// Goes through all routes stored and finds which one is the shortest. It then
// sets the shortest route on the map for the user to see.
function findShortest() {
var i = routeResults.length;
var shortestIndex = 0;
var shortestLength = routeResults[0].routes[0].legs[0].distance.value;
while (i--) {
if (routeResults[i].routes[0].legs[0].distance.value < shortestLength) {
shortestIndex = i;
shortestLength = routeResults[i].routes[0].legs[0].distance.value;
}
}
directionsDisplay.setDirections(routeResults[shortestIndex]);
}

Parse Cloud Code: Logic Branching in Promises

I'm trying to write a Parse.com Cloud Code function to accomplish the following workflow:
User submits a value.
Cloud code function checks to see if that value matches any objects of type code.
If not, the function returns a "not found" value.
If so, the object of type code is assumed to have a pointer to an object of type item.
Then, code.item is checked to see whether it has a pointer to an object of type alert.
If not, the function returns a "not found" value.
If code.item.alert does exist, then I want to fetch the full alert object, including pointers which may or may not exist, up to 2 layers deep.
As I begin writing the code for this function, I can get it working to the point of checking to see whether the code exists and, if so, whether code.item.alert also exists.
This is where the problem arises. As it currently stands, in the working version of my function, the alert item that is returned is only the class type and objectId. I understand why that is happening, and I am trying to write code to populate the object before returning it, but I am failing in that attempt.
Here's the code that is working so far (but only returning the alert object's shell):
Parse.Cloud.define("alertLookup", function (request, response) {
Parse.Cloud.useMasterKey();
var codeQuery = new Parse.Query("code");
codeQuery.equalTo("value", request.params.code);
codeQuery.include("item");
codeQuery.find().then(function (codes) {
if (codes.length === 0) {
response.success("no item");
} else {
var code = codes[0];
var item = code.get("item");
var alert = item.get("alert");
if (alert === null || alert === undefined) {
response.success("no item");
} else {
response.success(alert);
}
}
}, function (error) {
response.error(error);
});
});
Here's what I have tried that is failing with an error code of 141:
Parse.Cloud.define("alertLookup", function (request, response) {
Parse.Cloud.useMasterKey();
var codeQuery = new Parse.Query("code");
codeQuery.equalTo("value", request.params.code);
codeQuery.include("item");
codeQuery.find().then(function (codes) {
if (codes.length === 0) {
response.success("no item");
} else {
var code = codes[0];
var item = code.get("item");
var alert = item.get("alert");
if (alert === null || alert === undefined) {
response.success("no item");
} else {
return alert.fetch();
}
}
}).then(function (a) {
response.success(a);
}, function (error) {
response.error(error);
});
});
Why won't the fetch() call work properly? When I insert console.log() statements, although alert is non-null, return alert.fetch(); does not ever seem to be called. At least, the response.success(a); line is never called. Why not?
Try this instead while chaining Promises:
codeQuery.find().then(function (codes) {
if (codes.length != 0) {
var code = codes[0];
var item = code.get("item");
var alert = item.get("alert");
if (alert != null && alert != undefined) {
var alertObj = new Parse.Object("alert"); // alert class ???
alertObj.id = alert.id;
return alertObj.fetch();
}
}
// return a Promise for no items
return Parse.Promise.as("no item");
}).then(function (a) {
response.success(a);
}, function (error) {
response.error(error);
});

Azure mobile service - reading from two tables and return custom response object

I am writing Azure Mobile Service (AMS) API with JavaScript backend named customertickets and in the .get function I am attempting to read values from two tables in my AMS.
The two tables are 'User' and 'Ticket' and I am attempting to retrieve all tickets based on the passed parameter (phonenumber) and return some statistical data. Additionally, I am injecting a custom return value item.spname when looping through the tickets if the ticket satisfy a certain condition (item.parsedjsondata.SPId is not null or empty).
Here is the complete code (ctrl+F 'THIS DOES NOT WORK!'):
//Get ticket info by customer phonenumber
exports.get = function(request, response) {
var phonenumber = request.query.phonenumber;
var activeTicketsCounter = 0;
var completedTicketsCounter = 0;
var canceledTicketCounter = 0;
var needCustomerRatingTicketCounter = 0;
var includeCounterData = request.query.includeCounterData;
console.log("customertickets/get phonenumber: " + phonenumber);
request.service.tables.getTable('Ticket').read({
//SEE: http://stackoverflow.com/questions/24406110/how-to-get-system-properties-createdat-version-in-javascript-backend-of-azu
systemProperties: ['__createdAt', '__updatedAt'],
success: function(result) {
//No ticket is found
if (result.length === 0) {
console.log("customertickets/get: no ticket found");
response.send(statusCodes.NOT_FOUND, { message: "customertickets/get: no ticket is found" });
}
//return tickets after filtration based on the customer phonenumber
else {
console.log("customertickets/get: ticket found");
var filteredResults = [];
result.forEach(function(item) {
//only tickets with matched phonen number
if (JSON.parse(item.jsondata).customerPhonenumber == phonenumber) {
console.log(item);
//Adding parsed jsondata to item
item.parsedjsondata = JSON.parse(item.jsondata);
//Adding the name of the assigned spid; only if spid is not null ie. ticket is already assinged
if (item.parsedjsondata.SPId) {
console.log("SPID", item.parsedjsondata.SPId);
console.log("customerId", item.parsedjsondata.customerId);
//This works as expected
item.spid = item.parsedjsondata.SPId;
request.service.tables.getTable('User').where({ id: item.parsedjsondata.SPId.toString(), usertype: "200" }).read({
success: function(userResults) {
console.log('result', userResults[0]);
//Does not exist; return NOT FOUND as sp name!
if (userResults.length === 0) {
//This wroks fine and logs the expected result
console.log("customertickets/get: not SPname found", item.parsedjsondata.SPId);
//THIS DOES NOT WORK!
item.spname = "Service Provider Name Not Found";
}
//Record exists; return it
else {
//This wroks fine and logs the expected result
console.log("retrieved spname", JSON.parse(userResults[0].userjsondata).businessData.businessname.ar);
//THIS DOES NOT WORK!
item.spname = JSON.parse(userResults[0].userjsondata).businessData.businessname.ar;
}
}
});
}
//ActiveTicketsCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_ToBeAssigned"
|| item.parsedjsondata.ticketStatus == "TicketStatus_IsAssigned"
|| item.parsedjsondata.ticketStatus == "TicketStatus_InProgress"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_CustomerNotReachable"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_OutOfScope"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_CustomerCanceled"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_PriceDisagreement") {
activeTicketsCounter++;
}
//needCustomerRatingTicketCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_Completed_No_Customer_Rating") {
needCustomerRatingTicketCounter++;
}
//CompletedTicketsCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_Completed_And_Customer_Rated") {
completedTicketsCounter++;
}
//canceledTicketCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_CanceledByB8akAgent") {
canceledTicketCounter++;
}
//Testing: it works!
item.testing = "Testing Something!";
console.log("item.spname before push:", item.spname);
//pushing the found item to the list of results
filteredResults.push(item);
}
});
console.log("includeCounterData: " + includeCounterData);
if (includeCounterData == true) {
//After the loop, add the counters to the filteredresults to be returned
filteredResults.push({
activeTickets: activeTicketsCounter,
pendingCustomerRatingTickets: needCustomerRatingTicketCounter,
completedTickets: completedTicketsCounter,
canceledTickets: canceledTicketCounter
});
}
response.send(statusCodes.OK, filteredResults);
}
}
});
};
My main issue is that item.spname is never assigned a value and does not get returned in the response. I can see that the assigned value of item.spname which is JSON.parse(userResults[0].userjsondata).businessData.businessname.ar logs successfully in the AMS log but it does not get returned in the response.
The problem you have is that you're not waiting for the result of the many calls to
request.service.tables.getTable('User').where(...).read(...
to arrive before sending the response back to the client. Remember that almost everything in the node.js / JavaScript backend is asynchronous. When you call read on the User table, it won't wait for the result to arrive before executing the next statement - instead, it will queue the operation so that when the response is available, it will be executed.
To fix this you'll need to make all read calls to the users table, and only after you've got all the callbacks is when you can call response.send.

Update Google Places API results using javascript

I'm using Google Places API to get location details using javascript.
var request = {
input: request.term,
componentRestrictions: {country: 'us'},
types: ['geocode']};
service.getPlacePredictions(request, function (predictions, status) {
if (status != 'OK') {
return;
}
response($.map(predictions, function (prediction, i) {
var cty_st = '';
var pred_terms_lnt = prediction.terms.length;
if(pred_terms_lnt >= 3){
cty_st = prediction.terms[pred_terms_lnt - 3].value+', '+prediction.terms[pred_terms_lnt - 2].value;
}
else if(pred_terms_lnt >= 2){
cty_st = prediction.terms[pred_terms_lnt - 2].value;
}
else{
cty_st = prediction.description.replace(", United States", "");
}
return {
label: cty_st,
value: cty_st,
ref: prediction.reference,
id: prediction.id
}
}));
});
I want to show only city and state code from the results fetched and when I search for a location I'm getting duplicate city, state coder in the results. I want to remove these duplicates from the results. How to do that?
From the above results you can see last two results have same city and state code. I want to show only once.
Instead of types: ['geocode'] use types: ['(cities)']

Categories