Highlight current and up-one-level URL - javascript

I have a list of navlinks. When I'm on a certain page, that navlink should be highlighted. I also want the page up (only) one level to have its navlink highlighted as well, so:
All pages: /blogs, blogs/careers, blogs/authors
Page: /blogs/author
Highlight: /blogs/author, /blogs
Page: /blogs/author/Lauren-Stephenson
Highlight: /blogs/author/Lauren-Stephenson, blogs/authors
Here's how I'm doing it:
import React from 'react';
const navlinks = ["/blogs", "blogs/careers", "blogs/authors"]
const currentPath = "/blogs/authors/Lauren-Stephenson"
export function App(props) {
return (
<div className='App'>
{navlinks.map((links) =>
<div style={{color: currentPath.includes(links) ? 'green' : 'white'}}>{links}</div>
)}
</div>
);
}
But my code not only highlights /blogs/Authors/, it also highlights /blogs, which is incorrect, because I only want the page up one level to be highlighted.
How can I do this?

so maybe adding this condidtion might help you!
style={{color: currentPath.includes(links) && currentPath.length!==links.length ? 'green' : 'white'}}
it will be sure that it's not the same, if this wasn't the case you can change it from equals to < or > based on your need

Related

React, How to replace Unordered list bullets with images in the TreeView?

I am using react. I am able to generate a tree from xml file. Currently treeview is showing as an unordered list. How to replace that with images?
Please find my sandbox: https://codesandbox.io/s/falling-waterfall-2irybs
The code is working fine in Visual Studio. I am not sure how to use sandbox, not able to understand sandbox error.
Images are also included in the Sandbox.
On page load tree is collapsed showing service and sales two nodes with PLUS image.
when node is open, image will convert into minus image. After expand, all opened nodes will show minus image except the last one. Last node will show paper image.
Please help in fixing my treeview code.
Thanks a lot.
You would need to re-style the li element's ::marker selector. If you are open to using a 3rd-party css-in-JS solution then I would suggest using the styled-components package.
Here's an example implementation:
import styled from "styled-components";
import plus from "./plus.gif";
import minus from "./minus.gif";
import paper from "./paper.gif";
const StyledLI = styled.li`
::marker {
content: url(${({ expanded, isLeaf }) =>
isLeaf ? paper : expanded ? minus : plus});
}
`;
Pass expanded and isLeaf props to the new styled component when rendering.
class TreeNode extends React.Component {
render() {
const { node, onToggle } = this.props;
const activeChildren =
node.isActive && node.nodes.length ? (
<ul>
{node.nodes.map((node) => (
<TreeNode
id={node.id}
key={node.key_id}
node={node}
onToggle={onToggle}
/>
))}
</ul>
) : null;
return (
<StyledLI
id={node.id}
expanded={node.isActive} // <-- expanded if active
isLeaf={!node.nodes.length} // <-- leaf node if no children nodes
linkpagename={node.linkpagename}
key={node.key_id}
onClick={(event) => {
event.stopPropagation();
onToggle(node);
}}
>
<Link
to={node.linkpagename}
style={{ textDecoration: "none", color: "#000000" }}
>
{node.description}
</Link>{" "}
- {node.key_id} - {node.linkpagename}
{activeChildren}
</StyledLI>
);
}
}

React: how to set initial random useState value without useEffect?

I want to display 2 different DIVs randomly: one or another. So I try to keep a random boolean state variable and do the render depending on it.
Let's try to display BLUE sign in the blue box, and RED sign in the red box, for simplicity.
import React, {useState} from 'react';
const Loader = () => {
const [redLoader, setRedLoader] = useState(Math.random() < 0.5);
const loader = redLoader ?
<div style={{ backgroundColor: "red" }} key="red">
<div>RED</div>
</div>:
<div style={{ backgroundColor: "blue" }} key="blue">
<div>BLUE</div>
</div>
return (
<div className="full-screen-loader">
{loader}
</div>
)
};
export default Loader;
But sometimes I see the BLUE sign in the red box, for example.
just example
So React renders children from another parent.
If I define my random boolean variable out of the Component, nothing changes.
The only thing I can do is set the random redLoader variable inside useEffect, and then this will work.
So how can I define random state variable before the render, not in useEffect?
And why does React behave like this?
React version: 16.13.1
Based on your comments, you should use a useRef instead of useState: this will persist your data but will not cause a rerender.
const redLoader = useRef(Math.random() < 0.5);
// code
const loader = redLoader.current ?
// more code

