To expand the visual, I need to pass the Onclick function to antd Expand icon(shown below).
const showModal = () => {
setIsModalOpen(true);
};
const handleOk = () => {
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
This is how i passed it to normal button currently.
<div className="expandButton">
<button
type="button"
className="fullScreenButton"
onClick={showModal}
>
Click
</button>
</div>
Instead of this way can i pass the onclick function directly to react antd icon?
Current antd icon.
<div>
<ExpandAltOutlined style={{ fontSize: "150%" }} />
</div>
Simply add an onClick event
<ExpandAltOutlined style={{ fontSize: "150%" }} onClick={()=>console.log('hj')} />
Related
I'm kinda new to ReactJs, I'm trying to disable a button in my app when that button is pressed. I have a function called "disableButtonEG" but it does nothing when I pressed it.
function disableButtonEG= () => {
button.disabled = true
};
<Button
title="Press to disable"
buttonStyle={{backgroundColor: PrimaryColor, borderRadius: 10}}
titleStyle={{fontSize:13}}
onPress={disableButtonEG}
/>
Any assist is appreciated
Try this,
function App() {
const [disable, setDisable] = React.useState(false);
return (
<button disabled={disable} onClick={() => setDisable(true)}>
Click me!
</button>
);
}
Buttons have a disabled attribute, you can set this to true or false to disable the button. You should also be using onClick instead of onPress.
Here is an example of one way to achieve what you are trying to do in ReactJS
import React from "react";
function App() {
const [disable, setDisable] = React.useState(false);
return (
<button disabled={disable} onClick={() => setDisable(true)}>
Disable Button
</button>
);
}
export default App
EDIT: Disable via function
import React from "react";
function App() {
const [disable, setDisable] = React.useState(false);
function disableButton() {
setDisable(true)
}
return (
<button disabled={disable} onClick={disableButton}>
Disable Button
</button>
);
}
export default App
I don't think onPress handler exists in button.
Please try with onMouseDown instead of onPress
Looks like you wrote the function syntax wrong. If you are still having problems after fixing it, You can use state. For example, I have a disabled state which has an initial value of false
const [disabled, setDisabled] = useState(false);
And a function that will change it to true
const disableButtonEG = () => {
setDisabled(true);
};
Then modify the Button component like this
<Button
title="Press to disable"
buttonStyle={{ backgroundColor: PrimaryColor, borderRadius: 10 }}
titleStyle={{ fontSize: 13 }}
disabled={disabled}
onPress={disableButtonEG}
/>
I'm using a custom hook to open a modal which will perform different actions.
To open and close the modal im using the custom hook useSongUtils methods openModal and closeModal:
export const useSongUtils = () => {
const [isEditing, setIsEditing] = useState(false);
const openModal = ({ cellData }) => {
// outputs undefined
console.log('cell data is', cellData);
setIsEditing(true);
};
const closeModal = () => {
setIsEditing(false);
};
return {
closeModal, isEditing, setIsEditing, openModal,
};
};
And then importing the returned object into my component, where I have a method for a VirtualTable that renders some action links.
The cell data is an id and it is displayed correctly in the optionsRender method (both links work - I get the id). However, the idea is that clicking the Button element, calls the openModal method from usesongUtils and sets isEditing to true. That works.
However I'm also trying to get the cellData arguments in openModal method and it is not working. I'm getting undefined if I try to console.log.
// SongList.js
const optionsRender = ({ cellData }) => (
<div className='songs-list__options'>
<Link to={`/songs/${cellData}/edit`}>
<Icon name='edit' style={{ margin: '0 .2rem .2rem 0' }} />
</Link>
<a rel='noreferrer' target='_blank' href={`localhost/client/song/${cellData}`}>
<Icon name='play' style={{ margin: '0 .2rem' }} />
</a>
{cellData} // I can see the data!!
// im trying to pass cellData to openModal
<Button size='tiny' className='ui button' fluid icon='setting' circular onClick={() => openModal(cellData)} />
</div>
);
const {
closeModal, isEditing, openModal,
} = useSongUtils();
I have a ButtonGroup with a few Buttons in it, and when one of the buttons gets clicked, I want to change its color, I kinda want to make them behave like radio buttons:
<ButtonGroup>
<Button
variant={"info"}
onClick={(e) => {
..otherFunctions..
handleClick(e);
}}
>
<img src={square} alt={".."} />
</Button>
</ButtonGroup>
function handleClick(e) {
console.log(e.variant);
}
But that doesnt work, e.variant is undefined.
If it was just a single button I would have used useState and I would be able to make this work, but how do I make it work when there are multiple buttons, how do I know which button is clicked and change the variant prop of that button? And then revert the other buttons to variant="info"
Another approach that I could think of is to create my own Button that wraps the bootstrap Button and that way I can have access to the inner state and use onClick inside to control each buttons state, but I'm not sure if that will work, as then how would I restore the other buttons that werent clicked..?
To further from my comment above, you could create your own button component to handle its own state and remove the need to have lots of state variables in your main component e.g.
const ColourButton = ({ children }) => {
const [colour, setColour] = React.useState(true)
return (
<button
onClick={ () => setColour(!colour) }
style = {{color: colour ? "red" : "blue"} }
>
{ children }
</button>
)
}
That way you can just wrap your image in your new ColourButton:
<ColourButton><img src={square} alt={".."} /></ColourButton>
Edit:
I actually like to use styled-components and pass a prop to them rather than change the style prop directly. e.g. https://styled-components.com/docs/basics#adapting-based-on-props
EDIT: Kitson response is a good way to handle your buttons state locally :)
I like to handle the generation of multiple elements with a function. It allows me to customize handleClick.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [buttons, setButtons] = useState([
{
id: 1,
variant: "info"
},
{
id: 2,
variant: "alert"
}
]);
const handleClick = id => {
setButtons(previous_buttons => {
return previous_buttons.map(b => {
if (b.id !== id) return b;
return {
id,
variant: "other color"
};
});
});
};
const generateButtons = () => {
return buttons.map(button => {
return (
<button key={button.id} onClick={() => handleClick(button.id)}>
Hey {button.id} - {button.variant}
</button>
);
});
};
return <div>{generateButtons()}</div>;
}
https://jrjvv.csb.app/
You can maintain a state variable for your selected button.
export default class ButtonGroup extends Component {
constructor(props) {
super(props);
this.state = {
selected: null
};
}
handleClick = e => {
this.setState({
selected: e.target.name
});
};
render() {
const selected = this.state.selected;
return (
<>
<button
name="1"
style={{ backgroundColor: selected == 1 ? "red" : "blue" }}
onClick={this.handleClick}
/>
<button
name="2"
style={{ backgroundColor: selected == 2 ? "red" : "blue" }}
onClick={this.handleClick}
/>
<button
name="1"
style={{ backgroundColor: selected == 3 ? "red" : "blue" }}
onClick={this.handleClick}
/>
</>
);
}
}
Here is a working demo:
https://codesandbox.io/live/OXm3G
I want to click X Button in Card extra to visible "Confirm Remove Todo modal".
UI:
But...
the reality when I click X Button then it visible "Edit Todo modal" from Card event instead.
how can I fix it?
Code:
{todos.map(todo => (
<Card
className={styles.CardTodo}
headStyle={{ textAlign: 'left' }}
bodyStyle={{ textAlign: 'left' }}
key={todo._id}
title={todo.title}
onClick={() => handleSelectTodo(todo._id)}
extra={
<Button
type="danger"
shape="circle"
style={{ color: 'white', zIndex: 10 }}
onClick={() => handleRemoveTodo(todo._id)}
>
X
</Button>
}
>
{todo.description}
</Card>
))}
.
.
Thanks very much, guys
e.stopPropagation() is useful for me.
And then I found another problem.
It is handleRemoveTodo() is the function that opens another modal.
But that modal didn't get "Todo object"
when I remove e.stopPropagation(), the modal will get Todo Object again
Code:
Todo component
const handleRemoveTodo = () => {
setModalConfirmRemoveVisible(true)
}
const handleConfirmRemove = async todoId => {
console.log('Hello', todoId)
setIsRemoveLoading(true)
try {
await axios.delete(`/todos/${todoId}`, apiConfig)
} catch (err) {
console.error(err)
console.error(err.response.data)
}
await fetchTodos()
setModalConfirmRemoveVisible(false)
setIsRemoveLoading(false)
}
return (
{modalConfirmRemoveVisible && (
<ModalConfirmRemoveTodo
visible={modalConfirmRemoveVisible}
todo={todo}
isRemoveLoading={isRemoveLoading}
onConfirmRemoveTodo={handleConfirmRemove}
onCancel={() => setModalConfirmRemoveVisible(false)}
onConfirmRemove={handleConfirmRemove}
/>
)}
)
Modal component
const ModalConfirmRemoveTodo = props => {
const { visible, isRemoveLoading, onCancel, todo, onConfirmRemove } = props
console.log('ModalConfirmRemoveTodo', todo)
return (
<>
<Modal
visible={visible}
title={<Title level={3}>Remove Todo</Title>}
okButtonProps={{ loading: isRemoveLoading, disabled: isRemoveLoading }}
okText="Remove"
okType="danger"
onOk={() => onConfirmRemove(todo._id)}
onCancel={onCancel}
>
Want delete {todo.title} ?
</Modal>
</>
)
}
This is called Event Bubbling. When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.
Please refer to this article for details: https://javascript.info/bubbling-and-capturing#bubbling
Below is my solution to your problem. Instead of opening a modal, I just use a simple alert to simulate it.
Your current problem: https://codesandbox.io/s/event-bubbling-bojvq
You will see that the Chrome alert will pop up twice. The former is from the onClick of extra, the latter is from onClick of Card.
Solution: https://codesandbox.io/s/prevent-bubbling-zkxk6
Just add a simple e.stopPropagation() to prevent the bubbling inside extra Button onClick. Please refer to this: https://javascript.info/bubbling-and-capturing#stopping-bubbling for more information.
Back to your code, just simply update your Button's onClick like this:
onClick={e => { e.stopPropagation(); handleRemoveTodo(todo._id)}}
Use stopPropagation() method on your event:
<Button
type="danger"
shape="circle"
style={{ color: 'white', zIndex: 10 }}
onClick={e => { e.stopPropagation(); handleRemoveTodo(todo._id)}}
>
X
</Button>
The useState's value will change when the current button is clicked, which will call the child component.
Child component is Modal.
However, when the parent's button is repressed, the changed value is not changed again and will not be recalled.
https://codesandbox.io/s/patient-snowflake-wdm78
You can send the callback function to the Child Component like this.
StepComp.js
const StepComp = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const btnStyled = {
margin: "10rem"
};
const setVisible = visible => {
setIsModalVisible(visible);
};
return (
<div>
<Button onClick={() => setIsModalVisible(true)} style={btnStyled}>
jump
</Button>
<LoginModal open={isModalVisible} setVisible={setVisible} />
</div>
);
};
LoginModal.js
const LoginModal = ({ open, setVisible }) => {
const inputStyled = {
borderColor: "none",
borderBottom: "1px solid #EBEBEB",
marginBottom: "1rem"
};
return (
<div>
<Modal
title="login"
centered
visible={open}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
>
<div>
<input type="text" style={inputStyled} /> <br />
<input type="text" style={inputStyled} />
</div>
</Modal>
</div>
);
};
You're using isModelVisible and visible state properties, and initializing them a a boolean, then setting them to the opposite. This works, but only the first time.
What you need to do is setVisible(!visible) and setIsModalVisible(!isModalVisible) respectively.
While this will make it work, what I suggest doing instead is actually only having one state property, in the parent (StepComp), which then is passed as a callback to the child (Modal) along with the property whether it is open, then you render the child, if it's true, and use the same setState function in the child to close it.
This approach keeps all the logic for opening the Modal in one component.