How can I change styles in the onClick event? - reactjs

I want to show/hide the search bar on the top side of the screen.
I am trying to implement an operation where the search bar is shown when the search button is pressed and hides again when the close button of the search bar is pressed.
const showSearchBar = () => {
document.querySelector("#hearder_search_bar").style = {
top : 0
}
};
const hideSearchBar = () => {
document.querySelector("#hearder_search_bar").style = {
top : -71
}
};
return (
<>
<form id = "hearder_search_bar" action="#" className="header__search">
<input type="text" placeholder="Search"/>
<button
type="button"
class="search"
onClick={...}
>
</button>
<button
type="button"
className="close"
onClick={hideSearchBar}
>
</form>
<div className="header__action--search">
<button
className="header__action-btn"
type="button"
onClick={showSearchBar}>
</button>
</div>
</>
);
css
.header__search {
position: absolute;
left: 0;
top: -71px;
}

use react useState hook and let react handle the manipulation of the DOM.
const [shouldShowSearch, setShouldShowSearch] = useState(false);
const toggleShowSearch = () => setShouldShowSearch(prev => !prev);
const label = shouldShowSearch ? 'hide' : 'show';
const top = shouldShowSearch ? '70px' : '0';
//... code
<>
<form id="hearder_search_bar" action="#" className="header__search" style={{top}}>
// ... code
<button
type="button"
className={label}
onClick={toggleShowSearch}
>
</form>
// .. code
<button onclick={toggleShowSearch}>{label} search</button>

