dilettante dilettante - 4 months ago 19
JSON Question

Reactjs: trouble iterating over nested json array

I have a json file with a tree-like structure that could go down several levels, which looks something like this, and am trying to convert it into a menu (with children elements a sub-menu):

[
{
"label": {
"en": "Home"
},
"icon": "/images/nav/home.png",
"link": "/",
"type": "basic"
},
{
"label": {
"en": "Channels"
},
"icon": "/images/nav/channels.png",
"type": "children",
"children": [
{
"label": {
"en": "Getting Started"
},
"link": "/getting-started",
"type": "basic"
},
{
"label": {
"en": "Recommendations"
},
"link": "/recommendations",
"type": "basic"
},
{
"label": {
"en": "Calendar View"
},
"link": "/calendar",
"type": "basic"
},
{
"label": {
"en": "My Pictures"
},
"link": "/account/media",
"type": "basic"
},
{
"type": "space"
},
{
"label": {
"en": "All Channels"
},
"link": "/channels",
"type": "basic"
},
{
"label": {
"en": "Channel 1"
},
"link": "/channels/channel-1",
"type": "statuses",
"datasource": "/data/1",
"children": [
{
"label": {
"en": "Channel 1-1"
},
"link": "/channels/channel-1-1",
"type": "basic"
},
{
"label": {
"en": "Channel 1-2"
},
"link": "/channels/channel-1-2",
"type": "basic"
},
{
"label": {
"en": "Channel 1-3"
},
"link": "/channels/channel-1-3",
"type": "basic"
},
{
"label": {
"en": "Channel 1-4"
},
"link": "/channels/channel-1-4",
"type": "basic"
},
{
"label": {
"en": "Channel 1-5"
},
"link": "/channels/channel-1-5",
"type": "basic"
}
]
},
{
"label": {
"en": "Channel 2"
},
"link": "/channels/2",
"type": "statuses",
"datasource": "/data/2",
"children": [
{
"label": {
"en": "Channel 2"
},
"link": "/channels/channel-2",
"type": "basic"
},
{
"label": {
"en": "Channel 2-1"
},
"link": "/channels/channel-2-1",
"type": "basic"
},
{
"label": {
"en": "Channel 2-2"
},
"link": "/channels/channel-2-2",
"type": "basic"
},
{
"label": {
"en": "Channel 2-3"
},
"link": "/channels/channel-2-3",
"type": "basic"
},
{
"label": {
"en": "Channel 2-4"
},
"link": "/channels/channel-2-4",
"type": "basic"
}
]
},
{
"type": "custom",
"content": "<div><span class=\"green_bull\">&bull;</span>Currently Online</div><div><span class=\"red_bull\">&bull;</span>Currently Offline</div>"
}
]
},
{
"label": {
"en": "Shows"
},
"icon": "/images/nav/shows.png",
"type": "children",
"children": [
{
"label": {
"en": "LIVE"
},
"link": "/live",
"type": "basic"
},
{
"label": {
"en": "Browse Shows"
},
"link": "/live",
"type": "basic"
},
{
"label": {
"en": "Full Schedule"
},
"link": "/live",
"type": "basic"
},
{
"label": {
"en": "Upcoming Shows"
},
"type": "components",
"component": "navShow",
"datasource": "/shows/upcoming?limit=3"
}
]
},
{
"label": {
"en": "Community"
},
"icon": "/images/nav/community.png",
"type": "children",
"children": [
{
"label": {
"en": "Latest"
},
"link": "/community",
"type": "basic"
},
{
"label": {
"en": "Best of"
},
"link": "/community/highlight",
"type": "basic"
},
{
"label": {
"en": "Discussion Boards"
},
"link": "http://forum.slooh.askmp.ca/",
"type": "basic"
},
{
"label": {
"en": "Rankings"
},
"link": "/community/rankings",
"type": "basic"
},
{
"label": {
"en": "Full Listings"
},
"link": "/community/listings",
"type": "basic"
},
{
"type": "space"
},
{
"label": {
"en": "Hot this Month"
},
"type": "basic-loaded",
"datasource": "/community/hot"
},
{
"type": "space"
},
{
"type": "component",
"component": "nav",
"datasource": "/data/nav"
},
{
"type": "custom",
"content": "[social media HTML]"
}
]
},
{
"label": {
"en": "About"
},
"icon": "/images/nav/about.png",
"type": "children",
"children": [
{
"label": {
"en": "Our Values"
},
"link": "/about",
"type": "basic"
},
{
"label": {
"en": "In the News"
},
"link": "/about/media",
"type": "basic"
},
{
"label": {
"en": "The Team"
},
"link": "/about/#team",
"type": "basic"
},
{
"label": {
"en": "Guests"
},
"link": "/about/#guests",
"type": "basic"
},
{
"label": {
"en": "Partners"
},
"link": "/about/#partners",
"type": "basic"
},
{
"label": {
"en": "Media Kit"
},
"link": "/about/media",
"type": "basic"
},
{
"label": {
"en": "Contact Us"
},
"link": "/about/#contact",
"type": "basic"
},
{
"label": {
"en": "Upcoming Shows"
},
"type": "components",
"component": "navShow",
"datasource": "/data/shows/upcoming?limit=1"
}
]
},
{
"label": {
"en": "Help"
},
"icon": "/images/nav/help.png",
"link": "/",
"type": "children",
"children": [
{
"label": {
"en": "New here?"
},
"link": "/about",
"type": "basic"
},
{
"type": "space"
},
{
"label": {
"en": "Guides"
},
"link": "/help",
"type": "basic"
},
{
"label": {
"en": "Troubleshooting"
},
"link": "/help/#troubleshooting",
"type": "basic"
},
{
"label": {
"en": "Practice Activities"
},
"link": "/help#practice",
"type": "basic"
},
{
"label": {
"en": "Image Management"
},
"link": "/help/images",
"type": "basic"
},
{
"label": {
"en": "Photography 101"
},
"link": "/help/photography",
"type": "basic"
},
{
"label": {
"en": "What’s What?"
},
"link": "/community/whats",
"type": "basic"
},
{
"label": {
"en": "Hints and Tips"
},
"link": "/help/#hints",
"type": "basic"
},
{
"type": "space"
},
{
"label": {
"en": "Trouble Logging In?"
},
"link": "/help/account",
"type": "basic"
},
{
"label": {
"en": "Pricing Tiers"
},
"link": "/help/#account",
"type": "basic"
},
{
"label": {
"en": "Account FAQs"
},
"link": "/help/#account",
"type": "basic"
},
{
"label": {
"en": "Shows FAQs"
},
"link": "/help/shows",
"type": "basic"
},
{
"label": {
"en": "Reservations FAQs"
},
"link": "/help/faqs",
"type": "basic"
},
{
"type": "space"
},
{
"label": {
"en": "Contact Customer Support"
},
"link": "/help/contact",
"type": "basic"
},
{
"label": {
"en": "Site Feedback"
},
"link": "/help/contact#feedback",
"type": "basic"
}
]
},
{
"label": {
"en": "Settings"
},
"icon": "/images/nav/settings.png",
"link": "/",
"type": "children",
"children": [
{
"label": {
"en": "Personal Profile"
},
"link": "/account",
"type": "basic"
},
{
"label": {
"en": "Subscription Management"
},
"link": "/account/subscription",
"type": "basic"
},
{
"label": {
"en": "Alerts & Email Settings"
},
"link": "/account/#notifications",
"type": "basic"
}
]
}
]


