Remove / add classname from a HTML elements using React hooks - html

I'm trying to remove an attripute from html element using on click on a button:
import React , {useState} from 'react';
import classNames from 'classnames';
function App () {
const [isActive, setIsActive] = useState(false);
const handleOnClick = () => {
setIsActive(!isActive);
};
return (
<InlineBlockLogIn
className={classNames('active', { 'active' : isActive})}
onClick={handleOnClick} >
<InlineBlockReg
className={classNames('', { 'active' : isActive})}
onClick={handleOnClick} >
)};
I would like to remove the "active" from InlineBlockLogIn when clicked on the InlineBlockReg and so on.
So basically if active at one div it should be inactive at the second one.
Any idea how to do so please?

The code in your question does not have a single root element, is missing closing tags and the handlers are not correct. Maybe the following code can help you:
const App = () => {
const [isActive, setIsActive] = React.useState(true);
const handleOnClick = (value) => {
setIsActive(value);
};
return (
<div>
<div
className={isActive ? "active" : ""}
onClick={() => handleOnClick(false)}
>
InlineBlockLogIn
</div>
<div
className={isActive ? "" : "active"}
onClick={() => handleOnClick(true)}
>
InlineBlockReg
</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related

Passing a custom component to material ui dialog that opens it

I am trying to pass a custom component to a MUI Dialog in such way that it should open the Dialog itself and render its children.
const CustomDialog = ({children, someCustomComponent}) => {
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return(
<>
{someCustomComponent} // use this component to call handleOpen/handleClose
<Dialog>
<DialogTitle>
<DialogTItle>
<DialogContent>{children}</DialogContent>
<DialogActions>...</DialogActions>
</Dialog>
</>
);
}
CustomDialog.propTypes = {
someCustomComponent: PropTypes.node.isRequired,
}
And then call it like this
<CustomDialog someCustomComponent={<h1>open</h1>}>
{myDialogContent}
</CustomDialog>
Is this possible? So, essentially, I don't always want a button to open my Dialog. I want to have any component I pass to it to be able to open it.
This is kind of how this is done by using Button
return(
<>
<Button onClick={handleClickOpen} />
<Dialog>
...
but I want to pass any element to it.
Thanks!
A simple way to do it is with React.cloneElement
const CustomDialog = ({ children, someCustomComponent }) => {
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
// clone the component and add the onClick handler
const customComponentClone = React.cloneElement(someCustomComponent, {
onClick: handleClickOpen
});
return (
<>
{customComponentClone}
<Dialog>
<DialogTitle>
<DialogTItle>
<DialogContent>{children}</DialogContent>
<DialogActions>...</DialogActions>
</Dialog>
</>
);
}
This way you can use it like you mentioned
<CustomDialog someCustomComponent={<h1>open</h1>}>
{myDialogContent}
</CustomDialog>
Check here a live version

TypeError: Cannot read properties of undefined (reading 'map') whole component code is not working

When I start the npm code for the cart component is not working and displayed the blank page
map function did not work. When I comment the part which is not working then another component like the header is displayed
import React from 'react';
import Header from './Front/Header/Header';
const Cart = (props ) => {
const {cartitems} =props;
const{handleAddProduct}=props;
const {handleRemoveProduct}=props;
return (
<>
<Header/>
<div className="cart-items">
<div className="cart-items-header"> cartitems</div>
{!cartitems?.length ? (
<div className="cart-items-empty"> No items added in cart</div>
) : null}
<div>
//this part of code is not working
{cartitems.map((item) => (
<div key={item.id}>
<div>
<img className="cart-items-image"
src={item.image}
alt={item.name} />
</div>
<button className='cart-items-add' onClick={()=>handleAddProduct(item)}>+</button>
<button className='cart-items-remove' onClick={()=>handleRemoveProduct(item)}>-</button>
<div className='cart-items-price'>{item.quantity}* ${item.price}</div>
</div>
))}
</div>
</div>
</>
);
}
export default Cart;
here is the code of app.js in this code I got an error that cartitems.find is not a function plz let me know how to fix this issue
const { productitems } = data;
const [cartitems, setCartItems] = useState([]);
const { user } = useContext(UserContext);
const History = useHistory();
const handleAddProduct = (product) => {
// console.log(product);
const ProductExist = cartitems.find((item) => item.id === product.id)
// console.log(ProductExist);
// setCartItems(ProductExist);
if (ProductExist) {
setCartItems(
cartitems.map((item )=> item.id ===product.id ?
{...ProductExist ,quantity:ProductExist.quantity +1}:item)
)
}
else {
setCartItems([...cartitems,{...product,quantity:1}])
console.log('ni gya');
}
}
const handleRemoveProduct = (product) => {
const ProductExist = cartitems.find((item) => item.id === product.id);
if (ProductExist.quantity === 1) {
setCartItems(cartitems.filter((item) => item.id !== product.id));
}
else {
setCartItems(
cartitems.map((item) => item.id === product.id ?
{ ...ProductExist, quantity: ProductExist.quantity - 1 }
: item)
);
}
}
You can see there is a check above the code you commented out:
{
!cartitems?.length ? (
<div className="cart-items-empty">No items added in cart</div>
) : null
}
It checks to make sure cartitems is an array before attempting to use map() on it. In the ternary statement, instead of returning null if cartitems is empty, you should return the map function so it would read:
{!cartitems?.length ? (
<div className="cart-items-empty"> No items added in cart</div>
) : cartitems.map(item => (
// template code...
))}

Using callback ref to modify scrollLeft property in React

I've got a container div with a lot of children, and an overflow-x set to scroll.
This allows me to scroll the content to the left and right using my trackpad (or drag on mobile).
But I really would like the default scroll position to be the maximum horizontal value. (i.e. scrolled all the way to the right). The relevant code for this is Element.scrollLeft = <some large value>.
I'm trying to figure out how to achieve this with React and callback refs. I have the following code:
const containerRef = useCallback(
(node) => {
if (node !== null) {
node.scrollLeft = values.length * 20;
}
},
[values.length]
);
return (
<div className={"scroll-wrapper"} ref={containerRef}>
values.map(()=>{
// Some stuff in here that's irrelevant.
});
</div>
)
(This code was based on https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node)
When I put a breakpoint in the useCallback function, I see it is properly invoked with a non-0 value, but right after the call when I inspect node.scrollLeft it is still 0.
When I inspect the DOM in Chrome, I can actually force the scrollLeft of the element to be high number, which does work.
So why doesn't the React useCallback ref work?
You should use useRef hook to work with refs.
To create ref use this:
const containerRef = useRef();
And add it to ref of div as you did before:
<div className={"scroll-wrapper"} ref={containerRef}>
...
</div>
And you should use useEffect and call it one time to set scrollLeft to the component in ref:
useEffect(() => {
ref.current.scrollLeft = 4000;
}, []);
Here is the full example: https://codesandbox.io/s/lingering-glitter-s0gok?file=/src/App.js
This is how I fixed
then just make some css issue for that
const [scrollX, setScrollX] = useState({
side: ""
});
const scrollLeftRef = useRef();
const handleScroll = (data) => {
setScrollX(prev => ({ ...prev, side: data.side }));
}
useEffect(() => {
if (scrollX.side === "right") {
scrollLeftRef.current.scrollLeft += 200;
} else {
scrollLeftRef.current.scrollLeft -= 200;
}
}, [scrollX]);
<div class="slide-sample">
<div id="slideRight" onClick={() => handleScroll({ side: "left" })} class="preSlide">
<i className="fas fa-caret-square-left" />
</div>
<div ref={scrollLeftRef} class="slideouter">
<div class="slideinner srcl">
<ul>
{
categories.map((category, i) => {
return (
<Button
key={category.id}
onClick={() => { dispatch(filterfood(category.name)); handleItemClick(i) }}
variant={activeclass === i ? "contained" : "outlined"}
size="medium"
>
{category.name}
</Button>
)
})}
</ul>
</div>
</div>
<div id="slideRight" onClick={() => handleScroll({ side: "right" })} className="nextSlide">
<i className="fas fa-caret-square-right" />
</div>
</div>

Render input fields dynamically inside a list

I have set of components where it would consist of input fields along with text rows.
As given in the image the users should be able to add categories and description. After adding them they will be rendered as a list of components. like this
Inside a category there will be tags as given in the above image and to add them i have to add a input component. This input component should be available only when the user clicks on the Add tag button below each category row. When a user clicks on it,it should enable the input(should render a input component inside the selected category row) and should be able to type the tag name on it and save it. I need to make this input field enable only when i click on the add tag button. and it should enable only in the selected category row. This is the code that i have tried.
import React, { Component, Fragment } from "react";
import { Button, Header, Input } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import ReactDOM from "react-dom";
class App extends Component {
state = {
category: "",
description: "",
categories: []
};
onChange = (e, { name, value }) => {
this.setState({ [name]: value });
};
addCategory = () => {
let { category, description } = this.state;
this.setState(prevState => ({
categories: [
...prevState.categories,
{
id: Math.random(),
title: category,
description: description,
tags: []
}
]
}));
};
addTag = id => {
let { tag, categories } = this.state;
let category = categories.find(cat => cat.id === id);
let index = categories.findIndex(cat => cat.id === id);
category.tags = [...category.tags, { name: tag }];
this.setState({
categories: [
...categories.slice(0, index),
category,
...categories.slice(++index)
]
});
};
onKeyDown = e => {
if (e.key === "Enter" && !e.shiftKey) {
console.log(e.target.value);
}
};
tags = tags => {
if (tags && tags.length > 0) {
return tags.map((tag, i) => {
return <Header key={i}>{tag.name}</Header>;
});
}
};
enableTagIn = id => {};
categories = () => {
let { categories } = this.state;
return categories.map(cat => {
return (
<Fragment key={cat.id}>
<Header>
<p>
{cat.title}
<br />
{cat.description}
</p>
</Header>
<Input
name="tag"
onKeyDown={e => {
this.onKeyDown(e);
}}
onChange={this.onChange}
/>
<Button
onClick={e => {
this.addTag(cat.id);
}}
>
Add
</Button>
{this.tags(cat.tags)}
</Fragment>
);
});
};
render() {
return (
<Fragment>
{this.categories()}
<div>
<Input name="category" onChange={this.onChange} />
<Input name="description" onChange={this.onChange} />
<Button onClick={this.addCategory}>Save</Button>
</div>
</Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This is the codesandbox url.
Any idea on how to achieve this?.
I changed your code by using function components and react hooks and i created category component which has it own state like this:
import React, { Fragment } from "react";
import { Button, Header, Input } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import ReactDOM from "react-dom";
const App = () => {
const [Category, setCategory] = React.useState({
title: "",
description: ""
});
const [Categories, setCategories] = React.useState([]);
return (
<div>
{console.log(Categories)}
<Input
value={Category.title}
onChange={e => setCategory({ ...Category, title: e.target.value })}
/>
<Input
value={Category.description}
onChange={e =>
setCategory({ ...Category, description: e.target.value })
}
/>
<Button onClick={() => setCategories([...Categories, Category])}>
Save
</Button>
<div>
{Categories.length > 0
? Categories.map(cat => <CategoryItem cat={cat} />)
: null}
</div>
</div>
);
};
const CategoryItem = ({ cat }) => {
const [value, setvalue] = React.useState("");
const [tag, addtag] = React.useState([]);
const [clicked, setclicked] = React.useState(false);
const add = () => {
setclicked(false);
addtag([...tag, value]);
};
return (
<Fragment>
<Header>
<p>
{cat.title}
<br />
{cat.description}
</p>
</Header>
<Input
name="tag"
value={value}
style={{ display: clicked ? "initial" : "none" }}
onChange={e => setvalue(e.target.value)}
/>
<Button onClick={() => (clicked ? add() : setclicked(true))}>Add</Button>
<div>{tag.length > 0 ? tag.map(tagname => <p>{tagname}</p>) : null}</div>
</Fragment>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
and here a sandbox

How to manually trigger click event in ReactJS?

How can I manually trigger a click event in ReactJS?
When a user clicks on element1, I want to automatically trigger a click on the input tag.
<div className="div-margins logoContainer">
<div id="element1" className="content" onClick={this.uploadLogoIcon}>
<div className="logoBlank" />
</div>
<input accept="image/*" type="file" className="hide"/>
</div>
You could use the ref prop to acquire a reference to the underlying HTMLInputElement object through a callback, store the reference as a class property, then use that reference to later trigger a click from your event handlers using the HTMLElement.click method.
In your render method:
<input ref={input => this.inputElement = input} ... />
In your event handler:
this.inputElement.click();
Full example:
class MyComponent extends React.Component {
render() {
return (
<div onClick={this.handleClick}>
<input ref={input => this.inputElement = input} />
</div>
);
}
handleClick = (e) => {
this.inputElement.click();
}
}
Note the ES6 arrow function that provides the correct lexical scope for this in the callback. Also note, that the object you acquire this way is an object akin to what you would acquire using document.getElementById, i.e. the actual DOM-node.
Here is the Hooks solution:
import React, {useRef} from 'react';
const MyComponent = () => {
const myRefname= useRef(null);
const handleClick = () => {
myRefname.current.focus();
}
return (
<div onClick={handleClick}>
<input ref={myRefname}/>
</div>
);
}
Got the following to work May 2018 with ES6
React Docs as a reference: https://reactjs.org/docs/refs-and-the-dom.html
import React, { Component } from "react";
class AddImage extends Component {
constructor(props) {
super(props);
this.fileUpload = React.createRef();
this.showFileUpload = this.showFileUpload.bind(this);
}
showFileUpload() {
this.fileUpload.current.click();
}
render() {
return (
<div className="AddImage">
<input
type="file"
id="my_file"
style={{ display: "none" }}
ref={this.fileUpload}
/>
<input
type="image"
src="http://www.graphicssimplified.com/wp-content/uploads/2015/04/upload-cloud.png"
width="30px"
onClick={this.showFileUpload}
/>
</div>
);
}
}
export default AddImage;
You can use ref callback which will return the node. Call click() on that node to do a programmatic click.
Getting the div node
clickDiv(el) {
el.click()
}
Setting a ref to the div node
<div
id="element1"
className="content"
ref={this.clickDiv}
onClick={this.uploadLogoIcon}
>
Check the fiddle
https://jsfiddle.net/pranesh_ravi/5skk51ap/1/
Hope it helps!
In a functional component this principle also works, it's just a slightly different syntax and way of thinking.
const UploadsWindow = () => {
// will hold a reference for our real input file
let inputFile = '';
// function to trigger our input file click
const uploadClick = e => {
e.preventDefault();
inputFile.click();
return false;
};
return (
<>
<input
type="file"
name="fileUpload"
ref={input => {
// assigns a reference so we can trigger it later
inputFile = input;
}}
multiple
/>
<a href="#" className="btn" onClick={uploadClick}>
Add or Drag Attachments Here
</a>
</>
)
}
Riffing on Aaron Hakala's answer with useRef inspired by this answer https://stackoverflow.com/a/54316368/3893510
const myRef = useRef(null);
const clickElement = (ref) => {
ref.current.dispatchEvent(
new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true,
buttons: 1,
}),
);
};
And your JSX:
<button onClick={() => clickElement(myRef)}>Click<button/>
<input ref={myRef}>
Using React Hooks and the useRef hook.
import React, { useRef } from 'react';
const MyComponent = () => {
const myInput = useRef(null);
const clickElement = () => {
// To simulate a user focusing an input you should use the
// built in .focus() method.
myInput.current?.focus();
// To simulate a click on a button you can use the .click()
// method.
// myInput.current?.click();
}
return (
<div>
<button onClick={clickElement}>
Trigger click inside input
</button>
<input ref={myInput} />
</div>
);
}
this.buttonRef.current.click();
Try this and let me know if it does not work on your end:
<input type="checkbox" name='agree' ref={input => this.inputElement = input}/>
<div onClick={() => this.inputElement.click()}>Click</div>
Clicking on the div should simulate a click on the input element
let timer;
let isDoubleClick = false;
const handleClick = () => {
if(!isDoubleClick) {
isDoubleClick = true;
timer = setTimeout(() => {
isDoubleClick = false;
props.onClick();
}, 200);
} else {
clearTimeout(timer);
props.onDoubleClick();
}
}
return <div onClick={handleClick}></div>
for typescript you could use this code to avoid getting type error
import React, { useRef } from 'react';
const MyComponent = () => {
const fileRef = useRef<HTMLInputElement>(null);
const handleClick = () => {
fileRef.current?.focus();
}
return (
<div>
<button onClick={handleClick}>
Trigger click inside input
</button>
<input ref={fileRef} />
</div>
);
}
If it doesn't work in the latest version of reactjs, try using innerRef
class MyComponent extends React.Component {
render() {
return (
<div onClick={this.handleClick}>
<input innerRef={input => this.inputElement = input} />
</div>
);
}
handleClick = (e) => {
this.inputElement.click();
}
}
imagePicker(){
this.refs.fileUploader.click();
this.setState({
imagePicker: true
})
}
<div onClick={this.imagePicker.bind(this)} >
<input type='file' style={{display: 'none'}} ref="fileUploader" onChange={this.imageOnChange} />
</div>
This work for me
How about just plain old js ?
example:
autoClick = () => {
if (something === something) {
var link = document.getElementById('dashboard-link');
link.click();
}
};
......
var clickIt = this.autoClick();
return (
<div>
<Link id="dashboard-link" to={'/dashboard'}>Dashboard</Link>
</div>
);