I am pretty sure that I know what the problem is with my code, but I am unsure how to fix it.
I have a google fusion table that i am querying to generate a menu that has radio buttons in it. A map that is a google fusion table visualized like a google map is also on the page.
When i hard code a couple radio buttons and click them it makes the items light up on the map based on the ID of the element. I using google.maps.event.addDomListener to make this magic work. So that works great.
Now i want to take it one step further and actually pull the data from a google fusion table so it shows the most up to date list of items i have in my table. So, I'm using jQuery and a $.get command to get the feed in jsonp. I'm outputting 2 columns of data and dynamically building radio buttons by attaching them with a innerHTML line -- attaching it to a div.
So, I'm thinking the problem has to do with the DOM, but i am not sure how to get the radio buttons to load in first and then load in the map so all is available to the maps events so clikcing the radio actually does something.
The question is what modifications do i need to make so my dynamic generated radio buttons will work with my google fusion map?
Here is my javascript code:
function initialize() {
var table = ########;
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(30.6, -108.1),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var layer = new google.maps.FusionTablesLayer();
filterMap(layer, table, map);
getData(table);
google.maps.event.addDomListener(document.getElementById('num1'),
'click', function() {
filterMap(layer, table, map);
});
google.maps.event.addDomListener(document.getElementById('num2'),
'click', function() {
filterMap(layer, table, map);
});
}
// Filter the map based on checkbox selection.
function filterMap(layer, table, map) {
var where = generateWhere();
if (where) {
if (!layer.getMap()) {
layer.setMap(map);
}
layer.setOptions({
query: {
select: "State",
from: table,
where: where
}
});
} else {
layer.setMap(null);
}
}
// Generate a where clause from the checkboxes. If no boxes
// are checked, return an empty string.
function generateWhere() {
var filter = [];
var bugs = document.getElementsByName('bug');
for (var i = 0, bug; bug = bugs[i]; i++) {
if (bug.checked) {
var BugName = bug.value.replace(/'/g, '\\\'');
filter.push("'" + BugName + "'");
}
}
var where = '';
if (filter.length) {
where = "'BugName' IN (" + filter.join(',') + ')';
}
return where;
}
// build the menu
function getData(table) {
var queryUrlHead = 'http://www.google.com/fusiontables/api/query?sql=';
var queryUrlTail = '&jsonCallback=?'; // ? could be a function name
// write your SQL as normal, then encode it
var query = "SELECT BugName, bugAbbr FROM " + table + " LIMIT 1";
var queryurl = encodeURI(queryUrlHead + query + queryUrlTail);
var jqxhr = $.get(queryurl, dataHandler, "jsonp");
}
function dataHandler(d) {
// get the actual data out of the JSON object
var data = d.table.rows;
var ftdata = ['<div>'];
for (var i = 0; i < data.length; i++) {
ftdata.push('<input type="radio" id="'+data[i][1]+'" value="'+data[i][0]+'" name="bug">'+data[i][0]+'');
}
ftdata.push('</div>');
document.getElementById('ft-data').innerHTML = ftdata.join('');
}
google.maps.event.addDomListener(window, 'load', getData);
google.maps.event.addDomListener(window, 'load', initialize);
This site had a bunch of example code.
http://csessig.wordpress.com/category/fusion-tables/
Related
I'm using Google Autocomplete and want to put street number + route value to the input field after selecting necessary location. I'm using this code
let options = { types: ['address'] };
let autocomplete = new google.maps.places.Autocomplete(element, options);
autocomplete.addListener('place_changed', function () {
let place = autocomplete.getPlace();
let components = new AutoCompleteAddressComponent(place.address_components).parse();
/* getStreet is returning address_components.street_number.short_name
and address_components.route.long_name */
let streetName = components.getStreet().trim();
$(element).val(streetName);
});
And how this code is working:
User it typing something in the input
Google is suggesting location from where users are selecting necessary one
Input is reflecting on the user action and putting data. For example 777 Brockton Avenue, Abington, MA, USA
After this place_changed is firing and 777 Brockton Avenue, Abington, MA, USA replacing to 777 Brockton Avenue
I don't like that 4-th point where users can see how data is replacing from long address to the short one.
Is there any way to show street number + route right after selecting location from the dropdown? I've tried to play with an Autocomplete method options by providing different types, but nothing helps me. I also need to get all data like country, state, city, post_code in the autocomplete.getPlace() object (I'm pre-filling these fields on the site).
I've found solution by using Google Places Autocomplete Service and completely redesign of the Autocomplete widget
Here is a source code if someone will try to implement this service:
registerGoogleAutoComplete = function(input) {
let options = { types: ['address'] };
const autocomplete = new google.maps.places.AutocompleteService();
// building container for the prediction list
const predictionList = this.predictionListMarkup(input);
$(input).parent().append(predictionList);
/* listening the input changing event and send data to the Google Service
to get prediction list */
input.addEventListener('input', function () {
// display list if something have
if (input.value) {
predictionList.style.display = 'block';
/* here is a main call of the getPlacePredictions where your input
value is sending to the Google Service
(input option of the getPlacePredictions method) */
autocomplete.getPlacePredictions({
input: input.value,
types: options.types,
}, function (predictions, status) {
self.displayPredictionSuggestions(predictions, status, predictionList, input);
});
} else {
// hide if not
predictionList.style.display = 'none';
}
});
}
/**
* #param autocompleteFormField
* #returns {HTMLUListElement}
*/
this.predictionListMarkup = function (autocompleteFormField) {
const predictionsWrapperDiv = document.createElement(`ul`);
predictionsWrapperDiv.classList.add(`pac-container`, `pac-logo`);
predictionsWrapperDiv.style.display = 'none';
predictionsWrapperDiv.style.width = autocompleteFormField.clientWidth + 'px';
return predictionsWrapperDiv;
};
this.displayPredictionSuggestions = function (predictions, status, predictionList, autocompleteFormField) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
predictionList.style.display = `none`;
return;
}
predictionList.innerHTML = '';
/* this is a list of all predictions from the Google API. Each prediction
is a default Place object of the Google. So you can parse `address_component` and pre-fill whatever you want */
for (let prediction of predictions) {
self.predictionBuilder(prediction, predictionList, autocompleteFormField);
}
// here you can bind all necessary events like keyDownPress, keyUpPress to control your prediction list more
}
// this is a each prediction element UI building function
this.predictionBuilder = function (prediction, predictionList, autocompleteFormField) {
// we are creating li item to the ul container
const predictionListItem = document.createElement(`li`);
predictionListItem.classList.add(`pac-item`);
let text = prediction.description;
/* prediction has an matched_substrings, using which you can make matched string words bold (as Google is doing it) */
if (prediction.matched_substrings.length > 0) {
let tmp = text;
prediction.matched_substrings.forEach(function (item) {
let substrText = tmp.substring(item.offset, item.length + item.offset);
text = text.replace(substrText, '<span class="pac-matched">' + substrText + '</span>');
})
}
let node = document.createElement('div');
node.innerHTML = text;
predictionListItem.appendChild(node);
/* add 'onClick' event listener to handle user selecting action
where you can act the same is `place_changed` event of the Autocomplete service */
predictionListItem.addEventListener(`click`, function () {
self.autocompleteServiceListener(prediction, predictionList, autocompleteFormField);
});
predictionList.appendChild(predictionListItem);
};
P.s: Later I'll try to write a small component/widget for this
I want to make an input with autocomplete use google places API. And this is my code:
var options = {
componentRestrictions: {
country: "de"
}
};
var place = '';
var locationAutocompleteOneWay = document.getElementById('locationAutocompleteOneWay');
var autocompleteLocationOneWay = new google.maps.places.Autocomplete(locationAutocompleteOneWay, options);
google.maps.event.addListener(autocompleteLocationOneWay, 'place_changed', function() {
place = autocompleteLocationOneWay.getPlace();
});
For more customize, I want to add some custom place result when I input in the textbox. Here my code and result:
setTimeout(function() {
$(".pac-container").append('<div id="areasearch" class="pac-item areasearch"><span class="pac-icon pac-icon-areas"></span><span class="pac-item-query"><span class="pac-matched"></span>Test place</span> <span>custom place</span></div>');
}, 500);
But I want when I click on the result, it make my input locationAutocompleteOneWay has had a value of the result. But I don't know how to make it. And I want it can apply for multi-input on the page. I use it by jQuery and AngularJS. All solution of Jquery and AngularJS is good for me. Thank in advanced.
What I found is that, if you load the custom locations you're adding with attributes that can be used to set the lat/lng (and anything else you need), then you can bind to the mousedown event to assign a custom place object to the autocomplete.
In my script, I have the following snippet adding an item to the autocompletes (this adds to all auto-complete elements on the page):
$(".pac-container").append('<div id="areasearch' + i + '" class="pac-item areasearch custom" val="' + PlaceName + '" lat="' + Latitude + '" lng="' + Longitude + '" style="display: none;"><span class="pac-icon pac-icon-areas"></span><span class="pac-item-query"><span class="pac-matched"></span>' + PlaceName + '</span> <span>' + LocationName + '</span></div>');
Using the classes pac-item and custom, I then bind as follows:
setTimeout(function () {
$("div.pac-item.custom").mousedown(function () {
setCustomLocation($(this));
})
}, 100);
And the custom location function is:
setCustomLocation = function (obj) {
$("#" + currInput).val($(obj).attr("val"));
var newObj = {};
newObj["geometry"] = {}
newObj["geometry"]["location"] = {}
newObj["geometry"]["location"]["lat"] = function () { return $(obj).attr("lat"); }
newObj["geometry"]["location"]["lng"] = function () { return $(obj).attr("lng"); }
currAutocomplete.set("place", newObj);
}
The first line sets the name into the active input field, and the rest sets the place object for the active autocomplete (both variables captured in other events). The only values I needed for the project was the geometry lat/lng pair, but if you need more, just load it with whatever values you need to retrieve from the parent.
I am loading markers from a database to display on a google map by this below. This is working fine however, I would like to implement the option of pressing a particular button somewhere else on the page, and then map would dynamically change to only show markers pertaining to what was clicked.
Basically, I would like to filter by the 'type' column in my database but still keep all types loaing by default. eg. Page loads, Map loads and displays all types, User clicks on a button which causes the map to only show markers that have type1 as the value in the db. Kind of like a toggle with a check box.
Any ideas of how to go ahead with this, I don't think reloading markers from the db is the most efficient way, can I simply just hide markers which have this property?
map = new google.maps.Map(document.getElementById("google_map"), googleMapOptions);
//Load Markers from the XML File, Check (map_process.php)
$.get("map_process.php", function (data) {
$(data).find("marker").each(function () {
var name = $(this).attr('name');
var address = '<p>'+ $(this).attr('address') +'</p>';
var type = $(this).attr('type');
var description ='<p>'+ $(this).attr('description') +'</p>';
var point = new google.maps.LatLng(parseFloat($(this).attr('lat')),parseFloat($(this).attr('lng')));
var icon1 = customIcons[type] || {};
create_marker(point, name, address, false, false, false, icon1.icon);//"http://sanwebe.com/assets/google-map-save-markers-db/icons/pin_blue.png");
});
});
You can't just hide some specific markers according to their tag or type, you have to hide/remove them all first and then add those that you need on your map
Here are the functions that you need:
var all_markers = [];
var show_markers = [];
function setMarkers(map) {
for (var i = 0; i < show_markers.length; i++) {
show_markers[i].setMap(map);
}
}
function showMarkers(type) {
setMarkers(null);
show_markers = []
for (var i = 0; i < all_markers.length; i++) {
if (all_markers[i].type == type){
show_markers.push(all_markers[i])
}
}
setMarkers(map);
}
Here is the idea: Load all your markers into the all_markers, on your first loading the markers show_markers must be equal to all_markers. Hitting the button for showing specific markers must trigger function showMarkers which will clear your map and reload just specific ones.
So I've created a google maps page with a bunch of markers generated from XML. The idea is that when you click on a marker a div will be generated that displays events information related to that marker. This all works fine but what I'm struggling with is now trying to attach an accordion to the events information. The code I have so far will show an accordion on the first marker you click on (can be any one and it returns the correct info, shows the div and has an accordion) but not on any subsequent marker clicks, even the same one for a second click.
I'm sure this must be a simple fix but I've tried a few variations (there are three attempts at the accordion that I have left in to show the different versions) and I am getting the same results.
Here is the code that binds the events to the markers as a google event listener..
function bindEvents(marker, id, venueName, website){
google.maps.event.addListener(marker, 'click', function(){
// TARGET and show eventsFeed on click
$('#eventsFeed').show(222);
var eventsList = document.getElementById('eventsList');
// ADDS styles to the events feed divs when created
// DECLARED here for the inclusion of the venueName & website as feedhead
// even when no events are present
var venueNameDiv = "<div class='venueNameFeed'>";
var webSiteDiv = "<a target='_blank' class='websiteInFeed' href='http://"+website+"'><span class='fa fa-home'></span></a>";
var titleInFeed = "<div class='"+id+" eventTitleFeed'>";
var accordDataWrap = "<h2 class='accordWrap>";
var eventInFeed = "<div class='eventDescFeed'>";
var dateInFeed = '<div class="eventDateFeed">';
var priceInFeed = "<div class='eventPriceFeed'>";
// CLOSE the divs after each entry
var divBrk = "</div>";
var closeAccordDataWrap = "</h2>";
var feedHead = venueNameDiv + venueName + divBrk;
// EMPTY array to line up matched events in
var eventsLine = [];
// CYCLE through eventsArray
for (var key in eventsArray){
var eventLoop = eventsArray[key];
// MATCH id to venue_id
var venue_id = eventLoop.venue_id;
if (venue_id == id){
// ONLY show events from todays date onward
var now = new Date();
var date = new Date(eventLoop.eventDATE);
// SET hours to 0 to ignore time part (always as 01:00:00 for event date?)
now.setHours(0,0,0,0);
if (date >= now){
//ADD all matched events to eventsLine array
eventsLine.push(titleInFeed + eventLoop.eventTitle + divBrk +
accordDataWrap + eventInFeed + eventLoop.event + divBrk +
dateInFeed + formatDate(eventLoop.eventDATE) + divBrk +
priceInFeed + "£" + eventLoop.price + divBrk + closeAccordDataWrap);
}
}
}
// TURNS the array into a string and replaces those damned, infernal commas!!
var outputString = eventsLine.toString().replace(/>,/g, '>');
// PUT the compiled array into the eventsFeed div (with venueName as title)
if (website==""){
eventsList.innerHTML = feedHead + outputString;
} else {
eventsList.innerHTML = feedHead + webSiteDiv + outputString;
}
// ADD the accordion
$(document).on('click', marker, function(){
$(eventsList).accordion({
header: "div."+id,
icons: null
})
})
// OR
$(eventsList).each(function(){
$(eventsList).accordion({
header: "div."+id,
icons: null
});
});
// OR
accordion(eventsList, id);
});
}
This third option calls a separate function which is defined as;
function accordion(placement,id){
$(placement).accordion({
header: "div."+id,
icons: null
});
}
As you can probably tell I'm pretty new to all of this so any help or advice with anything would be greatly appreciated! :)
Can you replace this code:
$(eventsList).each(function(){
$(eventsList).accordion({
header: "div."+id,
icons: null
});
});
with this code:
$(eventsList).each(function(){
$(this).accordion({
header: "div."+id,
icons: null
});
});
and try. Also it will be better if you can Create a fiddle for your code.
I have a Store Locator and every time I click on an anchor (such as Zoom Here, Directions, or Street View), the hash in the href takes me to the top of the page. How can I prevent this from happening? I tried looking through the Store Locator source, but it's minified and hard to figure out what is what. I also tried adding event delegation to anchors with class "action" but this didn't work either.
Main function
google.maps.event.addDomListener(window, 'load', function() {
var map = new google.maps.Map(document.getElementById('mappanel'), {
center: new google.maps.LatLng(56.102683, 10.452576),
zoom: 7,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var panelDiv = document.getElementById('searchpanel');
var data = new storeSource;
var view = new storeLocator.View(map, data, {
geolocation: false
});
new storeLocator.Panel(panelDiv, {
view: view
});
});
storeLocator class
/** #extends storeLocator.StaticDataFeed */
function storeSource() {
jQuery.extend(this, new storeLocator.StaticDataFeed);
var that = this;
jQuery.get('/components/com_maps/storeSource.csv', function(data) {
that.setStores(that.parse_(data));
});
}
/** #private */
storeSource.prototype.parse_ = function(csv) {
var stores = [];
var rows = csv.split('\r');
var headings = this.parseRow_(rows[0]);
for (var i = 1, row; row = rows[i]; i++) {
row = this.toObject_(headings, this.parseRow_(row));
if(row.adresse.length > 3) {
row.lat = row.lat.replace(",", ".");
row.lng = row.lng.replace(",", ".");
var position = new google.maps.LatLng(row.lat, row.lng);
var locality = this.join_([row.postnr, row.by], ', ');
var store = new storeLocator.Store(row.uid, position, null, {
title: row.navn,
address: this.join_([row.adresse, locality, row.land], '<br>'),
phone: row.tlfnr
});
stores.push(store);
}
}
return stores;
};
/** Joins elements of an array that are non-empty and non-null. */
storeSource.prototype.join_ = function(arr, sep) {
var parts = [];
for (var i = 0, ii = arr.length; i < ii; i++) {
arr[i] && parts.push(arr[i]);
}
return parts.join(sep);
};
/*** CSV parsing */
storeSource.prototype.parseRow_ = function(row) {
// Each row in the CSV file only has ; as delimiter
row = row.split(';');
return row;
};
/** Creates an object mapping headings to row elements. */
storeSource.prototype.toObject_ = function(headings, row) {
var result = {};
for (var i = 0, ii = row.length; i < ii; i++) {
result[headings[i]] = row[i];
}
return result;
};
Here's a link to the Store Locator library: http://storelocator.googlecode.com/git/index.html
That is the default behaviour in the browser for clicking on an <a> tag that has an href value of #. The # is reserved for jumping to sections on the page. As an easy example, if you have an <a> tag with an href of #movies, and a section on your page that has a name attribute that is also movies, then clicking on <a href="#movies"> will bring the user directly to the movies section of your page. If you simply have #, then the browser skips to the very top of the page, because you didn't specify a section name.
To prevent this behaviour, you need to do at least this:
$(".my-links").on( 'click', function( evt ) {
evt.preventDefault();
});
And you may also need to include another line like this (depending on your selector/setup):
$(".my-links").on( 'click', function( evt ) {
evt.preventDefault();
evt.stopPropagation();
});
preventDefault() will stop the default behaviour for a click on any element that matches the selector. See here.
stopPropagation() will stop the default event from bubbling up the DOM, so it doesn't get caught by any parent elements. See here.
Hope this helps