I'm setting up a custom google maps Polymer element called "locator-map" that uses polymer-jsonp to grab data from a google spreadsheet, take the response, and send it off to a custom "google-map" element to plot the markers on the map. I can't seem to figure out how to actually inject the data coming back from the polymer-jsonp element into my google-map element so that it can use it to construct the markers.
Here's my data source: https://spreadsheets.google.com/feeds/list/0Ao_YrKZEsc4AdGppeG1zaGotRDd0LUdIYk9tdW9VZnc/od6/public/values?alt=json-in-script
I followed directions here to set this up initially: http://www.html5rocks.com/en/tutorials/webcomponents/yeoman/
Code for my locator-map element:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/polymer-jsonp/polymer-jsonp.html">
<link rel="import" href="google-map.html">
<polymer-element name="locator-map" attributes="">
<template>
<style>
/* styles for the custom element itself - lowest specificity */
:host { display: block; }
google-map {
display:block;
height:600px;
}
</style>
<!-- Load Data with JSONP Endpoint (in this case Google Spreadsheets)
Format: https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script&callback=
Source: https://docs.google.com/spreadsheet/ccc?key=0AqZBbhllhMtHdFhFYnRlZk1zMzVZZU5WRnpLbzFYVFE&usp=sharing
-->
<polymer-jsonp auto url="https://spreadsheets.google.com/feeds/list/0Ao_YrKZEsc4AdGppeG1zaGotRDd0LUdIYk9tdW9VZnc/od6/public/values?alt=json-in-script&callback=" response="{{locations}}"></polymer-jsonp>
<ul>
<template repeat="{{location in locations.feed.entry}}">
<li>Name: {{location.gsx$name.$t}}
<ul><li>Lat: {{location.gsx$lat.$t}}</li><li>Long: {{location.gsx$lng.$t}}</li></ul>
</li>
</template>
</ul>
<!-- Load the Google Map -->
<google-map map="{{map}}" latitude="45.526158" longitude="-122.679394" zoom="14" markers="{{locations}}"></google-map>
</template>
<script>
Polymer('locator-map', {
// element is fully prepared
ready: function(){
},
// instance of the element is created
created: function() { },
// instance was inserted into the document
enteredView: function() { },
// instance was removed from the document
leftView: function() { },
// attribute added, removed or updated
attributeChanged: function(attrName, oldVal, newVal) { }
});
</script>
</polymer-element>
Code for my google-map element:
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="google-map" attributes="latitude longitude zoom showCenterMarker map markers">
<template>
<style>
:host {
position: relative;
}
#map {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
</style>
<div id="map"></div>
</template>
<script>
(function() {
var CALLBACK_NAME = 'polymer_google_map_callback';
var MAP_URL = 'https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places&sensor=false&callback=' + CALLBACK_NAME;
var pendingCallbacks = [];
var loading;
function loadMapApi(callback) {
if (window.google && window.google.maps) {
callback();
return;
}
if (!loading) {
loading = true;
window[CALLBACK_NAME] = mapApiLoaded.bind(this);
var s = document.createElement('script');
s.src = MAP_URL;
document.head.appendChild(s);
}
pendingCallbacks.push(callback);
}
function mapApiLoaded() {
delete window[CALLBACK_NAME];
pendingCallbacks.forEach(function(callback) {
callback();
});
}
Polymer('google-map', {
latitude: '37.77493',
longitude: '-122.41942',
zoom: 10,
showCenterMarker: false,
observe: {
latitude: 'updateCenter',
longitude: 'updateCenter'
},
ready: function() {
loadMapApi(this.mapReady.bind(this));
},
created: function() {
},
enteredView: function() {
this.resize();
},
mapReady: function() {
// Create the Map
this.map = new google.maps.Map(this.$.map, {
zoom: this.zoom,
center: new google.maps.LatLng(this.latitude, this.longitude)
});
// Show Center Marker
this.showCenterMarkerChanged();
// Add Markers (if any supplied)
this.addMarkers();
// Fire the Map Ready Event
this.fire('google-map-ready');
},
resize: function() {
if (this.map) {
google.maps.event.trigger(this.map, 'resize');
this.updateCenter();
}
},
updateCenter: function() {
if (!this.map) {
return;
}
this.map.setCenter(
new google.maps.LatLng(this.latitude, this.longitude));
this.showCenterMarkerChanged();
},
zoomChanged: function() {
if (this.map) {
this.map.setZoom(Number(this.zoom));
}
},
showCenterMarkerChanged: function() {
if (!this.map) {
return;
}
if (!this.centerMarker && this.showCenterMarker) {
this.centerMarker = new google.maps.Marker({
map: this.map
});
}
if (this.centerMarker) {
this.centerMarker.setPosition(this.map.getCenter());
this.centerMarker.setMap(this.showCenterMarker ? this.map : null);
}
},
/*
* Add Markers
* Adds markers to the map. Expects an array of objects specifying the location information via name, lat and lng properties.
*
* @author erikharper
*/
addMarkers: function()
{
console.log("Markers: ");
console.log(this.markers);
// Get the Map instance
var map = this.map;
if(this.markers.isArray())
{
// Create each Marker on the Map
this.markers.forEach(function(marker){
// Create a LatLng object
var markerLatLng = new google.maps.LatLng(marker.lat, marker.lng);
// Create the Marker object and add it to the map via the map property
new google.maps.Marker({
map: map,
position: markerLatLng,
title: marker.name
});
});
}
}
});
})();
</script>
</polymer-element>
On my console I get a "this.markers is null". What am I doing wrong?
You must use these methods when mutating an array to ensure that any elements watching the array (via observers, computed properties, or data bindings) are kept in sync. Every Polymer element has the following array mutation methods available: push( path , item1 , [..., itemN ]) pop( path )
Double-curly brackets ( } ) support both upward and downward data flow.
You have markers="{{locations}}"
, which is the pure JSON response from the polymer-jsonp
component. I had to transform the data and parse the lat/lng first:
var markers = [];
markers.push({
lat: parseFloat(entry.gsx$lat.$t),
lng: parseFloat(entry.gsx$lng.$t),
name: entry.gsx$name.$t
});
this.markers = markers;
The way I approached was to reuse the existing Polymer google-map
element: http://jsbin.com/wowuledo/6/edit
The important bit is that when the this.markers
array changes, markersChanged
gets called, which in turn calls your addMarkers
(which I modified):
markersChanged: function() {
this.addMarkers();
},
addMarkers: function() {
this.markers.forEach(function(marker) {
var marker = new google.maps.Marker({
map: this.map,
position: new google.maps.LatLng(marker.lat, marker.lng),
title: marker.name
});
}.bind(this));
}
If you must create an additional element to add your own properties/methods to, why not inherit from google-maps
?
<polymer-element name="google-map-with-markers" extends="google-map" attributes="markers">
This way, you get all the functionality from google-maps
, but can data-bind to the markers
published property:
<google-map-with-markers latitude="45.526158" longitude="-122.679394" zoom="14" markers="{{markers}}"></google-map-with-markers>
Try: http://jsbin.com/renuyifu/1/edit
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With