When the user click for the first time on the map, he can see the related information. But if he click again, the informations are duplicated as you can see on the image below.
I expect that the old information is substitute with the newest.
For handle this request I've developed the function below:
function getElementInfo(elementID, layerName, layerTitle){
map.on('singleclick', function (event) {
var viewResolution = view.getResolution();
var coordinates = event.coordinate;
var epsg = 'EPSG:3857';
var params = {
'INFO_FORMAT': 'application/json'
};
var url = layerName.getSource().getFeatureInfoUrl(
coordinates,
viewResolution,
epsg,
params,
);
async function getFeatureProperties() {
try {
var response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error!\n Status: ${response.status}\n Type: ${response.type}\n URL: ${response.url}`);
} else {
var data = await response.text();
var json = JSON.parse(data).features[0].properties;
var tableHeadContents = '<thead>'
+ '</thead>';
var tableHead = $(tableHeadContents).attr("id","thead");
$("#"+elementID).append(tableHead);
var tableBodyContents = '<tbody></tbody>';
var tableBody = $(tableBodyContents).attr("id","tbody");
$("#"+elementID).append(tableBody);
for (items in json) {
key = items;
value = json[items];
tableRow = '<tr><td class="td-head">' + key + '</td><td class="td-body">' + value + '</td></tr>';
$("tbody").append(tableRow);
}
}
} catch (e) {
console.log(e);
}
}
getFeatureProperties();
});
};
I haven't strong skills with Javascript and probably there is an error here but I can't see it.
I call the function simply adding it after a TileWMS:
getElementInfo('onclickinfo35', wms35, 'NDVI Campania 20150807');
And the informations appears inside a simple table:
<table id="onclickinfo35"></table>
The reason why you are getting more and more values/rows in your table for every click, is because you don't clear the table before adding data.
You need to call $("#"+elementID).html(); before $("#"+elementID).append(tableHead);
Related
I've got a problem with JSON in JavaScipt. I've got 2 different JSON URL. One of them contains data about users and the second one about posts. And in posts JSON I've got a field userId.
I want to find a way to connect them somehow. I need to get users and their posts and then count how many posts every user wrote.
var postRequest = new XMLHttpRequest();
postRequest.open('GET', 'https://jsonplaceholder.typicode.com/posts');
postRequest.onload = function() {
var posts = JSON.parse(postRequest.responseText);
var userRequest = new XMLHttpRequest();
userRequest.open('GET', 'https://jsonplaceholder.typicode.com/users');
userRequest.onload = function (){
var users = JSON.parse(userRequest.responseText);
for(k in users){
document.write("</br></br>"+ users[k].name +", " + users[k].username + ", " + users[k].email + "</br>" + "-------------------------------------------------------------------------------------" + "</br>");
for(k1 in posts){
if(posts[k1].userId===users[k].id){
document.write(posts[k1].body + "</br>");
}
}
}
};
userRequest.send();
};
postRequest.send();
but I think it doesn't look good. I want to get data from JSON to variable to use them later, in function for example.
Anyone help? I've never connected data from 2 JSON files and want to do it in a good way and getting good practice.
Use this instead
for(k in users){
for(k1 in posts){
if(posts[k1].userId===users[k].id){
if(!users[k].hasOwnProperty('posts')) {
users[k].posts = [];
}
users[k].posts.push(posts[k1].body);
}
}
}
if you could you jquery
$.when($.ajax({
url: "https://jsonplaceholder.typicode.com/users"
})).then(function(data, textStatus, jqXHR) {
$.each(data, function(index, value) {
$.ajax({
url: "https://jsonplaceholder.typicode.com/posts?userId=" + value.id
}).then(function(data, textStatus, jqXHR) {
console.log("UserID:" + data[0].userId + " Nos Posts:" + data.length);
});
});
});
You can try above code and let me know if it solve your purpose
Steps you can use :
1. You can add a body property in to the objects in users array as per the id and userid match.
2. Later you can iterate the users array whenever you want to use.
DEMO
var postRequest = new XMLHttpRequest();
postRequest.open('GET', 'https://jsonplaceholder.typicode.com/posts');
postRequest.onload = function() {
var posts = JSON.parse(postRequest.responseText);
var userRequest = new XMLHttpRequest();
userRequest.open('GET', 'https://jsonplaceholder.typicode.com/users');
userRequest.onload = function (){
var users = JSON.parse(userRequest.responseText);
for(k in users) {
for(k1 in posts) {
if(posts[k1].userId===users[k].id){
users[k].body = posts[k1].body;
}
}
}
console.log("users", users);
};
userRequest.send();
};
postRequest.send();
My receive() function parses through data from a backend server and I use that data to create a renderHTML() function which displays the parsed data as an HTML string. I get the data to display and can also attach checkboxes perfectly fine. I am trying to get the value of questionid so that when the user clicks on the checkbox, I can use Ajax to send the values of which question was selected, which can be done by questionid. I am not sure on how to get the value of the questionid, store it, and send it through Ajax.
function receive() {
var text = document.getElementById("text").value;
var data = {
'text': text
};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var ourData = xhr.responseText;
var parsedData = JSON.parse(ourData);
console.log(parsedData);
renderHTML(parsedData);
}
};
xhr.open("POST", "URL", true);
xhr.send(JSON.stringify(data));
}
var questionid;
function renderHTML(data) {
var htmlString = "";
for (i = 0; i < data.length; i++) {
htmlString += "<p><input type='checkbox' value='data[i].questionid'>" +
data[i].questionid + "." + "\n";
htmlString += '</p>';
}
response.insertAdjacentHTML('beforeend', htmlString);
var t = this;
var checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].onclick = function() {
if (this.checked) {
console.log(this.questionid.value);
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var Data = xhr.responseText;
console.log(Data);
var parseData = JSON.parse(Data);
};
xhr.send(JSON.stringify(data));
}
}
}
There are many ways in which you can achieve what you are looking for. For that, you will need to understand one of two concepts:
bind
closures
None of them is easy to understand for beginners but will help you vastly improve your coding skills once you get them. You can read about them here and here respectively.
The problem with your code (amongst other details) is that the value of i is global, and so by the time the DOM is rendered and the user can click in one of the checkboxes, all the checkboxes have the same value of i (the last one).
bind helps you solve this by setting an argument to the function that will always remain the same.
closures help you solve this by storing the value of a variable declared in a scope that is accessible only from a function that stores a reference to that variable.
Here is some code I wrote that does what you want using a most modern syntax, which I would highly recommend.
Specially, I would recommend you to read about the fetch api; which is a much cleaner way to make http request.
This code does what you are looking for:
function receive() {
const text = document.getElementById('text').value;
const options = {
method: 'POST',
body: JSON.stringify({ text })
}
fetch("<the url here>", options)
.then( response => response.json())
.then( data => {
renderHTML(JSON.parse(data));
})
}
function renderHTML(data){
for (const x of data) {
const content = x.questionid;
// i'm asuming that the response html element already exists
response.insertAdjacentHTML('beforeend', `<p><input value="${content}" type="checkbox">${content}</p>`);
}
document.querySelectorAll('input[type="checkbox"]').forEach( input => {
input.addEventListener((e) => {
const options = {
method: 'POST',
body: JSON.stringify(e.target.value)
};
fetch('<the second url here>', options).then( response => response.json())
.then( data => {
// 'data' is the response you were looking for.
})
})
})
}
The closest issue I've found to mine is here. I believe I'm getting this error from how my .end() calls are set up. Here's the code we're working with:
app.get('/anihome',function(req,res){
var context = {};
function renderPage(context) {
res.render('anihome',context);
}
function addRequestToPage(text) {
context.data = text.toString('utf8');
context.info = JSON.parse(text);
return context;
}
function addAnimeToPage(text) {
context.anime = JSON.parse(text);
return context;
}
function addAnimeRequest(context) {
var options2 = {
host: 'anilist.co',
path: '/api/anime/20631?access_token=' + context.info.access_token,
method: 'GET'
};
https.request(options2, function(restRes) {
restRes.on('data',function(jsonResult) {
//context.anime = JSON.parse(jsonResult);
//console.log(JSON.parse(jsonResult));
console.log(context);
renderPage(context);
});
}).end();
}
function addHeaderRequest(context) {
var options = {
host: 'anilist.co',
path: '/api/auth/access_token?grant_type=client_credentials&client_id='
+ clientID + '&client_secret=' + secretKey,
method: 'POST'
};
https.request(options, function(restRes) {
restRes.on('data', function(jsonResult) {
context = addRequestToPage(jsonResult);
addAnimeRequest(context);
});
}).end();
}
addHeaderRequest(context);
});
I've tried setting up one of the .end()s with a callback, .end(addAnimeRequest(context));, which leaves me with a socket hang up error, so presumably something in my addAnimeRequest function is taking too long?
Is there a better way to make multiple requests to the same website with different options? I'm pretty new to Node.js.
The data event can be emitted more than once. You would need to add a listener for the end event and then pass in all of your data. Example:
https.request(options2, function(restRes) {
var buf = ''
restRes.on('data',function(jsonResult) {
//context.anime = JSON.parse(jsonResult);
//console.log(JSON.parse(jsonResult));
buf += jsonResult
});
restRes.on('end', function() {
// TODO JSON.parse can throw
var context = JSON.parse(buf)
renderPage(context)
})
}).end();
I am trying to get the hereNow parameter from FourSquare using a checkins query on a specific user, unfrotunately I can't seem to get that parameter using checkins, I am seeing all other data regarding a venue except for the hereNow parameter.
Does anyone know how I can get that parameter using checkins? Otherwise, how can I incorporate venue objects and tie into my current code?
Here is my JavaScript to set hereNow as a variable:
var count;
getVenueStatus = function() {
var hereNowUrl = 'https://api.foursquare.com/v2/venues/VENUE_ID?&oauth_token=OAUTH_TOKEN&v=20140303';
$.getJSON(hereNowUrl, {format: "json"}, function(data) {
$(data.response.venue).each(function(index) {
$(this).each(function(index) {
var venue = this;
var hereNowCount = venue.hereNow.count;
count = hereNowCount;
console.log(count);
});
});
});
}
Here is my JavaScript to display the results on a map:
findFoodTrucks = function (param) {
getVenueStatus();
$.mobile.pageLoading();
var url = 'https://api.foursquare.com/v2/users/80507329/checkins?oauth_token=OAUTH_TOKEN&v=20140303';
var mapBounds = new google.maps.LatLngBounds();
if (param.userloc) mapBounds.extend(param.userloc);
$.getJSON(url, function(data) {
$(data.response.checkins).each(function(index) { // groups: nearby, trending
$(this.items).each(function(index) {
var foodtruck = this;
var foodtruckPosition = new google.maps.LatLng(foodtruck.venue.location.lat, foodtruck.venue.location.lng);
var foodtruckIcon = (count > 0) ? 'foodtruck_active.png' : 'foodtruck_inactive.png';
var foodtruckStreet = (foodtruck.venue.location.address) ? '<br>' + foodtruck.venue.location.address : '';
var foodtruckContent = '<strong>' + foodtruck.venue.name + '</strong>' + foodtruckStreet + '<br>';
mapBounds.extend(foodtruckPosition);
addFoodTruckMarker(foodtruckPosition, foodtruckIcon, foodtruckContent);
console.log(foodtruck);
});
if (param.zoomtotrucks) $('#map_canvas').gmap('getMap').fitBounds(mapBounds);
});
})
.error( function() {
loadFoodTrucks(param); //try again
})
.complete( function() {
$.mobile.pageLoading( true );
});
}
Thanks in advance!
The check-in response includes a compact venue, which is only sometimes guaranteed to have a hereNow field. To get the hereNow count, it's probably best to make a second venue detail API call.
PS: also noticed that you seemed to be passing an OAuth token and client ID/secret—in this case, you only need the OAuth token! Take a look at https://developer.foursquare.com/overview/auth for more info.
Firstly, here is my code as I've progressed so far:
var http = require("http");
// Utility function that downloads a URL and invokes
// callback with the data.
function download(url, callback) {
http.get(url, function(res) {
var data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on("end", function() {
callback(data);
});
}).on("error", function() {
callback(null);
});
}
var cheerio = require("cheerio");
var url = "http://www.bloglovin.com/en/blogs/1/2/all";
var myArray = [];
var a = 0;
var getLinks = function(){download(url, function(data) {
if (data) {
// console.log(data);
var $ = cheerio.load(data);
$(".content").each(function(i, e) {
var blogName = $(e).find(".blog-name").text();
var followLink = $(e).find("a").attr("href");
var blogSite = $(e).find(".description").text();
myArray[a] = [a];
myArray[a]["blogName"] = blogName;
myArray[a]["followLink"] = "http://www.bloglovin.com"+followLink;
myArray[a]["blogSite"] = blogSite;
a++;
console.log(myArray);
});
}
});
}
getLinks();
As you can see, followLinks is concatenated to followUrl, of which I'd like to pass through the 'url' download, so effectively I'll be scraping each of the pages using the same CSS rules, which will be added to the multidimensional array for the corresponding blogger.
How can I go about this?
I do something similar in one of my scraping jobs, but I use the async.js library to accomplish. Note that I'm also using the request module and cheerio.js in my scraping. I fetch and scrape rows of data from a single webpage, but suspect you could do something similar to fetch URLs and request / scrape them in the same manner.
I also admit this is quite basic coding, certainly could be optimized with a bit of refactoring. Hope it gives you some ideas at least...
First, I use request to fetch the page and call my parse function -
var url = 'http://www.target-website.com';
function(lastCallback) {
request(url, function(err, resp, body) {
if(!err) { parsePage(err, resp, body, lastCallback); }
else { console.log('web request error:' + resp.statusCode); }
}
}
Next, in my parsePage function, I load the website into Cheerio, fetch the HTML of each data row into an array, push my parseRow function and each HTML segment into another array, and use async.parallel to process each iteration -
var rows = [];
function parsePage(err, resp, body, callback1) {
var $ = cheerio.load(body);
$('div#targetTable tr').each(function(i, elem) {
rows.push($(this).html());
});
var scrRows = [];
rows.forEach(function(row) {
scrRows.push(function(callback2) {
parseRow(err, resp, row);
callback2();
});
async.parallel(scrRows, function() {
callback1();
});
}
Inside your loop, just create an object with the properties you scrape then push that object onto your array.
var blogInfo = {
blogName: blogName,
followLink: "http://www.bloglovin.com"+followLink;
blogSite: blogSite
};
myArray.push(blogInfo);
You have defined a = 0; So
myArray[a] = [a]; // => myArray[0] = [0]; myArray[0] becomes an array with 0 as only member in it
All these statements throw an error since Array can have only integer as keys.
myArray[a]["blogName"] = blogName;
myArray[a]["followLink"] = "http://www.bloglovin.com"+followLink;
myArray[a]["blogSite"] = blogSite;
Instead try this:
var obj = {
index: a,
blogName: blogName,
followLink: "http://www.bloglovin.com" + followLink,
blogSite: blogSite
}
myArray.push(obj);
console.log(myArray);