Google Maps / jQuery - create object from json file - javascript

Here is a plunker of the google map that was working but after I get back from vacation it doesn't work anymore. But still you can look at the code more - https://plnkr.co/edit/jHCuVVhGDLwgjNw4bcLr
Here is the google maps code:
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(52.4357808, 4.991315699999973),
zoom: 2,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
}
var seg = {
1: 'investment_cast',
2: 'forged_Prod',
3: 'air_Prod',
5: 'worldwide',
6: 'structurals'
}
var comp = {
1: 'structurals',
2: 'airfoils',
3: 'wyman',
4: 'energy',
5: 'fasteners',
6: 'struc_comp',
7: 'mech_hard',
8: 'engine_prod',
9: 'corp',
10: 'aero',
12: 'timet',
13: 'spec_metals'
}
var myJSON = {};
var myMarkers=[];
$.getJSON("locations.json", function(json1) {
myJSON=json1;
$.each(json1, function(key, data) {
var latLng = new google.maps.LatLng(data.latitude, data.longitude);
// Creating a marker and putting it on the map
var marker = new google.maps.Marker({
position: latLng
});
myMarkers[key]=marker;
marker.setMap(map);
var infoWindow = new google.maps.InfoWindow();
google.maps.event.addListener(marker, 'click', function() {
if (infoWindow) {infoWindow.close();}
infoWindow = new google.maps.InfoWindow({
content: "<h5>" + data.display_name + "</h5>" +
"<div>" + data.street+ "</div>" +
"<div>" + data.city + ", " + data.state + " " + data.postal_code + "</div>" +
"<div class='mapPhoneNum'>" + data.telephone + "</div>" +
"Website"
});
infoWindow.open(map, marker);
map.setZoom(15);
map.panTo(this.getPosition());
google.maps.event.addListener(infoWindow,'closeclick',function(){
resetMapOrigin();
});
});
filterMarkers = function(category){
var component = category.data("component_id");
var segment = category.data("segment_id")
setMapOnAll(null);
resetMapOrigin();
var filteredMarkers=[];
$.each(myJSON, function(key, data) {
if( typeof(component)!="undefined" ){
if( (myJSON[key].component_id == component) && (myJSON[key].segment_id == segment) ){
filteredMarkers.push(key);
}
}else{
if( myJSON[key].segment_id == segment ){
filteredMarkers.push(key);
}
}
});
for(i=0;i<filteredMarkers.length;i++){
myMarkers[filteredMarkers[i]].setMap(map);
}
}
function setMapOnAll(map) {
for (var i = 0; i < myMarkers.length; i++) {
myMarkers[i].setMap(map);
}
}
function resetMapOrigin(){
map.setZoom(2);
map.setCenter({lat:52.4357808,lng:4.991315699999973});
}
});
});
So the problem is that var seg ={...} and var comp ={...} are hard coded into an object. What I need to be able to do is use $.getJSON (or whatever else will work) to pull that data from a json file (like I'm doing with the locations.json) and format it exactly like the objects currently are 1: 'structurals', 2: 'airfoils', and so on (I need to keep this structure).
The json files are formated like this -
Components:
[
{
"id": "1",
"display_name": "structurals"
},
{
"id": "2",
"display_name": "airfoils"
},
{
"id": "3",
"display_name": "wyman"
},
{
"id": "4",
"display_name": "energy"
},
{
"id": "5",
"display_name": "fasteners"
},
{
"id": "6",
"display_name": "struc_comp"
},
{
"id": "7",
"display_name": "mech_hard"
},
{
"id": "8",
"display_name": "engine_prod"
},
{
"id": "9",
"display_name": "corp"
},
{
"id": "10",
"display_name": "aero"
},
{
"id": "12",
"display_name": "timet"
},
{
"id": "13",
"display_name": "spec_metals"
}
]
Segments:
[
{
"id": "1",
"display_name": "investment_cast"
},
{
"id": "2",
"display_name": "forged_Prod"
},
{
"id": "3",
"display_name": "air_Prod"
},
{
"id": "5",
"display_name": "worldwide"
},
{
"id": "6",
"display_name": "structurals"
}
]
So How can I grab this JSON data from above and format it the same way that I currently have the "seg and comp" object formated? (the filenames are components.json and segments.json)
Thanks in advance.

One solution is to iterate through the array of objects, and create another object with properties named by each id. This shows what I mean, assuming you have already fetched and parsed the json into an object:
var data =
[
{
"id": "1",
"display_name": "investment_cast"
},
{
"id": "2",
"display_name": "forged_Prod"
},
{
"id": "3",
"display_name": "air_Prod"
},
{
"id": "5",
"display_name": "worldwide"
},
{
"id": "6",
"display_name": "structurals"
}
];
var seg = {};
data.forEach( function(o) {
var x = parseInt(o.id);
seg[x] = o.display_name;
});
console.log(seg);
/*
{ '1': 'investment_cast',
'2': 'forged_Prod',
'3': 'air_Prod',
'5': 'worldwide',
'6': 'structurals' }
*/
Actually in practice, I might use a utility library like lodash to do this, say with keyBy():
https://lodash.com/docs/4.17.2#keyBy
edit: keyBy() will not do exactly what you want, so ignore that part.
edit: in addition, if you are fetching 3 json files, those are async operations and so you will need to possibly combine the operations and wait until all the json fetches are done. Normally this would be done with a Promise in javascript (or a Promise library): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Here is a plunker with required and refactored code changes Working Example changes are in scripts.js file
Explaning my code:
The logic to build your required seg and comp from JSON data is to loop through your result and pick the data out of id and display_name as key & value.
function formatData(jsonData){
var obj ={};
jsonData.forEach(function(item,index){
var key = parseInt(item.id,10);
obj[key] = item.display_name;
});
return obj;
}
The above funciton takes your json data and returns back the formatted result in a object.
Next since you want all the data to be present upfront before you build your google map I would say lets load the data one by one and when we have all lets build the Map.
function GetAllDataSetsAndInititateMap() {
$.getJSON("segments.json", function(json) {
seg = formatData(json);
$.getJSON("components.json", function(json) {
comp = formatData(json);
$.getJSON("locations.json", function(json) {
myJSON = json;
BuildMap();
});
});
});
}
Having these in place, Write a new function called BuildMap and place all your current code which is present inside the $.getJSON("locations.json", function(json1) { block.
Your BuildMap function will look like
function BuildMap(){
var json1 = myJSON;
$.each(json1, function(key, data) {
// all the existing code.
});
}
This has been tested and Here is a Working Example in Plunker changes are in scripts.js file.
Hope this helps!!

For your question:
How can I grab this JSON data from above and format it the same way that I currently have the "seg and comp" object formated?
You can use $.getJSON() for your other json files (i.e. components.json and segments.json), just like you are doing with the locations.json file. Because this leads to three asynchronous requests, it would be beneficial to wait until all are completed. $.getJSON() returns a promise and you can wait until all promises are done before adding locations to the map.
You could use Promise.all() to run code after all promises are done, though it doesn't support IE. I looked for an equivalent jQuery function and found $.when (used with .done()) after reading this blog post that mentions it. That technique appears to work:
$.when($.getJSON("locations.json"), $.getJSON("segments.json"),
$.getJSON("components.json")).
done(function(locationsResponse, segResponse, compResponse) {
// Each argument is an array with the following structure: [ data, statusText, jqXHR ]
myJSON = locationsResponse[0];
var seg = segResponse[0];
var comp = compResponse[0];
//rest of code to add markers to the map
//...
});
When I looked at your plunker example, I did notice an error in the browser console:
script.js:79 Uncaught TypeError: category.data is not a function(…)
It appears that this is caused by the radio inputs calling the function filterMarkers and passing a string value instead of a reference to jQuery's selector for that input (i.e. $(this)). So you can update the inputs to all pass that reference and set the data-component_id and/or data-segment_id where appropriate. For example, the lines below:
<div class="optGroup"><input onclick="filterMarkers($(this));" type="radio" name="loc" value="investment_cast" data-segment_id="2" data-component_id="3" /> Investment Cast Products</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="structurals" /> PCC Structurals</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="airfoils" /> PCC Airfoils</div>
Should be updated like this:
<div class="optGroup"><input onclick="filterMarkers($(this));" type="radio" name="loc" value="investment_cast" data-segment_id="2" data-component_id="3" /> Investment Cast Products</div>
<div class="optChild"><input onclick="filterMarkers($(this));" type="radio" name="loc" value="structurals" data-component_id="1" /> PCC Structurals</div>
<div class="optChild"><input onclick="filterMarkers($(this));" type="radio" name="loc" value="airfoils" data-component_id="2" /> PCC Airfoils</div>
See this updated plunker.

Related

How to pass array as parameter in javascript code function?

I am sending array of objects to print function but not working.
<script>
var items = [{
"id": "1",
"name": "rishi"
}, {
"id": "2",
"name": "xyz"
}];
var output = "<button type='button' onClick='print(" + items + ")'>Print</button>";
document.getElementsByTagName("body").innerHTML = output;
function print(data) {
alert(data);
}
</script>
<body>
</body>
<script>
var items = [{
"id": "1",
"name": "rishi"
}, {
"id": "2",
"name": "xyz"
}];
var output = "<button type='button' onClick='print(" + items + ")'>Print</button>";
document.getElementsByTagName("body").innerHTML = output;
function print(data) {
alert(data);
}
</script>
<body>
</body>
It should return array when I will click on print
getElementsByTagName returns a collection of elements, so that you should access the body element by index [0]
In order to see the content of objects in the alert try to convert them to strings using JSON.stringify
var items = [{
"id": "1",
"name": "rishi"
}, {
"id": "2",
"name": "xyz"
}];
items = JSON.stringify(items.map(JSON.stringify))
var output = "<button type='button' onClick='print(" + items + ")'>Print</button>";
document.getElementsByTagName("body")[0].innerHTML = output;
function print(data) {
alert(data);
}
<body>
</body>
Try
function print(data) {
alert(JSON.stringify(data));
}
Otherwise you get only data type shown Object in this case
What you might do is get the first item the getElementsByTagName returns using document.getElementsByTagName("body")[0]
Then call the function print passing items as the argument onClick=print(items)
var items = [{
"id": "1",
"name": "rishi"
}, {
"id": "2",
"name": "xyz"
}];
var output = "<button type='button' onClick=print(items)>Print</button>";
document.getElementsByTagName("body")[0].innerHTML = output;
function print(data) {
alert(JSON.stringify(data));
}
Your issue is with document.getElementsByTagName("body").innerHTML. .getElementsByTagName doesn't return a single element, it returns a HTMLCollection, which contains all body tags. Imagine if you passed "p" into the same method; it is possible that there are multiple p tags and thus you need to get a collection back, not just one single element.
Instead, you can use document.querySelector('body') which will return the first found element of <body>, which you can then use .innerHTML on.
Lastly, you'll need to stringify your items array such that it is preserved when you pass it into your print method
See example below:
var items = [{
"id": "1",
"name": "rishi"
}, {
"id": "2",
"name": "xyz"
}];
var output = "<button type='button' onClick='print("+ JSON.stringify(items) + ")'>Print</button>";
document.querySelector("body").innerHTML = output;
function print(data) {
console.log(data);
alert(data);
}

Trouble displaying JSON data from music api

I am having trouble to display the top tracks of a searched artist using the LastFM api to get data. The api returns an object toptracks. I would like to grab details about each of the top tracks from that api data.
I am not sure if I am on the right track. Can someone take a look and let me know if I am doing something wrong?
Sample data from api:
{
"toptracks": {
"track": [{
"name": "Best I Ever Had",
"playcount": "3723918",
"listeners": "1086968",
"mbid": "00bde944-7562-446f-ad0f-3d4bdc86b69f",
"url": "https://www.last.fm/music/Drake/_/Best+I+Ever+Had",
"streamable": "0",
"artist": {
"name": "Drake",
"mbid": "b49b81cc-d5b7-4bdd-aadb-385df8de69a6",
},
"#attr": {
"rank": "1"
}
},
{
"name": "Forever",
"playcount": "1713492",
"listeners": "668998",
"url": "https://www.last.fm/music/Drake/_/Forever",
"streamable": "0",
"artist": {
"name": "Drake",
"mbid": "b49b81cc-d5b7-4bdd-aadb-385df8de69a6",
},
"#attr": {
"rank": "2"
}
}
}
function renderTracks(trackArray) {
function createHTML(track){
return `<h1>${track.name}</h1>
<h2>${track.artist[0]}</h2>
<h3>${toptracks[1].rank}</h3>
<h3>${track.playcount}</h3>`;
};
trackHTML = trackArray.map(createHTML);
return trackHTML.join("");
};
var searchString = $(".search-bar").val().toLowerCase();
var urlEncodedSearchString = encodeURIComponent(searchString);
const url = "lastFMwebsite"
axios.get(url + urlEncodedSearchString).then(function(response) {
// createHTML.push(response.data.track);
// $(".tracks-container").innerHTML = renderTracks(response.data.track);
// comented out old code above
createHTML.push(response.toptracks.track);
$(".tracks-container").innerHTML = renderTracks(response.toptracks.track);
})
I've notice that you have not parsed the response:
axios.get(url + urlEncodedSearchString).then(function(response) {
var parsed = JSON.parse(response);
$(".tracks-container").innerHTML = renderTracks(parsed.toptracks.track)
});
Another correction that I can suggest is to change the track.artist[0] to track.artist["name"] once this property returns an object instead of an array.
And about this: <h3>${toptracks[1].rank}</h3>. You will be not able to access that property because at your function you are providing just the trackproperty.
In this case you have two options: provide the whole response array or add a new parameter providing this.
function renderTracks(trackArray) {/**...*/};
//...
$(".tracks-container").innerHTML = renderTracks(parsed.toptracks)
Or
function renderTracks(trackArray, toptracks) {/**...*/};
//...
$(".tracks-container").innerHTML = renderTracks(parsed.toptracks.track, parsed.toptracks)
I hope this can help you :)
Your input JSON is not valid. You'll need to format it correctly. Once the data is correct:
createHTML.push(response.toptracks.track[0])
or
let i = 0;
for(; i < response.toptracks.track.length; i++){
createHTML.push(response.toptracks.track[i]);
}

Iterating over an array of objects?

Here is some sample data that I get from an API:
{
"Document": {
"Placemark": [
{
"name": " V5-MJW",
"address": "Aviation Road, Windhoek, Namibia",
"description": [],
"TimeStamp": {
"when": "2016-05-21T06:12:00-04:00"
},
"styleUrl": "#asset7541",
"Point": {
"coordinates": "17.0829055,-22.598271,743"
}
},
{
"name": "GSatMicro80149",
"address": "Unnamed Road, Lesotho",
"description": [],
"TimeStamp": {
"when": "2016-05-11T04:52:00-04:00"
},
"styleUrl": "#asset7543",
"Point": {
"coordinates": "27.5594894,-29.456703,1659"
}
}
]
}
}
This is my current code that is creating an array:
var flightPlanCoordinates = [];
//data being the returned values from the API.
$.each(data.Document.Placemark, function () {
var location = this.Point.coordinates.split(',');
var loc = {lat: parseFloat(location[1]), lng: parseFloat(location[0])};
flightPlanCoordinates[this.name] == null ? flightPlanCoordinates[this.name] = [] : flightPlanCoordinates[this.name].push(loc);
});
I get a lot of placemarks with the same name, I want to split each placemark with a different name into a different array.
This all works fine until I try to itterate over flightPlanCoordinates, I tried the following:
$.each(flightPlanCoordinates, function(index) {
}
But this does not work, If I log the length of flightPlanCoordinates, it results in 0, yet in Firefox Dev tools I can see the correct values inside of flightPlanCoordinates.
How would I go about doing this? Is there a better way than what I am doing here?
Please change
var flightPlanCoordinates = [];
to
var flightPlanCoordinates = {};
it should be an object, because you set it with properties like flightPlanCoordinates[this.name], where this.name is a string, not an index.

Push Json filtered key values to nested ul with Javascript

I need help pushing the values from a filtered json, I need this generate a nested ul list, I can not modify the json format at this point, I you check the console.log you will see the values to create the list, at this point I can't figure how to complete the 'for loop' to render the html markup needed, any help will be appreciated, this is the jsfiddle http://jsfiddle.net/43jh9hzz/, and if you check the console log you will see the values.
This is the Js:
var json='';
var property_set = new Set();
function iterate(obj, stack) {
json="<ul>";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
}
else {
// console.log(property);
property_set.add(property);
json+="<li>";
if(typeof obj[property] !== "number") {
json+="<li>"+obj[property]+"</li>";
console.log(obj[property]);
}
}
} json += "</li>";
}
}
var listEl = document.getElementById('output');
iterate(jsonObj)
And this is the json format:
var jsonObj =
{
"level_1": [
{
"level_1_name": "CiscoSingaporeEBC",
"level_2": [
{
"level_2_name": "Khoo Tech Puat",
"level_2_id": 2222,
"level_3": [
{
"name": "Boon Leong Ong",
"id": 6919
},
{
"name": "Kiat Ho",
"id": 6917
},
{
"name": "Overall Experience",
"id": 6918
}
]
}
]
},
{
"level_1_name": "CiscoLondonEBC",
"level_2": [
{
"level_2_name": "Bernard Mathews Ltd.",
"level_2_id": 2367,
"level_3": [
{
"name": "Barry Pascolutti",
"id": 7193
},
{
"name": "Kathrine Eilersten",
"id": 7194
},
{
"name": "Martin Rowley",
"id": 7189
}
]
},
{
"level_2_name": "FNHW Day 1",
"level_2_id": 5678,
"level_3": [
{
"name": "Jurgen Gosch",
"id": 7834
},
{
"name": "Overall Experience",
"id": 7835
}
]
},
{
"level_2_name": "Groupe Steria Day 1",
"level_2_id": 2789,
"level_3": [
{
"name": "Adam Philpott",
"id": 7919
},
{
"name": "Pranav Kumar",
"id": 7921
},
{
"name": "Steve Simlo",
"id": 7928
}
]
}
]
}
]
};
enter code here
I'm not sure if I am interpretting your request correctly, but I think this is what you want: http://jsfiddle.net/mooreinteractive/43jh9hzz/1/
Basically, you are calling the iterate function to run, but then that's it. The function actually needs to also return the value it generates.
I've added to the end of the function, after the for loop completes:
return json;
Do now the function returns the value it generated, but there are some other issues too. When you recursively call the iterate function again inside the iterate function, you actually want to add what it returns to the current json string housing all of your returned value.
So on that line I changed it from:
iterate(obj[property], stack + '.' + property);
to
json += iterate(obj[property], stack + '.' + property);
Now that other value will come back as well inside the main list you were creating in the first run of the function. Ok so that's pretty close, but one more small thing. I think when you added additional surrounding LI, you actually wanted to do an UL. I changed those to ULs and now I think the result is like a UL/LI list representing the text parts of the JSON object.
Again, that may not be exactly what you were after, but I think the main take away is using the function to return the value, not just generate it, then do nothing with it.

Populate Highchart Column From JSON

I have to create a column chart in my project using Highchart. I am using $.ajax to populate this data. My current JSON data is like this :
[{
"city": "Tokyo",
"totalA": "10",
"totalB": "15"
},
{
"city": "Seoul",
"totalA": "20",
"totalB": "27"
},
{
"city": "New York",
"totalA": "29",
"totalB": "50"
}]
How to resulting JSON string look like this:
[{
"name": "city",
"data": ["Tokyo", "Seoul", "New York"]
}, {
"name": "totalA",
"data": [10, 20, 29]
}, {
"name": "totalB",
"data": [15, 27, 50]
}]
Thank you.
Assuming all the elements look the same (they all have the same fields): Live Example
// src is the source array
// Get the fields from the first element
var fields = Object.keys(src[0]);
// Map each key to...
var result = fields.map(function(field) {
// Grab data from the original source array
var data = src.reduce(function(result, el) {
// And create an array of data
return result.concat(el[field]);
}, []);
// Format it like you want
return {name: field, data: data};
});
console.log(result);
If they aren't, the code is slightly more complicated: Live Example
// Work out the fields by iterating all of the elements
// and adding the keys that weren't found yet to an array
var fields = src.reduce(function (fields, current) {
return fields.concat(Object.keys(current).filter(function (key) {
return fields.indexOf(key) === -1;
}));
}, []);
var result = fields.map(function (field) {
// Need another step here, filter out the elements
// which don't have the field we care about
var data = src.filter(function (el) {
return !!el[field];
})
// Then continue like in the example above.
.reduce(function (result, el) {
return result.concat(el[field]);
}, []);
return {
name: field,
data: data
};
});
console.log(result);

Categories