MVC4 Knockout Googlemap binding error - google-maps

I'm trying to bind an address from my model to a marker on Google map.
The map should display the marker determined with the full address of the model. Beside the map, I would like to display the value for lat and lng of the marker. The user should be able to drag and drop the marker and the values of lat & lng should update. I use jsFiddle as start referenced from this website but I cannot quite get it to work.
I successfully created the map with a marker pointing to the address of the model. Unfortunately I'm get an error when adding knockout to bind it:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: lat is not defined;
Bindings value: value: lat
This is the view:
#model GoogleMapTest.Models.Restaurant
#{
ViewBag.Title = "Index";
}
<div id="panel">
<input id="address" value="">
<p data-bind="with: selectedPoint">
Name: <b>#Model.Name</b>
<br />
Lat: <span data-bind="text: lat"></span>
<br />
Long: <span data-bind="text: long"></span>
</p>
</div>
<div id="map-canvas"></div>
This is the script:
#section scripts {
<script type="text/javascript">
var geocoder;
var map;
var orignalLat;
var originalLong;
$(function () {
var stringAddress = '#Model.Address1' + ", " + '#Model.City' + ", " + '#Model.StateProv' + ", " + '#Model.Zip' + ", " + '#Model.Country';
$("#address").val(stringAddress);
geocoder = new google.maps.Geocoder();
var mapOptions = {
zoom: 16
}
google.maps.event.addDomListener(window, 'load', codeAddress(stringAddress));
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
});
function codeAddress(address) {
geocoder.geocode({ 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
orignalLat = results[0].geometry.location.lat();
originalLong = results[0].geometry.location.lng();
map.setCenter(results[0].geometry.location);
viewModel.selectedPoint(new point('', orignalLat, originalLong));
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
function point( name, lat, long) {
this.name = name;
this.lat = ko.observable(lat);
this.long = ko.observable(long);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, long),
title: name,
map: map,
draggable: true
});
//if you need the position while dragging
google.maps.event.addListener(marker, 'drag', function () {
var pos = marker.getPosition();
this.lat(pos.lat());
this.long(pos.lng());
}.bind(this));
//if you just need to update it when the user is done dragging
google.maps.event.addListener(marker, 'dragend', function () {
var pos = marker.getPosition();
this.lat(pos.lat());
this.long(pos.lng());
}.bind(this));
}
var viewModel = {
selectedPoint: ko.observable(new point('', 10, 10))
};
ko.applyBindings(viewModel);
</script>
}
Any help or suggestions would be greatly appreciated.
Edited for working solution...

Your viewModel consists of an array of points, but your markup binds directly to lat and lng properties that don't exist on the root viewModel. So that's why you are getting the error, but how to fix it is more interesting.
I'm actually not sure what you are trying to do and the fix is different based on that. Do you want ONE marker that displays when the user selects a point? Or do you want every point to have a marker on the map right from the beginning?
If you want markers for ALL points, change your markup to bind to all of them:
<p data-bind="foreach: points">
Name: <b>#Model.Name</b>
<br />
Lat: <span data-bind="text: lat"></span>
<br />
Long: <span data-bind="text: long"></span>
</p>
OR... If you want just one marker, I would first add a "selectedPoint" to your viewModel
var viewModel = {
selectedPoint: new point('', 0, 0),
points: (removed)
};
Then in your markup, bind the lat and lng on the selected point
<p data-bind="with: selectedPoint">
Name: <b>#Model.Name</b>
<br />
Lat: <span data-bind="text: lat"></span>
<br />
Long: <span data-bind="text: long"></span>
</p>

Related

Google map preview selected location on map

