Reputation: 29
I have been playing with Leaflet recently and integrated it within a WordPress custom post type. I added a field to the custom post type for a city. It is then encoded as JavaScript and sent to Mapbox for the coordinates. The coordinates then are sent to a function which displays the markers. That part works great. The problem I am having is getting the titles to loop through correctly and displaying in the popup dialog. When I look at the source code I see that both the name and city are being encoded correctly. Code is below. Thanks!
// Loops through CPT and puts both city and name into array
// TODO: Rename hometown to something more relevant
while ($loop->have_posts()) : $loop->the_post();
$post_meta = get_post_meta($post->ID, 'hometown', true);
$title = get_the_title($post->ID);
if ( !empty ( $post_meta ) || !empty ( $title ) ) {
$hometown[] = array(
'city' => $post_meta,
'name' => $title
);
}
endwhile;
<script>
var hometown = <?php echo wp_json_encode($hometown); ?>;
var map = L.map('map').setView([40, 0], 2);
L.mapbox.accessToken = 'myToken';
var geocoder = L.mapbox.geocoder('mapbox.places');
for ( var i = 0; i < hometown.length; i++ )
{
geocoder.query(hometown[i].city, showLoc);
}
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=myToken', {
maxZoom: 18,
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="http://mapbox.com">Mapbox</a>',
id: 'mapbox.streets'
}).addTo(map);
function showLoc(err, data) {
L.marker([data.latlng[0], data.latlng[1]], 2)
.bindPopup(hometown[0].name)
.addTo ( map );
}
</script>
Upvotes: 1
Views: 1429
Reputation: 28638
For example say, we've got the following array:
var homes = [{
name: 'Jane Doe',
city: 'Denver, Colorado'
},{
name: 'John Doe',
city: 'Houston, Texas'
}];
And we're going to iterate over the array's items and query each city property from the Mapbox's geocoder service:
for (var i = 0; i < homes.length; i++) {
geocoder.query(homes[i].city, callback);
}
That will in fact execute the following in this order:
geocoder.query('Denver, Colorado', callback);
geocoder.query('Houston, Texas', callback);
When these requests are complete it will execute the callback
method for each query:
function callback (err, data) {
// do stuff
}
Problem is that the requests are asynchronous and we have no way of being sure that they will be completed in the same order as we requested them. So inside the callback
method we have no way of directly knowing which item the result is from:
function callback (err, data) {
// Who's data is this?
}
Luckily the data
object supplied by the callback
method holds the original query in the data.results.query
property:
function callback (err, data) {
console.log(data.results.query);
}
That would log ['denver', 'colorado']
or ['houston', 'texas']
to your console depending on which query it's from. Now you can search your homes
array for the city and return the name:
function callback (err, data) {
// join the query array so we get the same string as we've queried
var city = data.results.query.join(', ');
// iterate over the homes array
for (var i = 0; i < homes.length; i++) {
// compare cities in lowercase (result returns in lowercase)
if (homes[i].city.toLowerCase() === city) {
// found match, do stuff
}
}
}
For your solution it would look something like this:
function callback (err, data) {
var city = data.results.query.join(', ');
for (var i = 0; i < homes.length; i++) {
if (homes[i].city.toLowerCase() === city) {
new L.Marker([data.latlng[0], data.latlng[1]])
.bindPopup(homes[i].name)
.addTo(map);
}
}
}
You can try it out here: http://jsfiddle.net/73hg2L4y/ (use your own token)
Hope that helps, good luck!
Note: you will run into trouble as soon as you've got two names with the same city, so it's best you make sure that all addresses are unique.
Upvotes: 2