I'm attempting to iterate through it, and create a secondary navigation out of the children.

The top level is easy enough to get at, and the second level is almost there. When mapping over children (in GetChildren below), though, I can't get anything that's a child array, only direct objects. So, I can get {child.link}, but {child.label.en} returns an error. Should I be approaching this a smarter way?

var GetChildren = React.createClass({
render: function() {
var childlink = this.props.data.map(function (child, i){
return (
<a key = {i} href={child.link}> {child.label.en}</a>
);
});
return (
<li className="childlist">
{childlink}
</li>
);
}
});

var MenuComponent = React.createClass({
getInitialState: function() {
return {
condition: [],
menuItem: []
};
},
componentDidMount: function() {
$.get(this.props.source, function(result) {
var items = result;
if (this.isMounted()) {
this.setState({
menuItem: items,
condition: false
});
}
}.bind(this));
},
render: function(condition) {
PrimaryMenu = this.state.menuItem || [];

return (
<aside>
<nav>
<ul>
{PrimaryMenu.map(function(el, i){
if (el.type == "basic") {
var PrimaryMenuLink = el.link;
} else {
PrimaryMenuLink = '/' +el.label.en.toLowerCase();
}
return <li key={i}> <a data-nav={'nav-' + el.label.en.toLowerCase()}>
{el.label.en}</a></li>

})}
</ul>
</nav>
{PrimaryMenu.map(function(el, i){
if (el.type == "children") {
return <section key={i} id={'nav-' + el.label.en.toLowerCase()}><ul><GetChildren data={el.children}/> </ul></section>
}

})}

</aside>
);
}
});

Answer

The problem may come from some of the json nodes that doesn't have the label property. Like this node:

{
   "type": "space"
},

As a result, it will generate "cannot read property of undefined" on the label property when reading en.

You should verify all the children nodes to be sure label is existing. Verify link too to avoid getting undefined as href props

Comments