I would like to allow my user to pick a location as well as previewing searched location to pick location.
Problem
Am not able to integrate the search-box to preview the searched location.
Code I am using
<input type="text" id="search">
<div id="map"></div>
var map = document.getElementById('map');
var lp = new locationPicker(map, {
setCurrentPosition: true,
lat: -13.9867852,
lng: 33.77027889
}, {
zoom: 15 // You can set any google map options here, zoom defaults to 15
});
// Listen to button onclick event
confirmBtn.onclick = function () {
var location = lp.getMarkerPosition();
var location = location.lat + ',' + location.lng;
console.log(location);
};
google.maps.event.addListener(lp.map, 'idle', function (event) {
var location = lp.getMarkerPosition();
var location = location.lat + ',' + location.lng;
console.log(location);
});
How do i enable the input to search location and display it on the map
Edit, Have managed to enable search on the input but can't move the marker to the selected location
google.maps.event.addDomListener(window, 'load', initialize);
function initialize() {
var input = document.getElementById('search');
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.setComponentRestrictions({'country':['mw']});
autocomplete.addListener('place_changed', function () {
var place = autocomplete.getPlace();
/*
console.log(place.geometry['location'].lat());
console.log(place.geometry['location'].lng());
console.log(place.name);
console.log(place.formatted_address);
console.log(place.vicinity);
console.log(place.url);
console.log(place.address_components);*/
if(!place.geometry) {
return;
}
console.log(place);
});
}
Kindly check out this sample fiddle that have a search box and a map. When a user selects a place suggestion in the autocomplete input, the sample then calls the getPlace() method, and then it opens an info window to display place details.
You can create an infowindow to display some place details:
<input id="search" type="text" placeholder="Enter a location">
<div id="map"></div>
<div id="infowindow-content">
<img src="" width="16" height="16" id="place-icon">
<span id="place-name" class="title"></span><br>
<span id="place-address"></span>
</div>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initialize" async defer></script>
</body>
In the initialize() function, declare your infowindow and marker objects and then set the marker position and infowindow content in the place_changed listener which is called whenever the user selects an autocomplete address suggestion.
var map;
function initialize() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -13.9867852, lng: 33.77027889},
zoom: 15
});
var input = document.getElementById('search');
var autocomplete = new google.maps.places.Autocomplete(input);
// Set the data fields to return when the user selects a place.
autocomplete.setFields(
['address_components', 'geometry', 'icon', 'name']);
autocomplete.setComponentRestrictions({
'country': ['mw']
});
var infowindow = new google.maps.InfoWindow();
var infowindowContent = document.getElementById('infowindow-content');
infowindow.setContent(infowindowContent);
var marker = new google.maps.Marker({
map: map,
anchorPoint: new google.maps.Point(0, -29)
});
autocomplete.addListener('place_changed', function() {
infowindow.close();
marker.setVisible(false);
var place = autocomplete.getPlace();
if (!place.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert("No details available for input: '" + place.name + "'");
return;
}
// If the place has a geometry, then present it on a map.
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17); // Why 17? Because it looks good.
}
marker.setPosition(place.geometry.location);
marker.setVisible(true);
var address = '';
if (place.address_components) {
address = [
(place.address_components[0] && place.address_components[0].short_name || ''),
(place.address_components[1] && place.address_components[1].short_name || ''),
(place.address_components[2] && place.address_components[2].short_name || '')
].join(' ');
}
infowindowContent.children['place-icon'].src = place.icon;
infowindowContent.children['place-name'].textContent = place.name;
infowindowContent.children['place-address'].textContent = address;
infowindow.open(map, marker);
});
}
You can also check out this example from the public documentation.
Hope this helps!

Google Maps API - Get New Center Coordinates after map is moved

I'm using the Google Maps API to display a map, but I now need to capture the centre coordinators if the user moves the map. I'm after the new lat/long of the new centre of the map after it has been moved.
Looking at the Maps Events docs I can see a few options here:
center_changed
dragend
that I could potentially move. I've tried both but can't get the syntax right and not sure how to retrieve the centre lat/long. Here's my latest attempt
google.maps.event.addListener(map, 'dragend', function() {
var latitude = event.latLng.lat();
var longitude = event.latLng.lng();
console.log("current latitude is: "+latitude);
console.log("current longitude is: "+longitude);
});
but I get an error TypeError: undefined is not an object (evaluating 'event.latLng.lat') when this runs.
Can anyone tell me what the most approrpriate event to use here and how I can get the new centre co-ordinatates when the map has changed by the user dragging it.
If you want the center values when it changes, use the 'center_changed' event:
center_changed
Arguments: None
This event is fired when the map center property changes.
google.maps.event.addListener(map, "center_changed", function() {
var center = this.getCenter();
var latitude = center.lat();
var longitude = center.lng();
console.log("current latitude is: " + latitude);
console.log("current longitude is: " + longitude);
});
proof of concept fiddle
code snippet:
function initMap() {
var myLatlng = {
lat: -25.363,
lng: 131.044
};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatlng
});
google.maps.event.addListener(map, "center_changed", function() {
var center = this.getCenter();
var latitude = center.lat();
var longitude = center.lng();
console.log("current latitude is: " + latitude);
console.log("current longitude is: " + longitude);
});
}
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>