You can use conditionnal className
className={headerIsHidden ? 'header__search__hidden' : 'header__search__shown'

Related

Retrieve form input values using React Children as a wrapper

I need to retrieve the input form data using the wrapper save button (Togglable component) and not a submit button inside a form component.
I have this form.
const BasicDataForm = () => {
return (
<form>
<div>
<label htmlFor="nameInput">Your Name: </label>
<input placeholder="Write your name here" type="text" id="nameInput" />
</div>
<div>
<label htmlFor="ageInput">Your Age: </label>
<input placeholder="Write your age here" type="number" id="ageInput" />
</div>
</form>
);
};
And the wrapper
const Togglable = ({ title, children }) => {
const [visible, setVisible] = useState(false);
const hideWhenVisible = { display: visible ? 'none' : '' };
const showWhenVisible = { display: visible ? '' : 'none' };
return (
<header>
<h2>{title}</h2>
<div style={hideWhenVisible}>
<button onClick={() => setVisible(true)}>Show</button>
</div>
<div style={showWhenVisible}>
<button>Save</button> {/* This button needs to retrieve all input form data from children */}
<button onClick={() => setVisible(false)}>Close</button>
{children}
</div>
</header>
);
};
And the main component
const App = () => {
return (
<>
<h1>Form Wrapper</h1>
<Togglable title="Basic Data Form">
<BasicDataForm />
</Togglable>
</>
);
};
I don't know if it's necessary to add a useState inside the form component. I also tried adding a new prop in the Togglable component that bind the onClick event of the save button to the onSubmit event of the form, but not work because there is no submit button inside form component.
The solution was much easier than I thought. You only need to wrap the entire children inside a <form> label and render only the content of the inputs. For every children a button will be added and you will manage the form outside the wrapper.
const Togglable = ({ title, children, handleSubmit }) => {
const [visible, setVisible] = useState(false);
const hideWhenVisible = { display: visible ? 'none' : '' };
const showWhenVisible = { display: visible ? '' : 'none' };
return (
<header>
<h2>{title}</h2>
<div style={hideWhenVisible}>
<button onClick={() => setVisible(true)}>Show</button>
</div>
<div style={showWhenVisible}>
<button onClick={() => setVisible(false)}>Close</button>
<form onSubmit={handleSubmit}>
{children}
<button type="submit">Save</button>
</form>
</div>
</header>
);
};

onClick load react component in the same place

I have a panel with 3 buttons, i want to make onclick on every button, a different component will appear in the same place. How can this logic be done?
<AddNotification />
<EditNotification />
<DeleteNotification />
const AdminPanel = () => {
return (
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className="form-group">
<Button type="submit">Add Notification</Button>
</div>
<div className="form-group">
<Button type="submit">Edit Notification</Button>
</div>
<div className="form-group">
<Button type="submit">Delete Notification</Button>
</div>
</form>
</Card>
)
}
#MLDC No i don't have another divs, i want to replace the buttons with the crossponding component. For example: onclick on Add, then Add component will appears instead of the buttons.
In that case, create a boolean state for every Panel that you have (I created 3 so that you could open the panels simultaneously),
const [isAddPanelOpen, setIsAddPanelOpen] = useState(false);
const [isEditPanelOpen, setIsEditPanelOpen] = useState(false);
const [isDeletePanelOpen, setIsDeletePanelOpen] = useState(false);
Next, apply this to every button
<Button onClick={setIsAddPanelOpen(prevState=>!prevState)}>Add Notification</Button>
<Button onClick={setIsEditPanelOpen(prevState=>!prevState)}>Edit Notification</Button>
<Button onClick={setIsDeletePanelOpen(prevState=>!prevState)}>Delete Notification</Button>
Lastly, Refactor your html to
<div className="form-group">
{isAddPanelOpen ? <AddNotification/> : <Button type="submit">Add Notification</Button>}
</div>
<div className="form-group">
{isEditPanelOpen ? <EditNotification/> : <Button type="submit">Edit Notification</Button>}
</div>
<div className="form-group">
{isDeletePanelOpen ? <DeleteNotification/> :<Button type="submit">Delete Notification</Button>}
</div>
Try this if you want to display one component at a time and hide the others when you click a button
const AdminPanel = () => {
const [componentToDisplay, setComponentToDisplay] = useState("")
return (
<>
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className="form-group">
{componentToDisplay !== "add ? (
<Button type="submit" onCLick={() => setComponentTodisplay("add")}>Add Notification</Button>)
:(<AddNotification />)}
</div>
<div className="form-group">
{componentToDisplay !== "edit ? (
<Button type="submit" onCLick={() => setComponentTodisplay("edit")}>Edit Notification</Button>)
:(<EditNotification />)}
</div>
<div className="form-group">
{componentToDisplay !== "delete ? (
<Button type="submit" onCLick={() => setComponentTodisplay("delete")}>Delete Notification</Button>)
:(<DeleteNotification />)}
</div>
</form>
</Card>
</>
)
}
Or if you want to be able to replace every buttons, use this logic with one state per button
const AdminPanel = () => {
const [addNotif, setAddNotif] = useState(false)
const [editNotif, setEditNotif] = useState(false)
const [deleteNotif, setDeleteNotif] = useState(false)
return (
<>
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className={`form-group ${editNotif || deleteNotif ? "display: none" : "display: flex"}`}>
{!addNotif ? (
<Button type="submit" onCLick={() => setAddNotif(true)}>Add Notification</Button>)
:(<AddNotification setAddNotif={setAddNotif} />)}
</div>
<div className={`form-group ${addNotif || deleteNotif ? "display: none" : "display: flex"}`}>
{!editNotif ? (
<Button type="submit" onCLick={() => setEditNotif(true)}>Edit Notification</Button>)
:(<EditNotification setEditNotif={setEditNotif} />)}
</div>
<div className={`form-group ${addNotif || editNotif ? "display: none" : "display: flex"}`}>
{!deleteNotif ? (
<Button type="submit" onCLick={() => setDeleteNotif(true)}>Delete Notification</Button>)
:(<DeleteNotification setDeleteNotif={setDeleteNotif} />)}
</div>
</form>
</Card>
</>
)
}
Then in your component
const AddNotification = ({setAddNotif}) => {
...
return (
...
<button onCLick={() => setAddNotif(false)}>back</button>
...
)
}
Same logic for the other components
To achieve this logic you need to manage which component is displayed using a state.
This means:
Attribute an arbitrary id to each component.
Store the id of the active component in a useState hook.
Use conditional rendering to display the component that match the current state.
Update the state to the corresponding Id when clicking on each button.
A small example
const [activePanel, setActivePanel] = React.useState(0)
let currentPanel = <Panel0 />
switch(activePanel){
case 0:
currentPanel = <PanelO />
case 1:
currentPanel = <Panel1 />
// Continue as needed
}
return (
<div>
<CurrentPanel/>
<button onClick={() => setActivePanel (0)}> Panel 0 </button>
<button onClick={() => setActivePanel (1)}> Panel 1 </button>
// And so on
</div>
)
You can further refine this by extracting the switch statement into its own component that takes the activePanel as a prop.

Close modal as soon as another one is pressed

I want a modal to close once a different modal is pressed, but I'm not sure on how to do it.
Essentially, if modal1 is pressed, it should show the contents of modal1, but as soon as modal2 is pressed,modal1 should disappear and only modal2 should show it's contents. How do I go about this?
I've tried to set it up with an open and close in the onclick but only had problems.
This is how I've got my code currently set up:
const [openQueueList, setOpenQueueList] = useState(false);
const handleOpenQueue = () => {
setOpenQueueList(true);
};
const [openRoomlist, setOpenRoomlist] = useState(false);
const handleOpenRoom = () => {
setOpenRoomlist(true);
};
const [openRoomQueueList, setOpenRoomQueueList] = useState(false);
const handleOpenRoomQueue = () => {
setOpenRoomQueueList(true);
};
in the return
<div class="modal">
<div >
{openQueueList ?
<TrackTable></TrackTable>
: null}
</div>
</div>
<div class="modal">
<div >
{openRoomlist ?
<LobbyUsers> </LobbyUsers>
: null}
</div>
</div>
<div class="modal">
<div >
{openRoomQueueList ?
<QueueSection></QueueSection>
: null}
</div>
Triggering the buttons
<button onClick={handleOpenRoomQueue}>
<QueueMusicIcon></QueueMusicIcon>
</button>
<button onClick={handleOpenRoom}>
<GroupIcon ></GroupIcon>
</button>
<button onClick={handleOpenQueue}>
<AudiotrackIcon></AudiotrackIcon>
</button>
Instead of using a state for each modal you could give each a key.
State would look like this
const [currentModal, openModal] = useState(null);
Then to open
<button onClick={() => openModal('queueList')}>Queue List</button>
<button onClick={() => openModal('roomList')}>Room List</button>
<button onClick={() => openModal('roomQueueList')}>Room Queue List</button>
Then your modals would look something like:
<div className="modal">
{currentModal === 'queueList' ?
<TrackTable></TrackTable>
: null}
{currentModal === 'roomList' ?
<LobbyUsers> </LobbyUsers>
: null}
{currentModal === 'roomQueueList' ?
<QueueSection></QueueSection>
: null}
</div>

