Iterating over an array of objects? - javascript

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.

Related

Set filter by partial string in mapbox-gl

My first question here, sorry in advance for any mistake...
I'm developing a mapbox web for my own pleasure, featuring photos taked by myself in a map. Info is loaded in JSON files, with this structure:
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-8.5375900268555,42.881175994873]
},
"properties": {
"title": "Graffiti",
"description": "",
"image": {
"imageSize": [1024, 768], "imageLandscape": 1, "imageUrl": "imgs/gsa_2016_files/20160805173018_OLY_PEP3_P8052307.jpg" },
"icon": {
"iconSize": [96, 73],
"iconUrl": "imgs/gsa_2016_files/thumb_20160805173018_OLY_PEP3_P8052307.jpg"
},
"extended_info": {
"tags": "graffitis,nomada",
"place": "europa,españa,galicia,santiago de compostela"
},
"time": "2016:08:05 17:30:18",
"year": 2016,
"month": 8,
"day": 5
}
}
I work with different JSON files for each map, which are loaded this way:
var map = new mapboxgl.Map({ blah, blah... });
var layerIds = [ '2016' ];
var layerColors = [ 'rgba(255,0,0,1)' ];
function add_sources_to_map()
{
for (var i = 0; i < layerIds.length; i++) {
var id = layerIds[i];
var layerId = layerIdPrefix + id;
var geoJsonFile = 'jsons/'+ id + '.geoJSON';
map.addSource(layerId, { type: 'geojson', data: geoJsonFile });
}
}
Later on I use a function to filter elements by year:
function filterByYear(year) {
var filterFullYear = [ '==', 'year', year];
// Aplica os filtros nas capas
for (var i = 0; i < layerIds.length; i++) {
var id = layerIds[i];
map.setFilter(id, filterFullYear);
}
}
But I would like to do some more filtering, by part of tags or place content. For example, anyone with a "tag" which contains "nomada", or any "place" with "europe". I have tried to do it but failed miserably, although my knowledge of mapbox-gl or even js is limited. Can this be done? Should I change my JSON structure? Can anybody point me to some help?
TIA!
This is not supported in Mapbox-GL-JS. The issue is being tracked here: https://github.com/mapbox/mapbox-gl-js/issues/4698

Filter out Array of object by a give value and avoiding to add duplicated according to the same value

I am trying to figure out how to extract a new array of object from an existing one according to some conditions I am passing through PLUS don't copy over the new array if the element already exist.
So this is the object I have: addressesObj
Now I would like to filter the object by a given postcode for instance:
`
var PostCode = "TN37 7AJ "
var newAddressesObj = addressesObj.filter( function (duties) {
return duties.Address.Postcode === PostCode
});
`
This works correctly, it gives me back an array with 2 objects:
newAddressesObj
Now from this new array I would like to delete the records with the same Postcode so it gives me back only one object - how do I do that?
I have tried using $.inArray together with the filter but I am doing something wrong, I also would like to do that all in one go - something like this:
var PostCode = "TN37 7AJ "
var newAddressesObj = addressesObj.filter( function (duties) {
return duties.Address.Postcode === PostCode && $.inArray(PostCode, addressesObj == -1
});
any ideas?
Thanks
Add the filtered postcode into an array and keep checking the postcode array for each element looped.
var PostCode = "TN37 7AJ";
var addressesObj = [{
"Address": {
"Postcode": "TN38 8EW",
"AddressLine1": "32 Head View"
},
"Name": "Ball, Jones",
"ServiceDutyId": 0
},
{
"Address": {
"Postcode": "TN37 7AJ",
"AddressLine1": "171 Road"
},
"Name": "Trump, Albert",
"ServiceDutyId": 3259
},
{
"Address": {
"Postcode": "BN1 5AA",
"AddressLine1": "171 Road"
},
"Name": "Martin, Lucas",
"ServiceDutyId": 4256
},
{
"Address": {
"Postcode": "TN37 7AJ",
"AddressLine1": "171 Road"
},
"Name": "Trump Albert",
"ServiceDutyId": 3273
}
]
var postcodeArr = [];
var isAbsence = function(postcode) {
if (postcodeArr.indexOf(postcode) == -1) {
postcodeArr.push(postcode);
return true;
}
return false;
}
var newAddressesObj = addressesObj.filter(function(duties) {
return duties.Address.Postcode === PostCode && isAbsence(duties.Address.Postcode);
});

Google Maps / jQuery - create object from json file

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.

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.

JavaScript 2 dimension array

I have 3 arrays
var city = [
['Kaunas', 54.896872,23.892426],
['Vilnius', 54.711136,25.280685],
['Klaipeda', 55.720149,21.131401],
['Utena', 55.536403,25.59494],
];
var lake = [
['Ezeras Bijote', 55.785092,23.062956],
['Ezeras Druksiai', 55.627996,26.565228],
['Ezeras Sartai', 55.804368,25.832863],
['Ezeras Metelys', 54.300299,23.767004],
];
var shop = [
['Kauno Akropolis', 54.891665,23.917744],
['Panorama', 54.709549,25.257454],
['Europa', 54.687514,25.262886],
['Ozas', 54.638628,25.135685],
];
I want add this 3 arrays to 1 array ut don't know how to do this, will very nice if i can call form alements like this bigArr[city][1], bigArr[shop][1],bigArr[lake][1]
Using what you already have:
var bigArr = {"city": city, "lake": lake, "shop": shop};
You may be interested in compact().
Alternatively, just declare it as an object already:
var myObject = {
city: [
....
],
lake: [
....
],
shop: [
....
]
};
You should use Objects instead of Arrays. You can access them by string keys. Create them as a literal:
var coordinates = {
"city": {
Kaunas: [54.896872,23.892426],
Vilnius: [54.711136,25.280685],
Klaipeda: [55.720149,21.131401],
Utena: [55.536403,25.59494]
},
"lake": {
...
},
"shop": {
...
}
}
Then access their properties by using member operators:
Dot notation: coordinates.shop
Bracket notation: coordinates["lake"]
To get the coordinates array for Utena, you might use coordinates.city["Utena"]
You might want to create an object instead of a multidimensional array -
var bigArr = {
"city": {
Kaunas: {
"lat": 54.896872,
"lon": 23.892426
},
Vilnius: {
"lat": 54.711136,
"lon": 25.280685
},
Klaipeda: {
"lat": 55.720149,
"lon": 21.131401
},
Utena: {
"lat": 55.536403,
"lon": 25.59494
}
},
"lake": {
...
},
"shop": {
...
}
}
And then you can use it, like bigArr.city.Kaunas.lat

Categories