How to get the latitude and longitude in this code

Here i am using google map API ,user search their area means i want to get the latitude and logidute and stored in my database, i don't know how to do ,i am new in google map integrating please help me some one
// This sample uses the Place Autocomplete widget to allow the user to search
// for and select a place. The sample then displays an info window containing
// the place ID and other information about the place that the user has
// selected.
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -33.8688, lng: 151.2195},
zoom: 13
});
var input = document.getElementById('pac-input');
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.bindTo('bounds', map);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
var infowindow = new google.maps.InfoWindow();
var marker = new google.maps.Marker({
map: map
});
marker.addListener('click', function() {
infowindow.open(map, marker);
});
autocomplete.addListener('place_changed', function() {
infowindow.close();
var place = autocomplete.getPlace();
if (!place.geometry) {
return;
}
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
// Set the position of the marker using the place ID and location.
marker.setPlace({
placeId: place.place_id,
location: place.geometry.location
});
marker.setVisible(true);
document.getElementById('place-name').textContent = place.name;
document.getElementById('place-id').textContent = place.place_id;
document.getElementById('place-address').textContent =
place.formatted_address;
infowindow.setContent(document.getElementById('infowindow-content'));
infowindow.open(map, marker);
});
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCW8mAAfcRRb4hrB33AWG_Mk71ZtORjOAo&libraries=places&callback=initMap"
async defer></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<input id="pac-input" class="controls" type="text"
placeholder="Enter a location">
<div id="map"></div>
<div id="infowindow-content">
<span id="place-name" class="title"></span><br>
Place ID <span id="place-id"></span><br>
<span id="place-address"></span>
</div>
As described in the documentation you can use the Google Maps Geocoding API and query using an address and the api will respond with the geocoding (including latitude and longitude) for that address. For example the following request,
curl "https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY"
, will repsond with
{
...
"geometry" : {
"location" : {
"lat" : 37.4223664,
"lng" : -122.084406
},
...
},
...
}
You can find a detailed example here.

Google map API theme option page not displaying

