Correct way of calling a javascript function - javascript

I am trying to extend the google maps marker example from the this website by adding the extraction of the country name.
Since google maps returns an array with details to each address, I need to iterate over the array to find the entry e.g. for "country". Since I would like to reuse the piece of code, I create a function.
But I am not sure how to call this function (here call find(components, item)) correctly.
I do not get any return from the find function. How do I call the find function correctly from within the select function?
*Could there be a different mistake why I get an empty return?*
Thank you for your thoughts and suggestions!
$(document).ready(function() {
initialize();
$(function() {
$("#address").autocomplete({
//This bit uses the geocoder to fetch address values
source: function(request, response) {
geocoder.geocode( {'address': request.term }, function(results, status) {
response($.map(results, function(item) {
return {
label: item.formatted_address,
value: item.formatted_address,
components: item.address_components,
latitude: item.geometry.location.lat(),
longitude: item.geometry.location.lng()
}
}));
})
},
// address_component selection
find: function(components, item) {
for(var j=0;j < components.length; j++){
for(var k=0; k < components[j].types.length; k++){
if(components[j].types[k] == "country"){
return components[j].long_name;
}
}
}
},
//This bit is executed upon selection of an address
select: function(event, ui) {
$("#latitude").val(ui.item.latitude);
$("#longitude").val(ui.item.longitude);
$("#country").val(this.find(ui.item.components, "country"));
var location = new google.maps.LatLng(ui.item.latitude, ui.item.longitude);
marker.setPosition(location);
map.setCenter(location);
}
});
});

The find() function is defined in the autocomplete options object.
If you want to access your find function you'll have to define it outside the autocomplete options or to get a pointer to it :
var find = $(event.target).data("autocomplete").options.find;
This is because jQuery changes the context of functions with the element that is attached to the listener.

Related

JS, Passing an argument to callback function (Bing maps)

Working with this example from Bing Maps V8
This line kicks off the map search: geocodeQuery("New York, NY");
This code fragment contains the callback function (which places the pin on the map):
var searchRequest = {
where: query,
callback: function (r) {
//Add the first result to the map and zoom into it.
if (r && r.results && r.results.length > 0) {
var pin = new Microsoft.Maps.Pushpin(r.results[0].location);
map.entities.push(pin);
map.setView({ bounds: r.results[0].bestView });
}
},
errorCallback: function (e) {
//If there is an error, alert the user about it.
alert("No results found.");
}
};
If I want to execute multiple searches, I can write:
geocodeQuery("New York, NY");
geocodeQuery("Queens, NY");
Now I have 2 pins on the map.
Next step: if I want to label the pins I'd extend the 'new pushpin code':
var pin = new Microsoft.Maps.Pushpin(r.results[0].location,
{
title: 'Queens',
text: '2'
});
Question:
The pins are placed by the callback function. Since I want each pin to have different text, how do I tweak this sample code so that I can pass new parameters to the callback function?
You would need to add an argument to the geocodeQuery function (maybe called title) and use that when you create the pin in the callback. Then you could simply call geocodeQuery("Queens, NY", "Queens")
function geocodeQuery(query, title) {
//If search manager is not defined, load the search module.
if (!searchManager) {
//Create an instance of the search manager and call the geocodeQuery function again.
Microsoft.Maps.loadModule('Microsoft.Maps.Search', function () {
searchManager = new Microsoft.Maps.Search.SearchManager(map);
geocodeQuery(query, title);
});
} else {
var searchRequest = {
where: query,
callback: function (r) {
//Add the first result to the map and zoom into it.
if (r && r.results && r.results.length > 0) {
var pin = new Microsoft.Maps.Pushpin(r.results[0].location, {
title: title,
text: '2'
});
map.entities.push(pin);
map.setView({ bounds: r.results[0].bestView });
}
},
errorCallback: function (e) {
//If there is an error, alert the user about it.
alert("No results found.");
}
};
//Make the geocode request.
searchManager.geocode(searchRequest);
}
}

Can't find any examples of google.maps.places.PlacesService() and getting errors

Can't find any examples of google.maps.places.PlacesServices() that searches from an input field with component restrictions, just like autocomplete. Google site only has reference material, no examples
I have this below but getting an error saying
TypeError: Cannot read property 'innerHTML' of undefined
and
TypeError: Cannot read property 'findPlaceFromQuery' of null
findLocationFromPlaces() {
this.placesService = new google.maps.places.PlacesService(this.cityInput);
const request = {
query: 'San Francisco',
fields: ['photos', 'formatted_address', 'name', 'rating', 'opening_hours', 'geometry']
};
this.placesService.findPlaceFromQuery(request
// {
// types: ['(cities)']
// // componentRestrictions: { country: this.countrySelected },
// // types: ['geocode'] // 'establishment' / 'address' / 'geocode'
// }
,
(results, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
}
else {
}
}
);
}
My "this.cityInput" is
#ViewChild('city') cityInput: HTMLDivElement;
<input appGooglePlaces id="city" (onSelect)="setAddress($event)" (keydown.Tab)="onTabAway($event)" (focusout)="focusOutFunction($event)" (input)="onLocationChange($event)" [ngClass]="{'is-invalid': registerForm.get('city').errors && registerForm.get('city').touched}"
formControlName="city" class="form-control google-place-input" [placeholder]="placeholder">
The Places service is used for place searches. It cannot behave like the Autocomplete service does. Furthermore, you cannot pass componentRestrictions to findPlaceFromQuery(). This method takes 3 parameters only: query, fields and the optional locationBias (which biases but does not restrict the area to search).
The documentation for Find Place from Query can be found here, and here's a working example.
If you also wish to implement Autocomplete functionality and e.g. restrict results to a specific country, please use the actual Autocomplete service.
Edit for mapless options:
Find place from query
function findLocationFromPlaces() {
let placesService = new google.maps.places.PlacesService(document.getElementById("map")); // i.e. <div id="map"></div>
const request = {
query: 'San Francisco',
fields: ['photos', 'formatted_address', 'name', 'rating', 'opening_hours', 'geometry']
};
placesService.findPlaceFromQuery(request, function(results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
console.log(results[0].formatted_address) // San Francisco, CA, USA
}
else {
console.log("doesn't work");
}
});
}
Autocomplete in address form (full example here) + country restriction
function initAutocomplete() {
// Create the autocomplete object, restricting the search predictions to
// geographical location types.
autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autocomplete'), {types: ['geocode'], componentRestrictions: {country: 'us'}});
// Avoid paying for data that you don't need by restricting the set of
// place fields that are returned to just the address components.
autocomplete.setFields(['address_component']);
// When the user selects an address from the drop-down, populate the
// address fields in the form.
autocomplete.addListener('place_changed', fillInAddress);
}
function fillInAddress() {
// Get the place details from the autocomplete object.
var place = autocomplete.getPlace();
for (var component in componentForm) {
document.getElementById(component).value = '';
document.getElementById(component).disabled = false;
}
// Get each component of the address from the place details,
// and then fill-in the corresponding field on the form.
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType).value = val;
}
}
}
Find Place web service (documentation here)
https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=San%20Francisco&inputtype=textquery&fields=photos,formatted_address,name,rating,opening_hours,geometry&key=YOUR_API_KEY
Autocomplete web service (documentation here) + country restriction
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=San+Francisco&types=geocode&components=country:us&key=YOUR_API_KEY
Hope this clarifies your question!

