I need to traverse this data structure to render a set of lists. With a structure where nested data has the same structure as parent, it would be no problem - but here all models are different. There will be one list where each item contains a list of each level in this structure. Like so:
Desired result:
Unselected
| Countries | Provinces | Cities | <--- Top ul
---------------------------------------
|-China | | | <--- Sub uls
|-Denmark | | |
Selected
| Countries | Provinces | Cities |
---------------------------------------
|-China X |-Matjii X |- Go Neng |
|-Denmark |-Pausiu |- Tsau Pei X |
The X
s represent a selected option. If an item is selected, only it's information should be shown in subsequent lists. As you see above, since China
is selected, the following lists have no data from Denmark
shown.
Data structure:
{
countries: {
china: {
name: "China",
provinces: {
matjii: {
name: "Matjii",
cities: {
goneng: {
name: "Go Neng"
},
tsauPei: {
name: "Tsau Pei"
}
}
},
pausiu: {
name: "Pausiu",
cities: {...}
}
}
},
denmark: {
name: "Denmark",
counties: {
borjskada: {
name: "Borjskada",
towns: {
fjollmaska: {
name: "Fjollmaska"
}
}
},
larvmauda: {
name: "Larvmauda",
towns: {
tarnaby: {
name: "Taernaby"
}
}
}
}
}
}
}
I've tinkered with two different recursive approaches, but what stops me is always that I can not anticipate what the next level might be called (city, town or matjii).
Am I missing some simple obvious solution? Pseudo code is fine, I'm looking for a general approach to this.
Basically, i believe the key lies in normalizing the data, either from the backend or frontend (js).
In this reply, I would assume you have no choice but to do it from the front end.
Each country have different naming conventions for their geographical locations, Eg. some name it city, counties, towns, village, etc..
Despite the differences in naming, they all follow a tree like hierarchical structure. Hence, this is your angle of attack. Normalize them based on hierarchical level.
The following sample code will print out your sample data in hierarchical level. Their levels are contrasted by the amount of indentation. Copy and paste the following code and run it in your browser console.
Data:
var data = {
countries: {
china: {
name: "China",
provinces: {
matjii: {
name: "Matjii",
cities: {
goneng: {
name: "Go Neng"
},
tsauPei: {
name: "Tsau Pei"
}
}
},
pausiu: {
name: "Pausiu",
}
}
},
denmark: {
name: "Denmark",
counties: {
borjskada: {
name: "Borjskada",
towns: {
fjollmaska: {
name: "Fjollmaska"
}
}
},
larvmauda: {
name: "Larvmauda",
towns: {
tarnaby: {
name: "Taernaby"
}
}
}
}
}
}
}
Functions:
function traverseDataStructure(rootNode, nodeLevel){
if(!rootNode) return;
if(nodeLevel > 3) return; //just a secondary protection for infinite recursion
if(!nodeLevel)
nodeLevel = 0;
var indentationForPrinting = '';
for(var i=0;i<nodeLevel;i++){
indentationForPrinting += ' ';
}
console.log(indentationForPrinting + 'Traversing level ' + nodeLevel);
for(var prop in rootNode){
//prop may either by countries (level 0) or provinces (level 1) or counties (level 1) or cities (level 2) or towns (level 2)
var regionType = prop;
var regionList = getRegionList(rootNode[prop]);
console.log(indentationForPrinting + 'regionType: ' + regionType);
console.log(indentationForPrinting + 'regionList: ' + regionList);
if(regionList.length <= 0) return;
//then iterate the list of regions
for(var i=0;i<regionList.length; i++){
for(var subRegion in regionList[i]){
if (subRegion == 'name'){
var regionName = regionList[i][subRegion];
console.log(indentationForPrinting + 'regionName: ' + regionName);
} else {
traverseDataStructure({subRegion: regionList[i][subRegion]}, nodeLevel+1);
}
}
}
}
}
function getRegionList(obj){
var list = [];
for(var location in obj){
list.push(obj[location]);
}
return list;
}
Run it:
traverseDataStructure(data);
Expected output:
Hope this can give you an alternative to tackle your problem