I have some nested Json in a file called data.json. I am using fetch
to read the file in and then would like to do some filtering based on if a user has a specific option selected in a dropdown on the website.
var jsonData = [{"type": "FeatureCollection",
"features": [
{"type": 'Feature', "properties": {"id": 1}, "geometry": {"type": "Point", "coordinates": [-80.71, 28.34]}},
{"type": 'Feature', "properties": {"id": 2}, "geometry": {"type": "Point", "coordinates": [-79.89, 28.45]}},
{"type": 'Feature', "properties": {"id": 2}, "geometry": {"type": "Point", "coordinates": [-60.79, 28.32]}}
]}
]
I would like to perform some filtering on this array of features based on the "properties": {"id": #}
field. E.g. if a user selects a value that matches that id, keep that in my result display data, else remove it.
I am trying to do something via a Promise like below. I'm new to JavaScript but the usage of .filter
in the below code is my attempt to get this to work.
Ideal solution I want to achieve:
I am displaying a map of data on the U.S. Map with points relative to some locations that belong to the id
field I mentioned. I would like the user to be able to click one of the IDs via a drop-down facility in Javascript, then via their selection, filter the JSON data to only features that belong to that Id. E.g. a traditional filter you'd use on data.
function filterIds(data) {
let idFilter= document.getElementById("id-filter");
let selection = idFilter.addEventListener('change', function(event) {
return this.value;
});
data.features.map((element) => {
// spread out our array of data and filter on specific property (namely, the id key)
return {...element, properties: element.filter((property) => property.id=== selection)};
});
async function getData(url) {
let response = await fetch(url);
return await response.json();
};
getData("../data/processed/data.json") // fetch raw data
.then(data => filterIds(data));
Assuming that the OP initially needs to keep the fetched data in sync with the dropdown ... the dropdown-option's id-values after all have to reflect the feature-items of the fetched data's features
array ... the proposed steps for a main initializing process are as follows ...
features
array. Thus one later even avoids the filter task due to just looking up the id-specific feature-list based on the selected id.'change'
handling. (The following example code favors an explicit data-binding approach for the handler).// ... mocked API call ...
async function fetchData() {
return new Promise(resolve =>
setTimeout(() => resolve({
data: [{
"type": "FeatureCollection",
"features": [{
"type": 'Feature',
"properties": {
"id": 1
},
"geometry": {
"type": "Point",
"coordinates": [-80.71, 28.34]
}
}, {
"type": 'Feature',
"properties": {
"id": 2
},
"geometry": {
"type": "Point",
"coordinates": [-79.89, 28.45]
}
}, {
"type": 'Feature',
"properties": {
"id": 2
},
"geometry": {
"type": "Point",
"coordinates": [-60.79, 28.32]
}
}]
}]
}), 2000)
);
}
// one time data transformation in order to avoid filtering later.
function getFeaturesMapGroupedByPropertiesId(featureList) {
return featureList.reduce((map, featureItem) => {
const { properties: { id } } = featureItem;
(map[id] ??= []).push(featureItem);
return map;
}, {});
}
function renderDropdownOptions(node, idList) {
const { options } = node;
// delete/reset the `options` collection.
options.length = 0;
// put/add initial default selected option item.
options.add(new Option('select an id', '', true, true));
idList.forEach(id =>
options.add(new Option(`feature ${ id }`, id))
);
}
function handleFeatureChangeWithBoundFeaturesMap({ currentTarget }) {
const idBasedFeaturesMap = this;
const featureId = currentTarget.value;
console.log(
`id specific feature list for id "${ featureId }" ...`,
idBasedFeaturesMap[featureId],
);
}
async function main() {
console.log('... trigger fetching data ...');
const { data } = await fetchData();
console.log('... fetching data ... done ...', { data });
const idBasedFeaturesMap =
getFeaturesMapGroupedByPropertiesId(data[0].features);
// console.log({ idBasedFeaturesMap });
// //console.log(Object.keys(idBasedFeaturesMap));
const dropdownNode = document.querySelector('select#feature');
if (dropdownNode) {
console.log('... synchronize dropdown data ...');
renderDropdownOptions(
dropdownNode,
Object.keys(idBasedFeaturesMap),
);
dropdownNode
.addEventListener(
'change',
handleFeatureChangeWithBoundFeaturesMap.bind(idBasedFeaturesMap)
);
console.log('... synchronize dropdown data ... done!');
}
}
main();
.as-console-wrapper {
min-height: 100%;
width: 80%;
left: auto!important;
}
body { margin: 0; }
<select id="feature">
<option value="">... initializing ...</option>
<!--
<option value="1">feature 1</option>
<option value="2">feature 2</option>
//-->
</select>