over_query_limit javascript v3

In my app I am trying to get a Region (city) to store in my Location model along with lngLat and address.
The thing is that for new locations it would be easy as when I would create I would do that. For old locations I wrote this bit of code
function geocodeLatLng(geocoder, latlngStr, callback) {
var latlng = { lat: parseFloat(latlngStr.split(',')[0]), lng: parseFloat(latlngStr.split(',')[1]) };
var city;
geocoder.geocode({ 'location': latlng }, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
var address = results[0].address_components;
for (var p = address.length - 1; p >= 0; p--) {
if (address[p].types.indexOf("locality") != -1) {
console.log(address[p].long_name);
city = address[p].long_name;
callback(city);
}
}
}
});
}
And I am calling it like this
self.getRegion = function () {
for (var i = 0; i < self.rawLocations().length; i++) {
var location = self.rawLocations()[i];
setTimeout(
geocodeLatLng(geocoder, location.systemRepresentation(), function (res) {
}), 250);// End of setTimeOut Function - 250 being a quarter of a second.
}
}
The issue is that I get over_query_limit after 5 calls. I will store the Location it self in the database for now I would have to do this to fix the old locations.
Any headers?
Google maps javascript library has a maximum calls per second as well as an hourly rate, are you trying to geocode at a rate faster than their per second rate possibly?
5 does seem low as their own documents inform users that it is 50 per second (https://developers.google.com/maps/documentation/geocoding/usage-limits)
Also have you signed up for a key and are using it? This could make a difference (if the google account is old as signed up for maps API sometime you can use the system without a key)

How do I get a value back from a custom dojo module?

I'm working through the process of modulization on an app that I have written. This works with spatial location
I'm using an event to query for the user's lat / lon position for use inside the application. My calling snippet is below (button click starts it up)
<script>
require([
'dojo/dom',
'dojo/_base/array',
'demo/testModule',
'esri/SpatialReference',
'esri/geometry/Point'
], function (
dom,
arrayUtils,
testModule,
SpatialReference,
Point
) {
//Here is the button click listener
$('#whereAmIButton').click(function () {
var spatialRef = new esri.SpatialReference({ 'wkid': 4326 });
//variable I want to set to a returned geometry.
var myGeom;
//This runs but I'm missing the boat on the return of a value
testModule.findUserLocPT(spatialRef);
//var myModule = new testModule(); //not a constructor
});
});
</script>
Here is the custom module. It logs the information to the console for the user's location. But I want to return the value for setting the 'myGeom' variable.
define(['dojo/_base/declare','dojo/_base/lang','dojo/dom',
'esri/geometry/Point','esri/SpatialReference'], function (
declare, lang, dom, Point, SpatialReference) {
return {
findUserLocPT: function (spatialRef) {
var geom;
var location_timeout = setTimeout("geolocFail()", 5000);
navigator.geolocation.getCurrentPosition(function (position) {
clearTimeout(location_timeout);
var lat = position.coords.latitude;
var lon = position.coords.longitude;
setTimeout(function () {
geom = new Point(lon, lat, spatialRef);
//console.log writes out the geom but that isnt what I am after
console.log(geom);
//I want to return this value
return geom;
}, 500);
});
function geolocFail() {
console.log("GeoLocation Failure");
}
}
}//end of the return
});
Any help would be welcome. I can by reference back change textual/html values on the document but am not getting things back as a variable.
Andy
Ok, I don't know if this is the 'best' answer but I have one now.
I added a global variable inside the 'test.html' page
<script>
var theGeom; //This is the variable
require([
'dojo/dom',
here is where I am setting the value of this variable for use in the original dojo 'require' code block. This is coming from the 'testModule.js'
setTimeout(function () {
geom = new Point(lon, lat, spatialRef);
theGeom = geom; //Here is the feedback of the value to the global variable.
return myGeom;
}, 500);
$('#whereAmIButton').click(function () {
var spatialRef = new esri.SpatialReference({'wkid':4326});
testModule.findUserLocPT(spatialRef);
setTimeout(function () {
console.log(theGeom); //here is the value set and ready to use
},2000);
});
I'm not sure if this is the best way. If you have something better please let me know.
Andy

Handling no results in jquery autocomplete

Hey I'm trying to return a message when there are no results for the users current query! i know i need to tap into the keyup event, but it looks like the plugin is using it
This question is really out of date, anyways I'm working with the new jQuery UI 1.8.16, autocomplete is now pretty different:http://jqueryui.com/demos/autocomplete/#default
Anyways if you're trying to the do the same thing as the question asks, there is no more parse function, as far as I know there is no function that is called with the search results.
The way I managed to pull this off is by overriding the autocomplete's filter function - Note: this will affect all your autocompletes
$.ui.autocomplete.filter = function(array, term) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
var aryMatches = $.grep( array, function(value) {
return matcher.test(value.label || value.value || value);
});
if (aryMatches.length == 0){
aryMatches.push({
label: '<span class="info" style="font-style: italic;">no match found</span>',
value: null
});
}
return aryMatches;
};
The function is slightly modified from the source, the grep call is the same, but if there are no results I add an object with a value of null, then I override the select calls to check for a null value.
This gives you an effect where if you keep typing and no matches are found you get the 'no matches found' item in the dropdown, which is pretty cool.
To override the select calls see jQuery UI Autocomplete disable Select & Close events
$(this).data('autocomplete').menu.options.selected = function(oEvent, ui){
if ($(ui.item).data('item.autocomplete').value != null){
//your code here - remember to call close on your autocomplete after
}
};
Since I use this on all my autocompletes on a page, make sure you check if value is null first! Before you try to reference keys that aren't there.
You could try supplying a parse option (function to handle data parsing) and do what you need when no results are returned to parse.
This example assumes you're getting back an array of JSON objects that contain FullName and Address attributes.
$('#search').autocomplete( {
dataType: "json",
parse: function(data) {
var array = new Array();
if (!data || data.length == 0) {
// handle no data case specially
}
else {
for (var i = 0; i < data.length; ++i) {
var datum = data[i];
array[array.length] = {
data: datum,
value: data.FullName + ' ' + data.Address,
result: data.DisplayName
};
}
}
return array;
}
});
I'm using the following code for the same purpose (the message is shown in the autocomplete list):
success: function(data, status, xhr){
if(!data.length){
var result = [
{
label: 'There are no matches for your query: ' + response.term,
value: response.term
}
];
response(result);
}
else{
// normal response
}
}
You can also utilize the "response" event to examine this. Simple but powerful. http://api.jqueryui.com/autocomplete/#event-response
response: function (event, ui) {
if (ui.content.length == 0) {
//Display an alert or something similar since there are no results
}
},

Categories

Resources