This is a proper noob question it would seem, so apologies, but I can't seem to solve it so I'm reaching out for some assistance.
I have a function in my .js file that interacts with the Google Places library to autocomplete a field in a form. I then have an ajax function that runs when you click the submit button which creates variables in the django session. The data of interest to me is lat and long.
However, for some reason, I can't seem to get the data to pass from one to the other. I know the ajax function is working because if I type in fixed values they propagate through to django, but I can't seem to get it to update dynamically.
const csrf = document.getElementsByName('csrfmiddlewaretoken');
var lat;
var lng;
function autocomplete_location() {
let defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(49.6331, -11.7247),
new google.maps.LatLng(59.4850, 1.5906));
let input = document.getElementById('id_your_location');
let options = {
bounds: defaultBounds,
types: ["address"],
fields: ["name", "geometry"],
};
let autocomplete = new google.maps.places.Autocomplete(input, options);
autocomplete.addListener('place_changed', function() {
// Get place info
let place = autocomplete.getPlace();
// Do whatever with the value!
lat = place.geometry.location.lat()
lng = place.geometry.location.lng()
console.log(lat)
console.log(lng)
})
}
$(document).ready(function (){
$(".btn").click(function (){
$.ajax({
url: '',
type: 'POST',
data: {
'csrfmiddlewaretoken': csrf[0].value,
'lat': lat,
'long': lng,
},
success: function (response) {
console.log(response)
window.location.replace('/new_path/')
},
error: function (error) {
console.log(error)
}
})
})
})
UPDATE -----------------------------------------------------------
I have managed to get this working. I have moved the ajax call into the autocomplete function, but it only works when I click the submit button, it does not work when I press the enter key, so I need to brush up on my JS and ajax to solve that problem.
const csrf = document.getElementsByName('csrfmiddlewaretoken');
function autocomplete_location() {
let defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(49.6331, -11.7247),
new google.maps.LatLng(59.4850, 1.5906));
let input = document.getElementById('id_your_location');
let options = {
bounds: defaultBounds,
types: ["address"],
fields: ["name", "geometry"],
};
let autocomplete = new google.maps.places.Autocomplete(input, options);
autocomplete.addListener('place_changed', function() {
// Get place info
let place = autocomplete.getPlace();
// Do whatever with the value!
var lat = place.geometry.location.lat();
var lng = place.geometry.location.lng();
console.log(lat)
console.log(lng)
$("form").submit(function (){
$.ajax({
url: '',
type: 'POST',
data: {
'csrfmiddlewaretoken': csrf[0].value,
'lat': lat,
'long': lng,
},
success: function (response) {
console.log(response)
// this is not good. But I couldn't find a better way to redirect
// window.location.replace('/coach/')
},
error: function (error) {
console.log(error)
}
})
})
})
}
where do you call autocomplete_location() ? try passing lat and long in that function as parameters e.g. autocomplete_location(lat, long)
Related
Im writing a javascript and wanted to send the data to PHP page addProject-logic.php through ajax POST.
Although the POST request success on the javascript, but on my php page i couldnt echo, it showed undefined "latLng"
My file structure:
Structure
addMap.js :
google.maps.event.addListener(marker, 'dragend', function (marker) {
var latLng = marker.latLng
currentLatitude = latLng.lat()
currentLongitude = latLng.lng()
var latlng = {
lat: currentLatitude,
lng: currentLongitude,
}
//Post LAT LNG TO POST
function postLatLng() {
$.ajax({
type: 'POST',
url: '../includes/actions/addProject-logic.php',
data: {
latLng: latlng,
},
success: function (response) {
window.alert('Success')
},
})
}
var geocoder = new google.maps.Geocoder()
geocoder.geocode(
{
location: latlng,
},
function (results, status) {
if (status === 'OK') {
if (results[0]) {
input.value = results[0].formatted_address
map.setZoom(18)
map.panTo(latLng)
postLatLng()
} else {
window.alert('No results found')
}
} else {
window.alert('Geocoder failed due to: ' + status)
}
},
)
})
i create a function postLatLng then execute in another action
Whenever I echo on php addProject-logic.php page, echo $_POST['latLng']; it showed undefined array key latLng
Your example is a bit vague as you don't show what addProject-logic.php file does but here's a fresh example with a javascript call and a php code.
I'm simplifying by using javascript (you can convert to jQuery) and removing geocode as it seems it is not the issue here (but then, your example is vague).
I'm using fetch to make the requests in order to show the different steps. Notice the JSON.stringify call.
// Data is
var latlng = {
lat: 42,
lng: 42
}
function postLatLng() {
fetch('addProject-logic.php', {
method: 'POST',
body: JSON.stringify({
latLng: latlng
})
})
// the response sent back via php is json
.then(response => response.json())
.then(json => {
// The data returned by the php script contains latLng
window.alert(json.latLng)
})
.catch(err => {
console.error(err)
})
}
On the php side:
<?php
// Header for the JSON response
header('Content-Type: application/json; charset=UTF-8');
// parsing the post content
// My guess is you miss both this call and the JSON.stringify in the js
$data = json_decode(file_get_contents('php://input'), true);
// here we send back the post data.
echo json_encode([
'latLng' => $data["latLng"],
]);
I'm working on a weather app, on top of having the option to get his geolocation the user can also input a city to get the weather info.
I've been stuck for a while, I'm trying to get the info of the weather using the input of the user, using my api request(which is working on codepen // I'm working on VSCode). Im using the same url of my geoLocation but changing it to taking the city instead of the lon and lat as input, but I always get a ERROr 400, but I can't seem to locate the source of my error.
// Get weather from input
function getVal() {
var val = document.querySelector('#search-city').value;
const url = 'https://api.openweathermap.org/data/2.5/weather?q=' + val + '&appid={API key}&units=metric';
$.ajax({
url: url,
type: "GET",
dataType: 'json',
success: (data) => {
$('#city').text(data.name)
$('#condition').text(data.weather[0].main);
$('h1').text(Math.round(data.main.temp));
backgroundChange(data.weather[0].main);
},
error: () => {
return false
}
});
};
// Get weather using location
function geoLocation() {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
let lat = position.coords.latitude;
let long = position.coords.longitude;
let url = 'https://api.openweathermap.org/data/2.5/weather?lat=' + lat + '&lon=' + long + '&appid={API Key}&units=metric';
$.ajax({
url: url,
type: "GET",
dataType: 'json',
success: (data) => {
$('#city').text(data.name)
$('#condition').text(data.weather[0].main);
$('h1').text(Math.round(data.main.temp));
backgroundChange(data.weather[0].main);
},
error: () => {
return false
}
});
})
};
});
I would really appreciate your help !
Thank you very much!!
// RESOLVED
At first I created the function outside of my onlick event and the API Call was made even before the event was called, so I think the input couldn't make it's way to the URL.
Here is the modify version which is now working :
$('.search-icon').click(
function getVal() {
var city = document.querySelector('#search-city').value;
const url = 'https://api.openweathermap.org/data/2.5/weather?q='+city+'&appid=dc8c9152e8adaad0ec8bf635818c0d42&units=metric';
$.ajax({
url: url,
type: "GET",
dataType: 'json',
success: (data) => {
$('#city').text(data.name)
$('#condition').text(data.weather[0].main);
$('h1').text(Math.round(data.main.temp));
backgroundChange(data.weather[0].main);
},
error: () => {
return false
}
});
});
I believe in this part of API's url "ppid={API Key}" you are passing as a string. You should inform your API key in order to fetch the data.
Thanks for your responses but I found the solution ! Instead of creating an event using the function, I put the function in the event.
I'm attempting to create a simple weather API that replaces handlebars placeholder variables with user input of a city name linked to an api. It works very strangely, it will display the correct data after the next input is submitted. I.E. I submit "Dayton" and the placeholder data shows up again, then I submit "New York" and Dayton's correct info pops up. If I were to submit a third city, New York would display. Any ideas on why? Here's my code:
var currentWeather = {
cityName: "London",
temperature: 86,
description: 'cloudy'
};
var addCurrentWeather = function(data) {
var weather = {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
};
var renderCurrentWeather = function () {
var weather= currentWeather;
var source = $('#weather-template').html();
var template = Handlebars.compile(source)
var weatherHTML = template(currentWeather);
$('#city').append(weatherHTML);
};
// fetch applying user input to grab data from api
var fetchCurrentWeather = function (query) {
$.ajax({
method: "GET",
url: "https://api.openweathermap.org/data/2.5/weather?q=" + query + "&APPID=MYKEY",
dataType: "json",
success: function (data) {
addCurrentWeather(data);
renderCurrentWeather();
currentWeather = {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
}
});
};
$('#search').on('click', function () {
var search = $('#search-query').val();
console.log(search);
fetchCurrentWeather(search);
});
renderCurrentWeather();
I will assume that you expect from your code to do following in the success handler.
Update your global weather object
Use that global object to render your template
That does not happen because your function addCurrentWeather does essentially nothing as it updates a local variable and discards it.
So make sure that this function instead updates the global variable.
var addCurrentWeather = function(data) {
currentWeather = {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
};
and in the success handler you should have then only
addCurrentWeather(data);
renderCurrentWeather();
Reason why it then currently works the way it does is because after you call the render function you later update the global variable directly hence why this data is then used on next api fetch.
As a suggestion, try to avoid using global variables as it is easy to create bugs like this. Instead try to use pure functions as it will also help if you start unit test your code.
In your case have addCurrentWeather function accept data and return a weather object. And similarly have the render method accept weather object instead of reading it from global var.
Something like this
function getCurrentWeather(data) {
return {
cityName: data.name,
temperature: data.main.temp,
description: data.weather[0].main
}
};
function renderCurrentWeather(weather) {
var source = $('#weather-template').html();
var template = Handlebars.compile(source)
var weatherHTML = template(currentWeather);
$('#city').append(weatherHTML);
};
function fetchCurrentWeather(query) {
$.ajax({
method: "GET",
url: "https://api.openweathermap.org/data/2.5/weather?q=" + query + "&APPID=MYKEY",
dataType: "json",
success: function (data) {
const weather = getCurrentWeather(data);
renderCurrentWeather(weather);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus);
}
});
};
$('#search').on('click', function () {
var search = $('#search-query').val();
console.log(search);
fetchCurrentWeather(search);
});
fetchCurrentWeather('London');
<script>
new Vue({
el: '#fad' ,
data: {
data: {},
},
mounted() {
var self = this;
navigator.geolocation.getCurrentPosition(success, error);
function success(position) {
var GEOCODING = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + '%2C' + position.coords.longitude + '&language=en';
$.getJSON(GEOCODING).done(function(location) {
$('#country').html(location.results[0].address_components[5].long_name);
$('#state').html(location.results[0].address_components[4].long_name);
$('#city').html(location.results[0].address_components[2].long_name);
$('#address').html(location.results[0].formatted_address);
$('#latitude').html(position.coords.latitude);
$('#longitude').html(position.coords.longitude);
})
var lat = position.coords.latitude;
$.ajax({
url: 'https://api/post//',
data: {
lat: position.coords.latitude,
lon: position.coords.longitude,
city:location.results[0].address_components[2].long_name,
},
type: "POST",
dataType: 'json',
success: function (e) {
if (e.status == 1) {
self.data = e.data;
console.log(e.data)
}
}
});
console.log(lat);
}
function error(err) {
console.log(err)
}
}
})
</script>
This is my code. I am able to get lat and lon values and pass. But I am not able to pass city. When I do this way, I am getting error. I am very weak in js and this is the first time doing a project. Please help me to obtain the result. I need to send name of city through ajax request. <span id="city"></city> in html gives me the city name. How to get the city name in script and send this by ajax request. Please help me?
I think you were trying to make the AJAX function in the wrong place. The getCurrentPosition is asynchronous so the response is not necessarily available immediately - thus the ajax request that you are trying to send should be sent only on getting the response from getCurrentPosition
<script>
new Vue({
el: '#fad' ,
data: {
data: {},
},
mounted(){
var self = this;
navigator.geolocation.getCurrentPosition( success, error );
function success( position ) {/* geolocation success callback */
var GEOCODING = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + '%2C' + position.coords.longitude + '&language=en';
$.getJSON( GEOCODING ).done( function( location ) {
$('#country').html(location.results[0].address_components[5].long_name);
$('#state').html(location.results[0].address_components[4].long_name);
$('#city').html(location.results[0].address_components[2].long_name);
$('#address').html(location.results[0].formatted_address);
$('#latitude').html(position.coords.latitude);
$('#longitude').html(position.coords.longitude);
/*
As this is an asynchronous process, make the
ajax request here.
*/
var lat = position.coords.latitude;
console.log( lat );
$.ajax({
url: 'https://api/post//',
data: {
lat: position.coords.latitude,
lon: position.coords.longitude,
city: location.results[0].address_components[2].long_name,
state: location.results[0].address_components[4].long_name,
country: location.results[0].address_components[5].long_name
},
type: 'POST',
dataType: 'json',
success: function(e) {
if( e.status == 1 ) {
self.data = e.data;
console.log( e.data )
}
}
});
});
}
function error( err ) {/* geolocation error callback */
console.log( err )
}
}
});
</script>
You have a syntax error in your code, that's why it's not running.
In your $.ajax call, you have a semicolon after
city:location.results[0].address_components[2].long_name;
which is a syntax error, remove the trailing ;
EDIT
You updated your answer and fixed the trailing ;, next to that the code seems to run ok, check the snippet below.
Here's a small snippet with reformatted code. Don't forget to change your $.ajax url, unless you really want to POST to https://api/post
new Vue({
el: '#fad',
data: {
data: {},
},
mounted() {
var self = this;
navigator.geolocation.getCurrentPosition(function () {
var GEOCODING = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + '%2C' + position.coords.longitude + '&language=en';
$.getJSON(GEOCODING).done(function (location) {
$('#country').html(location.results[0].address_components[5].long_name);
$('#state').html(location.results[0].address_components[4].long_name);
$('#city').html(location.results[0].address_components[2].long_name);
$('#address').html(location.results[0].formatted_address);
$('#latitude').html(position.coords.latitude);
$('#longitude').html(position.coords.longitude);
});
$.ajax({
url: 'https://api/post//',
data: {
lat: position.coords.latitude,
lon: position.coords.longitude,
city: location.results[0].address_components[2].long_name,
},
type: "POST",
dataType: 'json',
success: function (e) {
if (e.status == 1) {
self.data = e.data;
console.log(e.data)
}
}
});
},
function () {
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<div id="fad"></div>
I have been using the example shown here (https://astuntechnology.github.io/osgis-ol3-leaflet/ol3/05-WMS-INFO.html) to try and retrieve features at a coordinate from multiple TileWMS layers I have set up in my application.
This example has been tweaked so it now returns data in JSONP using the reqwest library, but now I am trying to figure out the best way to adapt this to include multiple layers and multiple features.
I am thinking of using the map.forEachLayerAtPixel function to retrieve all layers present at the map click location, and then within if statements call the feature and add this to a variable to build a dynamic html table of results.
I don't know if this is the best approach but is the only way I can think of doing it so I am able to retrieve the information in a way I can lay it out specifically.
Below is the javascript for my on map click function but it is not returning the pop up and doesn't display any errors.
I am not sure if I am using the correct approach, and does anything look incorrect with the below?
Thanks
var popup = new ol.Overlay.Popup();
map.addOverlay(popup);
map.on('singleclick', function(evt) {
if($(window).width() <= 767 && document.getElementById('sidebar').style.display == 'block') {
$('#sidebar').toggle();
$(".navbar-collapse.in").collapse("hide");
map.updateSize();
return false;
}
// Hide existing popup and reset it's offset
popup.hide();
popup.setOffset([0, 0]);
var displayedLayers = [];
var content = "";
map.forEachLayerAtPixel(evt.pixel, function(layer) {
displayedLayers.push(layer.get('name'));
});
if ($.inArray('layer62', displayedLayers) > -1) {
var url = layer62
.getSource()
.getGetFeatureInfoUrl(
evt.coordinate,
map.getView().getResolution(),
map.getView().getProjection(),
{
'INFO_FORMAT': 'text/javascript',
'format_options': 'callback:results',
'propertyName': 'definition'
}
);
reqwest({
url: url,
type: 'jsonp',
jsonpCallbackName: 'results'
}).then(function (data) {
var feature = data.features[0];
var props = feature.properties;
content += "<h4>Flood Zone 3</h4><p>" + props.definition + "</p>";
});
}
if ($.inArray('layer63', displayedLayers) > -1) {
var url = layer63
.getSource()
.getGetFeatureInfoUrl(
evt.coordinate,
map.getView().getResolution(),
map.getView().getProjection(),
{
'INFO_FORMAT': 'text/javascript',
'format_options': 'callback:results',
'propertyName': 'definition'
}
);
reqwest({
url: url,
type: 'jsonp',
jsonpCallbackName: 'results'
}).then(function (data) {
var feature = data.features[0];
var props = feature.properties;
content += "<h4>Flood Zone 2</h4><p>" + props.definition + "</p>";
});
}
return content;
popup.show(evt.coordinate, content);
});
EDITED original answer as it wasn't correct, this one seems to work. It's jus a test based in your code but changes the way the popup is handled:
var layers = [
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://demo.opengeo.org/geoserver/wms?',
params: {
'LAYERS': 'ne:ne',
'TILED': true,
'version': '1.1.0'
},
serverType: 'geoserver',
})
}),
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://demo.opengeo.org/geoserver/wms?',
params: {
'LAYERS': 'ne:ne',
'TILED': true,
'version': '1.1.0'
},
serverType: 'geoserver',
})
})
];
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var popup = new ol.Overlay( /** #type {olx.OverlayOptions} */ ({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
}));
var map = new ol.Map({
layers: layers,
target: 'map',
overlays: [popup],
view: new ol.View({
center: [327641, 4149464],
zoom: 3,
//EPSG: 25830
})
});
map.on('singleclick', function (evt) {
content.innerHTML = "";
var displayedLayers = [];
var responses = 0;
var url = layers[0].getSource()
.getGetFeatureInfoUrl(
evt.coordinate,
map.getView().getResolution(),
map.getView().getProjection(), {
'INFO_FORMAT': 'text/javascript',
'format_options': 'callback:parseResponse',
'propertyName': 'name'
});
reqwest({
url: url,
type: 'jsonp',
jsonpCallbackName: 'parseResponse'
}).then(function (data) {
var feature = data.features[0];
var props = feature.properties;
content.innerHTML += "<h4>First Layer</h4><p>" + props.name + "</p>";
popup.setPosition(evt.coordinate);
});
// Second layer
var url = layers[1].getSource()
.getGetFeatureInfoUrl(
evt.coordinate,
map.getView().getResolution(),
map.getView().getProjection(), {
'INFO_FORMAT': 'text/javascript',
'format_options': 'callback:parseResponse',
'propertyName': 'name'
});
reqwest({
url: url,
type: 'jsonp',
jsonpCallbackName: 'parseResponse'
}).then(function (data) {
var feature = data.features[0];
var props = feature.properties;
content.innerHTML += "<h4>Second layer</h4><p>" + props.name + "</p>";
popup.setPosition(evt.coordinate);
});
});
Jsfiddle here: http://jsfiddle.net/fbma/1pchmpoo
for anyone struggling with openlayers 3+ getGetFeatureInfoUrl function with multiple layers, the solution for me was passing the parameters LAYERS, QUERY_LAYERS and FEATURE_COUNT. Specially the last one as even including all layers in the two former ones, geoserver indeed takes all the layers BUT assumes tha FEATURE_COUNT is 1
So the nex example did the work
var url = layers[0].getSource()
.getGetFeatureInfoUrl(
evt.coordinate,
map.getView().getResolution(),
map.getView().getProjection(), {
**'LAYERS':'ne:ne,ne:ne2,ne:ne3,ne:ne4,ne:ne5',
'QUERY_LAYERS': 'ne:ne,ne:ne2,ne:ne3,ne:ne4,ne:ne5',
'FEATURE_COUNT':100000**,
'INFO_FORMAT': 'text/javascript',
'format_options': 'callback:parseResponse',
'propertyName': 'name'
});