I have a menu, rendered due to an array.map BUT I want to have a submenu rendered too but I can not find the way of achieving this
for instance I have this correctly done
import React from 'react'
export const Menu = () => {
const item = [
'option1',
'option2',
'option3',
'option4',
'opction5',
]
const subMenuItem = [
'2.option1',
'2.option2',
'2.option3',
'2.option4',
'2.option5',
'2.option6',
]
return (
<>
<div>
Hola
</div>
<ul>
{
item.map((x, index) => (
<li key={index}>
{x}
</li>
))
}
</ul>
</>
)
}
but now I want to have a submenu on option2 mapping the subMenuItem array if there is a condition in which some variable is equal to an option from item
something inside the above mapping like
if (x === 'option2') {
<ul>
subMenuItem.map((y,i)=>(
<li key={i*1000}
{y}
</li>
))
</ul>
something like that
thanks in advance
Assuming you have subMenu field inside the menu item such as :
const menu = [
{"name": 'option1'},
{"name": 'option2', "subMenu": [...]},
{"name": 'option3'},
]
You can render conditionally:
return (
<>
<div>
Hola
</div>
<ul>
{
item.map((x, index) => (
<li key={index}>
<>
{x.name}
{x.subMenu && x.subMenu.map((subMenuItem, subIndex) => (
<li key ={index + subIndex}>
{subMenuItem.name}
</li>
)}
</>
</li>
))
}
</ul>
</>
)
import React from 'react'
export const Menu = () => {
const item = [
'option1',
'option2',
'option3',
'option4',
'opction5',
]
const subMenuItem = [
'2.option1',
'2.option2',
'2.option3',
'2.option4',
'2.option5',
'2.option6',
]
return (
<>
<div>
Hola
</div>
<ul>
{
item.map((x, index) => {
return ( <li key={index}>
{x}
</li>
{if (x === 'option2') {
<ul>
{
subMenuItem.map((y,i)=>(
<li key={i*1000}>
{y}
</li>
))
}
</ul>})
})
}
</ul>
</>
)
}
Try this
this is what I did
import React from 'react'
import styled from 'styled-components'
export const Menu = () => {
const LI = styled.li`
list-style: '- ';
`
const item = [
'option1',
'option2',
'option3',
'option4',
'option5',
]
const subMenuItem = [
'2.option1',
'2.option2',
'2.option3',
'2.option4',
'2.option5',
'2.option6',
]
return (
<>
<ul>
{
item.map((x, index) => (
<LI key={index}>
{x}
<ul>
{(x === 'option2') &&
subMenuItem.map((y, i) => (
<li key={i * 1000}>
{y}
</li>
))
}
</ul>
</LI>
))
}
</ul>
</>
)
}
just put the condition inside of it as it is...first time doing this , seems tricky though :P
Related
I'm fairly new to React and I'm working on a website for a friend that uses a lot of react features. One thing this website needs is a navbar where every item in the navbar has a dropdown selection of additional nav items. I'm able to both render pages conditionally as independent nav items and create the hover dropdown on each nav item, but my issue comes into merging them together. I've tried a few things such as mapping through props twice, creating a large object where the nav item is a name and the dropdown items are subnames, but neither of those worked.
Here is the code I'm using:
function Nav(props) {
const [navItemList, setNavItemList] = useState([
{name: 'About', dropdownItem1: 'About Me', dropdownItem2: 'About Tampa Bay', id: 1},
]);
const { pages = [], setCurrentPage, currentPage } = props;
return (
<header className="flex-row">
<h1 class="name-tag">
<img src={"../../assets/Logo1.png"} />
</h1>
<nav>
<NavItems items={navItemList} />
<ul className="flex-row nav-list">
{pages.map(navItem => (
<li className={`li-spacing text-format ${currentPage.name === navItem.name && 'navActive'}`} key={navItem.id}>
<span onClick={() => { setCurrentPage(navItem) }}>{navItem.name}</span>
</li>
))}
</ul>
</nav>
</header>
)
}
function App() {
const [pages] = useState([
{
id: 1,
name: 'Home'
},
{
id: 2,
name: 'About Me'
},
{
id: 3,
name: 'About Tampa Bay'
},
])
const [currentPage, setCurrentPage] = useState(pages[0])
return (
<div>
<Nav
pages={pages}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
></Nav>
<main>
<Pages currentPage={currentPage}></Pages>
</main>
</div>
);
}
function NavItems(props) {
const items = props.items
return (
<ul className=" flex-row nav-list">
{/* map through the props so each navitem receives unique information */}
{items.map((navItem) => (
<div className="dropdown" key={navItem.id}>
<li className="nav-list-item">{ navItem.name }</li>
<div className="dropdown-item">
<p>{ navItem.dropdownItem1 }</p>
<p>{ navItem.dropdownItem2 }</p>
</div>
</div>
)) }
</ul>
)
}
export default NavItems;
Something like this maybe? This might need to be adjusted a bit to fit your styling needs.
const pages = {
home: {
name: 'Home',
subPages: {},
},
about: {
name: 'About',
subPages: {
aboutMe: {
name: 'About Me',
},
aboutTampaBay: {
name: 'About Tampa Bay',
},
},
},
}
function App() {
const [currentPageKey, setCurrentPageKey] = useState('home')
return (
<div>
<Nav pages={pages} currentPage={currentPage} setCurrentPageKey={setCurrentPageKey} />
<main>
<Pages currentPage={pages[currentPageKey]} />
</main>
</div>
)
}
function Nav(props) {
const { setCurrentPageKey, currentPage, pages } = props
return (
<header className="flex-row">
<h1 class="name-tag">
<img src={'../../assets/Logo1.png'} />
</h1>
<nav>
<ul className="flex-row nav-list">
{Object.entries(pages).map(([key, { name, subPages }]) => (
<li className={`li-spacing text-format ${currentPage.name === name && 'navActive'}`} key={key}>
<NavItems setCurrentPageKey={setCurrentPageKey} title={name} items={subPages} />
<button onClick={() => setCurrentPageKey(key)}>{name}</button>
</li>
))}
</ul>
</nav>
</header>
)
}
export default function NavItems(props) {
const { setCurrentPageKey, items, title } = props
return (
<ul className="flex-row nav-list">
<div className="dropdown">
<li className="nav-list-item">{title}</li>
<div className="dropdown-item">
{/* map through the props so each navitem receives unique information */}
{Object.entries(items).map(([key, { name }]) => (
<button onClick={() => setCurrentPageKey(key)} key={key}>
{name}
</button>
))}
</div>
</div>
</ul>
)
}
i want to change the text value in a div by clicking on a ul li item.
const text = {
value1 : 'blabla1',
value2 : 'blabla2',
value3 : 'blabla3'
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<div> </div>
By clicking on li 1 the div get the value1, by clicking on li 2 the div get the value2 etc.
Can someone give me some advice, thank you
i am write code
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const text = [
{ id: 1, value: "blabla1" },
{ id: 2, value: "blabla2" },
{ id: 3, value: "blabla3" }
];
const [textSelected, setTextSelected] = useState("");
const selectLi = (id) => {
let index = text.findIndex((x) => x.id === id);
if (index === -1) return;
setTextSelected(text[index].value);
};
return (
<>
<ul>
{text.map((x) => (
<li
onClick={() => {
selectLi(x.id);
}}
>
{x.id}
</li>
))}
</ul>
<br />
<div>{textSelected}</div>
</>
);
}
Work Demo
Here is another approach:
import React, { useState } from "react";
export default function App() {
const [listValues, setListValues] = useState([1, 2, 3]);
const text = { value1: "blabla1", value2: "blabla2", value3: "blabla3" };
const showTextValue = (index) => {
const newValues = [...listValues];
newValues[index] = Object.values(text)[index];
setListValues(newValues);
};
const content = listValues.map((val, index) => (
<li key={index} onClick={() => showTextValue(index)}>
{val}
</li>
));
return (
<div className="App">
<ul>{content}</ul>
</div>
);
}
import React from "react";
import "./styles.css";
export default function App() {
const clickHandler = (e) => {
alert("value is " + e.target.id);
let item = document.getElementById(e.target.id);
console.log(item.getAttribute("name"));
};
return (
<div className="App">
<ul>
<li id="blabla1" name="el1" onClick={clickHandler}>
1
</li>
<li id="blabla2" name="el2" onClick={clickHandler}>
2
</li>
<li id="blabla3" name="el3" onClick={clickHandler}>
3
</li>
</ul>
</div>
);
}
CodeSandbox example. You can also assign a value to a variable by using useState.
how to expand the elements present inside li . I used toggle on selected
I tried to add a default propertied selected false then onClick of the li I ensures if the values matches then selected should be true and displays that particular section ,and onClick of same it should collapse
Is it possible to open always the first dropdown remaining should be closed and when clicked other it open another li dropdown.
Currently onClick is not working
Here is my code
Demo
export default function App() {
const filterAddition = X.map((item) => ({
...item,
menus: item.menus.map((items) => ({
...items,
selected: false
}))
}));
const handleOnClick = (event) => {
filterAddition.map((item) => {
item.menus.map((items) => {
if (items.El=== event.target.value) {
return {
...items,
selected: !item.selected
};
}
});
});
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<nav className="animated bounceInDown">
{filterAddition.map(({ menus }, idx) => {
return menus.map(({ El, subSection, selected }, idx) => (
<ul key={idx}>
<li className="sub-menu" value={El} onClick={handleOnClick}>
<a href="#settings">
{El}
<div class="fa fa-caret-down right"></div>
</a>
{selected && (
<ul>
{subSection.map(({ E }, i) => (
<li key={E}>
{E}
</li>
))}
</ul>
)}
</li>
</ul>
));
})}
</nav>
</div>
);
}
So much to change.
First, you have to use useState to make component reactive when data is change.
Second, onClick have to change.
Third, try to read documentation especially about react hooks, state and lifecycle.
see this https://codesandbox.io/s/pensive-cloud-9mco1?file=/src/App.js
import React, { useState, useEffect } from "react";
import "./styles.css";
const X = [
{
detail1: "FirstJob",
menus: [
{
Order: 1,
El: " Record Management",
subSection: [
{
E: "Check Notification",
Order: "CheckNotification"
},
{
E: "Check Record",
Order: "CheckRecord"
}
]
},
{
Order: 2,
El: "Management",
subSection: [
{
E: "Notification",
Order: "Notification"
},
{
E: "Check",
Order: "Check"
}
]
}
]
}
];
export default function App() {
const [state, setState] = useState(X);
useEffect(() => {
const filterAddition = X.map((item) => ({
...item,
menus: item.menus.map((items) => ({
...items,
selected: false
}))
}));
setState(filterAddition);
}, []);
const handleOnClick = (label) => {
const temp = JSON.parse(JSON.stringify(state));
for(let i in temp) {
const menus = temp[i].menus;
for(let j in menus) {
const item = temp[i].menus[j];
if(item.El === label) {
item.selected = !item.selected;
}
}
}
setState(temp);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<nav className="animated bounceInDown">
{state.map(({ menus }, idx) => {
return menus.map(({ El, subSection, selected }, idx) => (
<ul key={idx}>
<li className="sub-menu" value={El} onClick={() => handleOnClick(El)}>
<a href="#settings">
{El}
<div className="fa fa-caret-down right"></div>
</a>
{selected && (
<ul>
{subSection.map(({ E }, i) => (
<li key={E}>
{E}
</li>
))}
</ul>
)}
</li>
</ul>
));
})}
</nav>
</div>
);
}
I am very new to react and js,
I have a menu and submenu, I use a list to map data,
I want to write a function, so onmouseover one item in the list,
if it has submenu, it will show.
the problem is that I can't select the submenu using ref.
It is just too complicated for me, any help would be much appreciated!
enter image description here
import React, { Component } from "react";
export class Menu extends Component {
constructor(props) {
super(props);
this.liRefs = [];
}
showSubmenu = (e) => {
// this.liRefs.current.style.display = "block";
for (var i = 0; i < this.liRefs.length; i++) {
this.liRefs[i].current.style.display = "block";
}
// console.log(this.liRefs[10]);
};
getStyle = (e) => {
e.target.style.background = "red";
};
render() {
return (
<ul className="mainmenu">
{this.props.items.map((i) =>
i.subitems ? (
<li key={i.id} onMouseOver={this.showSubmenu}>
{i.icon}
{i.name}
<ul key={i.id} ref={(ref) => (this.liRefs[i.id] = ref)}>
{i.subitems.map((item) => (
<div key={item.id} className="submenu">
{item.icon}
{item.name}
</div>
))}
</ul>
</li>
) : (
<li key={i.id}>
{i.icon}
{i.name}
{i.img}
</li>
)
)}
</ul>
);
}
}
export default Menu;
You are giving ref value to this. liRefs[i.id] and accessing through this. liRefs[i] so that both are the different change your code as below:
{this.props.items.map((i,index) =>
i.subitems ? (
<li key={i.id} onMouseOver={this.showSubmenu}>
{i.icon}
{i.name}
<ul key={i.id} ref={(ref) => (this.liRefs[i.id] = ref)}>
{i.subitems.map((item) => (
<div key={item.id} className="submenu">
{item.icon}
{item.name}
</div>
))}
</ul>
</li>
) : (
<li key={i.id}>
{i.icon}
{i.name}
{i.img}
</li>
)
)}
I am new to React, I want to hide parent div if child is having null, li data is passing with props
import React from 'react';
const PublicationTags = (props) => {
return (
<div className="publication-tags">
<h4>Темы публикации</h4>
<ul>
{props.data &&
props.data.tag_names &&
props.data.tag_names.map((tag_name, key) => (
<li key={key}>
{tag_name}
</li>
))}
</ul>
</div>
);
};
export default PublicationTags;
If there is no data on li items I want to hide the and tag.
<ParentDiv style={this.props.data===null ? {display:'none'}:{display:'flex'}>{this.props.data}</ParentDiv>
Hope this helps.
Depends on the whole structure of the app but you could do something like:
import React from 'react';
const PublicationTags = props => {
if (!props.data.length) {
return null;
}
return (
<div className="publication-tags">
<h4>Темы публикации</h4>
<ul>
{props.data &&
props.data.tag_names &&
props.data.tag_names.map((tag_name, key) => (
<li key={key}>
{tag_name}
</li>
))}
</ul>
</div>
);
};
export default PublicationTags;
or:
import React from 'react';
const PublicationTags = props => {
return props.data.length ? (
<div className="publication-tags">
<h4>Темы публикации</h4>
<ul>
{props.data &&
props.data.tag_names &&
props.data.tag_names.map((tag_name, key) => (
<li key={key}>
{tag_name}
</li>
))}
</ul>
</div>
) : null;
};
export default PublicationTags;