How to change style attribute of element with React Hooks? - reactjs

Hello I have seen tutorials but not sure how to change element attributes in React like with a button click change the width of an element. This is easy with vanilla javascript using document.querySelector. But how is it done in React?? State? or useRef? It says to avoid refs too much so is there a useState way to do this? Toggling the width is my goal, but any advice is appreciated. I don't think I am supposed to use document.querySelector...
My Attempt:
const myRef = useRef("80%");
const changeWidth = () => {
widthRef.style.width = "100px";
};
<div>
<div style ={{width:400px, height: 400px}} ref ={myRef}>
<button onClick={changeWidth}></button>
</div

you can change style directly using style prop
//
const [width, setWidth] = useState("400px")
function hanldeWidthChange() {
// you can set width to any value you want
setWidth("100px")
}
<div>
<div style ={{width: width, height: "400px"}}>
<button onClick={() => hanldeWidthChange()} ></button>
</div>
</div

Related

How to change style of input tag based on checkbox?

I have input form and input tag as a button.
Before I was able to make a button which changed styling according to clicking on it but now i try to make this input gray until user check the checkbox. I tried to use <Show> and when property but i cant use when on <Show> tag. Then I tried to use onChange property and it seem to not give me any errors. I just don't understand how can I change styling inside class=" and then connect it to checkbox function? My checkbox is made by using createSignal
Any ideas?
<input
onChange={functionForStyling}
name="submit"
type={"submit"}
value={"Sign up"}
class=""
/>
Assigning a class to a checkbox element is not different than assigning it to any html element.
Here is how you can assign a class to an html element conditionally.
import { createSignal, JSX } from 'solid-js';
import { render } from 'solid-js/web';
const App = () => {
const [isChecked, setIsChecked] = createSignal(true);
const toggle = () => setIsChecked(c => !c);
const handleChange: JSX.EventHandler<HTMLInputElement, Event> = (event) => {
setIsChecked(event.currentTarget.checked);
};
return (
<div>
<style>{`
input.checked {
transform: rotate(45deg);
}
input.unchecked {
transform: rotate(45deg);
}
`}</style>
<input
type='checkbox'
class={isChecked() ? 'checked' : 'unchecked'}
checked={isChecked()}
onChange={handleChange}
/>
{` `}
<button onclick={toggle}>Toggle</button>
</div>
);
};
render(() => <App />, document.body);
https://playground.solidjs.com/anonymous/163ffec6-1293-4702-9ef6-0425461328c3
Please keep in mind that styling a checkbox is not that straightforward. You need to use pseudo selectors etc.

Is there a way to add a tooltip to the rating component on Material UI?

I am trying to add a tooltip to each star of the rating component on Material UI [v4] but I am not being able to.
Is there a way to achieve this without having to use another rating library?
These are the links for the components I am trying to implement:
https://material-ui.com/es/api/rating/
https://material-ui.com/es/api/tooltip/
Thanks in advance!
Provide a custom IconContainerComponent and create your own Tooltip inside.
<Rating
IconContainerComponent = {
function IconContainer(props) {
// trigger your custom tooltip here
const { value, ...other } = props;
return <span {...other} />;
}
}
/>
I tried using the solution of #hamidreza which was similar to the one posted here but it did not work for me.
I know I'm a bit late to this but here is my solution:
Enclosing the <Rating> component with <Box> or a div (due to multiple child errors from Tooltip) then placing it as a child of the <Tooltip> component.
const [value, setVal] = React.useState(2);
const [tipValue, setTipValue] = React.useState(2);
<Tooltip title={tipValue === -1 ? value : tipValue}>
<Box display="inline-block">
<Rating
value={value}
onChange={(event, newValue) => {
setVal(newValue);
}}
onChangeActive={(event, newHover) => {
setTipValue(newHover);
}}
/>
</Box>
</Tooltip>
Working Demo:
https://codesandbox.io/s/blue-haze-jlvbb8?file=/demo.tsx
Splitting the tipValue and the value for me was necessary. This is to change the Tooltip message on hovering on the Rating component.

How to store changes in state using contenteditable element?

How to store changes in state using contenteditable element?
This code store it nicely, but the cursor changes to the beginning of the element.
Do I have to code the cursor position or is there an easy solution?
And no I wont use a form element.
import React, { useState } from 'react';
const About = () => {
const [text, setText] = useState('Hallo');
return (
<div className="about">
<h2>About</h2>
<div className="title column m-0"
contentEditable={true}
suppressContentEditableWarning={true}
onInput={(e) => { setText(e.target.innerHTML) }}
onBlur={(e) => { setText(e.target.innerHTML) }}
dangerouslySetInnerHTML={{ __html: text }}
></div>
</div >
)
}
export default About;
If you only want to store changes and not to have a controlled component you can use onInput prop. It will store the changed text into your state.
<div
contentEditable={true}
suppressContentEditableWarning={true}
onInput={e => setText(e.currentTarget.textContent)}
></div>
P.S: The reason that cursor loses focus is that when you dangerouslySetInnerHTML, you basically are re-mounting every data that you have in your div including the cursor position. That's one of the reasons which makes setting HTML in this way, not recommended.

Having trouble with onMouseEnter event in React