I'm having some issues with the integration of a google map in my web site which can geocode an address before displaying the map with the correct location.
So i have a script (it worked when i was in localhost but since i put the web site online nothing happens) :
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script>
var geocoder;
var map;
var firstLoc;
function findAddress() {
geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address' : document.getElementById('address_field').value},
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
firstLoc = results[0].geometry.location;
map = new google.maps.Map(document.getElementById("map-location"),
{
center: firstLoc,
zoom: 17,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
}
else {
alert('Geocode failed: ' + status);
}
}
);
}
google.maps.event.addDomListener(window, 'load', findAddress);
</script>
I put an address in a field in my theme option page then i register the value and put it in a hidden input in my front-end and try to get it with geocoder.geocode( { 'address' : document.getElementById('address_field').value}
Seems to have a problem with geocoding, i tested with a simple script with a fix position and it showed fine.
In case you need it this is how i display the map in the front-end :
<div class="contact-map">
<div id="map-location"></div>
<form class="address-hidden">
<?php echo "<input id='address_field' type='text' value= '{$content_options['geolocal_setting']}'/>"?>
</form>
</div>

Can't load markers into Google Maps API from JSON

Thanks in advance for any help you can provide! I'm trying to create markers in my Google Map using JSON data. The good news is that I've got the data in the format I need it. The bad news is that I'm new to JSON, and I can't seem to get the markers to show up on the map. From the console's response, the issue seems to be the mapInit line at the bottom of the code below.
I have tried resolving this problem by reviewing solutions at different markers on google maps v3, Using JSON markers in Google Maps API with Javascript, and Google Maps API v3: Adding markers from an array doesn't work, among others. I've also tried duplicating the examples at http://weareallrobots.com/demos/map.html and other sites, but I'm still having trouble.
My code:
<script>
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
function initialize() {
var rendererOptions = {
draggable: true,
panel:document.getElementById('directions_panel')
};
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var mapOptions = {
zoom: 6,
center: chicago,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
directionsDisplay.setMap(map);
// HERE'S WHERE PROBLEMS START
$.getJSON("mapall.js", {}, function(data){
$.each(data.masterlocation, function(i, item){
$("#markers").append('<li>' + item.nickname + '</li>');
var marker = new google.maps.Marker({
position: new google.maps.LatLng(item.latitude, item.longitude),
map: map_canvas,
title: item.nickname
});
arrMarkers[i] = marker;
var infowindow = new google.maps.InfoWindow({
content: "<h3>"+ item.nickname +"</h3>"
});
arrInfoWindows[i] = infowindow;
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
});
});
}
function calcRoute() {
UNRELATED ROUTING CODE HERE
}
// HERE'S WHERE MORE PROBLEMS START
$(function(){
// initialize map (create markers, infowindows and list)
mapInit();
// "live" bind click event
$("#markers a").live("click", function(){
var i = $(this).attr("rel");
// this next line closes all open infowindows before opening the selected one
//for(x=0; x < arrInfoWindows.length; x++){ arrInfoWindows[x].close(); }
arrInfoWindows[i].open(map, arrMarkers[i]);
});
});
</script>
My JSON Data
[{"masterlocation":{"latitude":"33.5","nickname":"First","longitude":"-86.8"}},{"masterlocation":{"latitude":"34.7","nickname":"Second","longitude":"-86.6"}},
UPDATE 1
As per comments from geocodezip and Adam, I've updated my code to the below. I added the + symbol before latitude and longitude, and I replaced mapInit with initialize. However, I'm still not getting any markers to show up. Firebug is telling me that I have errors in my jQuery file, but I'm not sure if these are related. Thanks for sticking with me!
Code:
// HERE'S WHERE PROBLEMS START
$.getJSON("mapall.js", {}, function(data){
$.each(data.masterlocation, function(i, item){
$("#markers").append('<li>' + item.nickname + '</li>');
var marker = new google.maps.Marker({
position: new google.maps.LatLng(+item.latitude, +item.longitude),
map: map_canvas,
title: item.nickname
});
arrMarkers[i] = marker;
var infowindow = new google.maps.InfoWindow({
content: "<h3>"+ item.nickname +"</h3>"
});
arrInfoWindows[i] = infowindow;
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
});
});
}
function calcRoute() {
UNRELATED ROUTING CODE HERE
}
// HERE'S WHERE MORE PROBLEMS START
$(function(){
// initialize map (create markers, infowindows and list)
initialize();
// "live" bind click event
$("#markers a").live("click", function(){
var i = $(this).attr("rel");
// this next line closes all open infowindows before opening the selected one
//for(x=0; x < arrInfoWindows.length; x++){ arrInfoWindows[x].close(); }
arrInfoWindows[i].open(map, arrMarkers[i]);
});
});
JQuery errors
TypeError: a is undefined
[Break On This Error]
...rn a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){...
jquery.js (line 29)
TypeError: a is undefined
[Break On This Error]
...rn a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){...
UPDATE 2
My current code is below, as well as the error codes I am getting in the console. New errors appeared when I reloaded the page, and they refer to the line in my javascript where function initialize first occurs. Maybe this is the problem?
Also, is it possible that the problem is in the JSON? Each JSON entry is preceded by the name of the MYSQL table, "Masterlocation" (see above.) In other JSON examples I've seen, the term that comes after the "." in "$.each(data.masterlocation)" only occurs once.
My Javascript:
<script>
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
function initialize() {
var rendererOptions = {
draggable: true,
panel:document.getElementById('directions_panel')
};
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var chicago = new google.maps.LatLng(41.850033, -87.6500523);
var mapOptions = {
zoom: 6,
center: chicago,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
directionsDisplay.setMap(map);
$.getJSON("mapall.js", {}, function(data){
console.log(data);
$.each(data.masterlocation, function(i, item){
console.log(item);
$("#markers").append('<li>' + item.nickname + '</li>');
var marker = new google.maps.Marker({
position: new google.maps.LatLng(+item.latitude, +item.longitude),
map: map,
title: item.nickname
});
arrMarkers[i] = marker;
var infowindow = new google.maps.InfoWindow({
content: "<h3>"+ item.nickname +"</h3>"
});
arrInfoWindows[i] = infowindow;
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
});
});
}
function calcRoute() {
ROUTING CODE
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: optimize,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById("directions_panel");
}
$(function(){
// initialize map (create markers, infowindows and list)
initialize();
// "live" bind click event
$("#markers a").live("click", function(){
var i = $(this).attr("rel");
// this next line closes all open infowindows before opening the selected one
//for(x=0; x < arrInfoWindows.length; x++){ arrInfoWindows[x].close(); }
arrInfoWindows[i].open(map, arrMarkers[i]);
});
});
</script>
Javascript Errors from Console: these only occurred after I reloaded the page.
Uncaught TypeError: Cannot read property 'length' of undefined jquery.js:29
c.extend.each jquery.js:29
(anonymous function) mapall:87
b jquery.js:121
w.onreadystatechange jquery.js:127
Uncaught TypeError: Cannot read property 'length' of undefined jquery.js:29
c.extend.each jquery.js:29
(anonymous function) mapall:87
b jquery.js:121
w.onreadystatechange jquery.js:127
In addition to any other errors, the way you're accessing the JSON data doesn't match the format of that data.
Your code to access the JSON data is:
$.getJSON( "mapall.js", {}, function( data ) {
$.each( data.masterlocation, function( i, item ) {
... use item.nickname, item.latitude, and item.longitude here
});
});
Now there's nothing wrong with that code, if the JSON data looked like this:
{
"masterlocation": [
{
"nickname": "First",
"latitude": 33.5,
"longitude": -86.8
},
{
"nickname": "Second",
"latitude": 34.7,
"longitude": -86.6
}
]
}
This JSON data is an object with a single property named masterlocation. That property is an array of objects, each one containing nickname, a string, and latitude and longitude, two numbers.
That's a pretty sensible way to lay out the JSON data. I would do it just about the same myself. (The only things I can think of changing would be the naming conventions: I'd probably use a name like locations instead of masterlocation because I like to see plural names for arrays, and I like shorter names for commonly-used properties, e.g. name, lat, and lng. But that's purely a matter of style—the structure I'd use is identical aside for names.)
Unfortunately, your actual JSON data looks like this:
[
{
"masterlocation": {
"latitude": "33.5",
"nickname": "First",
"longitude": "-86.8"
}
},
{
"masterlocation": {
"latitude": "34.7",
"nickname": "Second",
"longitude": "-86.6"
}
}
]
This is an array of two elements. Each element is an object with one property named masterlocation. Each masterlocation object contains the nickname, latitude, and longitude properties. And the latitude and longitude are strings instead of numbers like they should be.
It would be easy enough to change your code to work with this structure:
$.getJSON( "mapall.js", {}, function( data ) {
$.each( data, function( i, item ) {
var loc = item.masterlocation;
... use loc.nickname, +loc.latitude, and +loc.longitude here
});
});
But if you have the option of changing the format of your JSON format, I'd do that instead. You had the right idea in your JavaScript code, just change the JSON output to match.
Make sure the latitude and longitude are actually numbers in JS, not strings.
To do a type convert, just put a + in front of the string
position: new google.maps.LatLng(+item.latitude, +item.longitude)
For some reason, google's API was not built smart enough to handle passing in strings containing numbers....go figure.
EDIT
Ditto to the comment on your post as well - you are calling a function mapInit() but you should be calling the function initialize() from the looks of it.
EDIT2
This line:
map: map_canvas,
should be
map: map,