How to open form on button click in react JS

function openForm() {
document.getElementById("myForm").style.display = "block";
}
function closeForm() {
document.getElementById("myForm").style.display = "none";
}
<button class="openButton" onclick={openForm} style={openButton}>AI Chat</button>
<button type="button" class="btn cancel" onclick={closeForm}>Close</button>
I am trying to open a form by onclick event in react, but it's not opening, I am new to react. here attaching what the code..this is working fine with. document.getElementById("myForm").style.display = "block"; As by default chat window is none ,we need to add STYLE display = block when using react,but am nit getting how to add.
const [open, setIsOpen] = useState(false);
const openForm = () =>
{
setIsOpen(true);
};
<Button variant="primary" onClick={openForm} style={openButton} >IRB Chat</Button>
<form open={open}>
<div class="chatPopup" id= "myForms" style={chatPopup}>
<div class="formContainer" style={formContainer}>
<span class="title1" style={title1}>IRB Chat</span>
<label for="msg"><b>Message</b></label>
<iframe customFrameSection style={customFrameSection} frameborder="1" id="AIChat" style={{border:'1px solid rgba(0,255,0,0.3)',width: "285px",height: "400px"}}></iframe>
<button type="button" class="btn cancel" onclick={closeForm} style={cancelButton}>Close</button>
</div>
</div>
</form>
CSS :-
const chatPopup = {
display: "none",
position: "fixed",
bottom: "75px",
right: "15px",
border: '3px solid #F1F1F1',
zIndex:9
};
To do this with React, the best way is using State.
If you do this with vanilla javascript, you don't need React.
example with React and useState:
const [open, setIsOpen] = React.useState(false);
const openForm = () => setIsOpen(true);
<button onClick={openForm}> click me! </button>
<Form open={open}/>
hope helpfull =)
const [open, setIsOpen] = useState(false);
const openForm = () => setIsOpen(true);
<button class="openButton" onClick={() => {openForm}} style={openButton}>Chat</button>
<div class="chatPopup" id="myForm" style={chatPopup}>
<Form open={open}/>
<div class="formContainer" style={formContainer}>
<span class="title1" style={title1}>Chat</span>
<label for="msg"><b>Message</b></label>
<iframe customFrameSection style={customFrameSection} frameborder="1" id="AIChat" style={{border:'1px solid rgba(0,255,0,0.3)',width: "285px",height: "400px"}}></iframe>
<button type="button" class="btn cancel" onclick={closeForm} style={cancelButton}>Close</button>
</div>
</div>

my onclick function overlapped with submit handler

when i put onClick event the form does not validate and if i delete onClick event the form does not want to submit
so recently i just start a new project with kendo react. on this project i tried to create customize grid where i can add new lines, edit or remove.
<form style={{ width: '1000px' }} onSubmit={this.handleSubmit} >
<div className="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<div className="k-animation-container">
<DropDownList
defaultValue={this.state.productInEdit.Programto || ''}
onChange={this.onDialogInputChange}
name="Programto"
required={true}
data={this.prog}
/>
</div>
</div>
</div>
<div className="row" >
<DialogActionsBar>
<Button
className="k-button"
onClick={this.props.cancel}
>
Cancel
</Button>
<Button className="mt-3" type="submit" primary={true} onClick={this.props.save} > Save </Button>
</DialogActionsBar>
</div>
</form>
and this is the event for validation
handleSubmit = (event) => {
event.preventDefault();
this.setState({ success: true });
setTimeout(() => { this.setState({ success: false }); }, 3000);
}
and submit code i create it on different page, so i need to call the event with this.props.save;
save = () => {
const dataItem = this.state.productInEdit;
const products = this.state.products.slice();
if (dataItem.ProductID === undefined) {
products.unshift(this.newProduct(dataItem));
} else {
const index = products.findIndex(p => p.ProductID === dataItem.ProductID);
products.splice(index, 1, dataItem);
}
this.setState({
products: products,
productInEdit: undefined
});
}
i tried to call save event inside the handleSubmit but still not working

Resources