I'm trying to build a navbar, using React and hooks, where each div will change to a specific color on an onMouseEnter and onMouseLeave. I can't figure out why they're all affected if i hover over one. I guess I'm asking how I could make them independent of one another.
Sorry if this is a really obvious mistake. Still really green. Thanks again!
Here is a link to the CodeSandbox: https://codesandbox.io/s/holy-snowflake-twojb?file=/src/navbar.js
I refactored your code.
You can check it in https://codesandbox.io/s/lucid-lake-u3oox?file=/src/navbar.js
You are using the function setBackground to set the background color in the hoverStyle CSS class which affects to all <div className="hoverStyle"> tags.
There are many options to do that. If you want to do it with React, one way of do it is creating a CSS class like this:
.active {
background-color: #ffac4e;
}
then, create a functional component
const Activable = ({ className, children, bgColor}) => {
const [active, setActive] = useState('#fff');
return (
<div className={`${ className } ${ active }`
onMouseEnter = {() => setActive( bgColor )}
onMouseLeave = {() => setActive('#fff')}
>
{ children }
</div>
)
}
then replace your ` with this new component like this:
<Activable className="hoverStyle" bgColor="#ffac4e">
<div style = {navChildLeft}>2020</div>
<div style = {navChildTop}>
Shy RL <br />
Digital - Album art
</div>
</Activable>
and repeat with the rest of <div>'s
With react, it is important to think about reusable components. How can you create something that you can reuse over and over again in different parts of your project.
Take a look at this sample of your project broken into components.
https://codesandbox.io/s/holy-brook-3jror?fontsize=14&hidenavigation=1&theme=dark
I would recommend reading this to help out: https://reactjs.org/docs/thinking-in-react.html

Change the direction of ag-grid to RTL

I am using ag-grid in react, and I want to change the direction to RTL, also use of local text. Based on the ag-grid documentation enableRtl={true} would change the style of the grid. It is true when we set it permanently, but when I want to change it programmatically, it does not change. I passed the variable through props to the component for changing the direction and translating the text. This is my code
const Grid= ({dir}) =>{
return (
<div
className="ag-theme-balham"
style={{ height: '100%', width: '100%' }}
>
<AgGridReact
defaultColDef={defaultColDef}
columnDefs={column}
rowData={rowData}
enableRtl={dir === 'rtl'}
localeTextFunc={(key, defaultValue) => {
return dir === 'rtl' ? gridLocal[key] : defaultValue;
}}
/>
</div>
);
}
before changing direction
after changing direction
As it should be
I searched for the solution, but I cannot find a way to solve it.
What should I do? What is wrong with my code?
Edit: where I used the Grid component
const MainLayout = (props) => {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = useState(false);
const handleDrawerOpen = () => { setOpen(true) };
const handleDrawerClose = () => { setOpen(false) };
return (
<div >
<Topbar
setLang={props.setLang}
drawerOpen={handleDrawerOpen}
drawerClose={handleDrawerClose}
status={open}
handleSignOut={props.handleSignOut}
/>
<div style={{height:'48px'}}/>
<div className={classes.content}>
<Sidebar open={open} drawerClose={handleDrawerClose}/>
<Grid dir={theme.direction}/>
</div>
</div>
);
}
I have the same issue. After searching many times, I found only one solution.
I used angular not react, but, I can tell you the steps I used to solve this problem.
I followed the following steps:
I stored the value of the direction in the localstorage
Created a button to trigger an event that will change the value of the direction.
Get the value of the direction from the localstorage in the constructor
Inside the trigger, I changed the value on the localstorage for each click event.
finally, at each click event refresh the page with window.location.reload() to see the effect.
I know. It is not the perfect solution, but this is the only solution that worked for me. I think this problem is not found in the enterprise version of ag-grid.
Update:
I found a better solution. I use angular not React.
In angular, I used <ng-template> as follow:
<ng-template [ngIf]="AgGridDir === 'rtl'" [ngIfElse]="LeftGrid" #Withbutton>
<ag-grid-angular style="width: 100%; height: 450px;"
[class]="Table_Color_mode===Constants.light || Theme_dir===Constants.light?'ag-theme-alpine':'ag-theme-alpine-dark'"
[rowData]="ItemsMainCategories | async" [columnDefs]="columnDefs" (gridReady)="OnGridReady($event)"
[defaultColDef]="defaultColDef" [overlayLoadingTemplate]="overlayLoadingTemplate" [animateRows]="true"
[enableRtl]="true" [frameworkComponents]="agFrameworks" rowSelection="single"
(rowEditingStarted)="onRowEditingStarted($event)" (cellValueChanged)="UpdateItemMainCat($event)">
</ag-grid-angular>
</ng-template>
<ng-template #LeftGrid>
<ag-grid-angular style="width: 100%; height: 450px;"
[class]="Table_Color_mode===Constants.light || Theme_dir===Constants.light?'ag-theme-alpine':'ag-theme-alpine-dark'"
[rowData]="ItemsMainCategories | async" [columnDefs]="columnDefs" (gridReady)="OnGridReady($event)"
[defaultColDef]="defaultColDef" [overlayLoadingTemplate]="overlayLoadingTemplate" [animateRows]="true"
[enableRtl]="false" [frameworkComponents]="agFrameworks" rowSelection="single"
(rowEditingStarted)="onRowEditingStarted($event)" (cellValueChanged)="UpdateItemMainCat($event)">
</ag-grid-angular>
</ng-template>
<ng-template> is a tag created by Angular framework that can be used to render some components or HTML tags based on a condition.
As you can see, I used the same Ag-grid table with the same parameters. Each one with an ng-template. I used a variable called AgGridDir which is dynamically changed to rtl to ltr based on the user choice.
If the user chooses 'rtl' the first template is rendered and the [enableRtl]="true" is set to true, and if the user chooses 'ltr', then the second template will be rendered dynamically without reloading the page and the [enableRtl]="false".
I don't know about react much details, but, I want to share the idea.

Resources