React default className ... Before ternary operator kicks in

import './App.css'
import {Button} from "antd"
<Button
shape="round"
className={
istrue === "itstrue" ? "trueclass" : "trueclass active"
}
>
TEXT
</Button>
Is it possible to set a default className ... just to start because const [istrue, setIsTrue] = useState(["itstrue"]); isn't working. It starts with itstrue state but ... the button always starts out with the non active state. I need it to start with the active state.
Can someone please help me? Thank you
You need to specify the conditional class names in react as:
className={"trueclass " + (!itstrue ? 'active' : '')}
By this the trueclass will be applied independent of the condition and the class active will only be applied when itstrue is false.

React - Problems with function parameters for assigning values

I have a sidebar where it is possible to change the background of the sidebar as a background, I store pictures in the object, everything worked well for me until I decided to add a second property "color" inside the object, that is, in addition to changing the background, the color of the text also changes. it looks like this
I think that the essence is clear, but as I mentioned earlier, the problems started when I decided to add a second property, that is, the color of the text
The problem is that the color property does not work for me, that is, it works, but in this case the sidebar background does not work
My object looks very simple
import Bg from "../../SideBar/Background/mac.jpg"
import Pink from "../../SideBar/Background/pink.jpg"
import Anapa from "../../SideBar/Background/anapa.jpg"
const SideBarBackgrounds = [
{
SideBarWallpaper: Bg,
color: "red",
},
{
SideBarWallpaper: Pink,
color: "green",
},
{
SideBarWallpaper: Anapa,
color: "yellow",
},
].map((item) => {
return {
SideBarWallpaper: item.SideBarWallpaper,
color: item.color,
}
}
)
export default SideBarBackgrounds;
That is, I import the picture and apply it as the value for the SideBarWallpaper properties then create a second property named color and apply the string as the color
Then I use local storage to save the user changes.
export const CounterContext = createContext([]);
export default function ThemeDoc(props) {
const [SideBarBackground, SetSideBarBackground] = useState(JSON.parse(localStorage.getItem("BgKey")));
useEffect(() => {
localStorage.setItem("BgKey", JSON.stringify(SideBarBackground));
})
const ChangeSideBarWallpaper = (SideBarWallpaper) => {
localStorage.setItem('BgKey', JSON.stringify(SideBarWallpaper));
SetSideBarBackground(SideBarWallpaper);
}
return (
<div className="page-wrapper chiller-theme toggled">
<CounterContext.Provider value={{
SideBarWallpaperValue: [SideBarBackground, SetSideBarBackground],
}}>
<SideBar ChangeSideBarWallpaper={ChangeSideBarWallpaper} SideBarPageContent={SideBarPageContent} {...props} />
</CounterContext.Provider>
</div>
);
}
As you can see, I use React Context since I have a lot of themes and I import them in many files, in this case I deleted everything personal and left only the code that belongs to the background of the sidebar
Then I have a component called SideBarWallpaperContainer where I import my object, create a loop using a map, process each property from the object and finally import the SideBarWallpaperContainer component inside the SideBarModal component
export default function SideBarWallpaperContainer(props) {
const SideBarWallpaperList = SideBarBackgrounds.map((theme, index) => {
return (
<img key={index} width={"70"} height={"55"} src={theme.SideBarWallpaper}
className={"SideBar_Appearance_Select_Icon"}
onClick={() => props.ChangeSideBarWallpaper(theme.SideBarWallpaper)} alt={"Select Theme"}/>
);
})
return (
<>
{SideBarWallpaperList}
</>
);
}
SideBarModal.jsx
const DraggableDialog = (props) => {
...
return(
<SideBarWallpaperContainer {...props} />
...
);
}
Through props, I get the ChangeSideBarWallpaper method to change the background and color
And the color for the sidebar text I get using useContext it looks like this
SideBarMenu.jsx
export default function SideBarMenu(props) {
const {SideBarWallpaperValue} = React.useContext(CounterContext);
const [SideBarWallpaperTheme,] = SideBarWallpaperValue;
const SideBarWallpaperStyle = SideBarWallpaperTheme;
return(
<Link
style={{ color: SideBarWallpaperStyle && SideBarWallpaperStyle.color,}}>{item.name}
</Link>
);
}
Now when you roughly understand how all the logic works, I want to explain the problem. The problem is that either the sidebar color or the background does not work for me, please pay attention to the method
props.ChangeSideBarWallpaper (theme.SideBarWallpaper)}
When I use theme.SideBarWallpaper as a parameter inside the ChangeSideBarWallpaper method, only the background works for me and not the color, and this is of course logical, then I tried to apply 2 parameters, the color and the background, it looked like this
onClick={() => props.ChangeSideBarWallpaper(theme.SideBarWallpaper, theme.color)}
But in this case, only the background also worked and the only solution that remained for me to transfer the entire value, it looked like this
onClick={() => props.ChangeSideBarWallpaper(theme)}
And then I was surprised now only the sidebar color works for me but the background does not work, You can look at the picture (sorry if I'm so long and boring to explain :) I just want you to understand the problem as clearly as possible)
I decided to check if I get a picture and yes I get
Now that you understand the problem, I will be interested in hearing your advice, thank you for paying attention to my long question.
Before I demonstrate the solution, I would like to say that the problem lies with me, I, as always, introduced myself impatiently and inattentively: (it turns out that I forgot that in the SideBar component I get the SideBarBackground value in short, the code looked like this
const {someValue} = useContext(SideBarContext);
const {SideBarValue, SideBarWallpaperValue} = React.useContext(CounterContext);
const [SideBarTheme] = SideBarValue;
const [SideBarBackground] = SideBarWallpaperValue;
<div style={{backgroundImage: `url(${SideBarBackground})`}}>
...
</div>
Then I got the SideBarWallpaper value
<div style={{backgroundImage: `url(${SideBarBackground.SideBarWallpaper})`}}>
...
</div>

Text editor value disappears in React Js

I am making a simple accordion and inside each accordion, there is a text editor.
Accordion.js
<div className="wrapper">
{accordionData.map((item, index) => (
<Accordion>
<Heading>
<div
style={{ padding: "10px", cursor: "pointer" }}
className="heading"
onClick={() => toggleHandler(index)}
>
{toggleValue !== index ? `Expand` : `Shrink`}
</div>
</Heading>
<Text> {toggleValue === index && item.content && <EditorContainer />} </Text>
</Accordion>
))}
</div>
Here accordion is made up of as a component. This line {toggleValue === index && item.content && <EditorContainer />} is made to check the accordion clicked and then it loads the content and text editor accordingly.
Complete working example:
https://codesandbox.io/s/react-accordion-forked-dcqbo
Steps to reproduce the issue:
-> Open the above link
-> There will be three accordion
-> Click on any of the accordion, that will change the text from Expand to Shrink
-> Now fill some random text inside the editor then click on the text Shrink
-> Again open the same accordion by clicking Expand
-> Now already entered value is missing
I doubt it happens because every time we expand/shrink, the text_editor.js component gets called and that has the state value like,
this.state = {
editorState: EditorState.createEmpty()
};
Here instead of EditorState.createEmpty(), Should I need to give any other thing?
Requirement:
How can I store the already entered value in the text editor. Even though user clicks expand/shrink, the entered text needs to be remain there in the editor.
Any help is much appreciated.
You are correct, the entered value is missing because you are unmounting the EditorContainer component when its shrinked — that when you expand it again it creates a new editorState which is empty.
2 Possible solutions I could think of.
Move editorState and onEditorStateChange to the Parent component and pass that to EditorContainer. This way, when we unmount the EditorContainer we won't lose the previous editorState because it's on the Parent.
We wrap our EditorContainer inside a div and we'll apply a display style when we toggle between shrink/expand. This way, we are only hiding the EditorContainer not unmounting so its states will retain.
I would choose to implement the 2nd solution because we only have to make changes to our Accordion.js file. In either ways, I would create a new component that would handle the current item. I call it NormalAccordionItem.
const NormalAccordionItem = ({ data }) => {
const [show, setShow] = useState(false);
function toggle() {
setShow((prev) => !prev);
}
return (
<Accordion>
<Heading>
<div
style={{ padding: "10px", cursor: "pointer" }}
className="heading"
onClick={toggle}
>
{show ? "Shrink" : "Expand"}
</div>
</Heading>
<Text>
<div style={{ display: show ? "block" : "none" }}> // notice this
<EditorContainer />
</div>
</Text>
</Accordion>
);
};
Then on our NormalAccordion we'll use NormalAccordionItem.
const NormalAccordion = () => {
return (
<div className="wrapper">
{accordionData.map((data) => (
<NormalAccordionItem data={data} key={data.id} />
))}
</div>
);
};
That's it, check the demo below.
Edit Updated demo to expand NormalAccordionItem one at a time.

Categories