How to keep semantic-ui modal from closing when displaying different components? - javascript

I am trying to use a modal for authentication (login and register). So far I have been able to get it to display correctly and can switch from login to register component, but for some reason the modal will close after trying to switch back from register to login. I have a header that contains the trigger for the modal. Here is my code so far:
Header.js
import React, { Component } from "react";
import Login from "./Login";
import Register from "./Register";
import logo from "../assets/logo.png"
import { Modal } from "semantic-ui-react";
class Header extends Component {
constructor(props){
super(props);
this.state = { login: true, header: "Login"}
this.handleRegister = this.handleRegister.bind(this);
this.handleLogin = this.handleLogin.bind(this);
}
handleRegister = () => {
this.setState({ login: false,
header: "Register"});
}
handleLogin = () => {
this.setState({ login: true,
header: "Login"});
}
renderModal () {
const showLogin = this.state.login ? (<Login handleRegister={this.handleRegister} />) : (<Register handleLogin={this.handleLogin} />);
return (
<Modal closeIcon onClose={this.handleLogin} size="tiny" trigger={<a className="item">Login</a>}>
<Modal.Header style={{backgroundColor: "#005ce6", color:"white"}}>{this.state.header}</Modal.Header>
<Modal.Content>
{showLogin}
</Modal.Content>
</Modal>
)
}
render() {
return (
<div>
<div className="ui menu hover" style={{ padding: 0}}>
<div className="right menu">
{this.renderModal()}
</div>
</div>
</div>
)
}
}
export default Header;
Register.js
import React, { Component } from 'react';
class Register extends Component {
constructor(props){
super(props)
this.handleLogin = this.props.handleLogin.bind(this);
}
render() {
return (
<div>
<div>
<form action="/auth/register" method="post" className="ui form">
<div className="field">
<label>First Name</label>
<input type="text" placeholder="First Name" name="firstName"/>
</div>
<div className="field">
<label>Last Name</label>
<input type="text" placeholder="Last Name" name="lastName"/>
</div>
<div className="field">
<label>Email</label>
<input type="text" placeholder="Email" name="email"/>
</div>
<div className="field">
<label>Password</label>
<input type="password" placeholder="Password" name="password"/>
</div>
<button type="submit" className="ui button">Submit</button>
</form>
<div style={{paddingTop:20}}>
<div>Already have account? Please <a onClick={this.handleLogin}>Login</a></div>
</div>
</div>
</div>
)
}
}
export default Register;
Login.js
import React, { Component } from 'react'
class Login extends Component {
constructor(props){
super(props)
this.handleRegister = this.props.handleRegister.bind(this);
}
render(){
return (
<div>
<form action="/auth/login" method="post" className="ui form">
<div className="field">
<label>Email</label>
<input type="text" placeholder="Email" name="email"/>
</div>
<div className="field">
<label>Password</label>
<input type="password" placeholder="Password" name="password"/>
</div>
<button type="submit" className="ui button">Submit</button>
</form>
<div style={{paddingTop:20}}>
<div>Don't have an account? Please <a onClick={this.handleRegister}>Register</a></div>
</div>
</div>
)
}
}
export default Login;
I have tried using the open field for the modal and setting a "show" state depending if the trigger is set off, but it ends up never closing. It seems that when I go from register to login components via the "Login" click it will set off a close event and I can not figure out why.

Workaround: add closeOnDimmerClick={false} as Modal prop.
Source: https://github.com/Semantic-Org/Semantic-UI-React/issues/2493#issuecomment-362972834
There are some issues with Modal component of Semantic UI React. Definitely.
Repro steps:
https://codesandbox.io/s/30n2v379r1
open modal by clicking Login (top left corner, also zoom out to see the links of modal)
click Register link of the modal
click Login link of the modal
Actual: modal is closed
Expected: modal is open and Register form is displayed
IMO, after changing the markup (Register form has more inputs) navigation link has new coordinates which is out of initial coords range of the modal. Therefore, clicking on this link now is treated like a clicking somewhere outside of the modal.
PS: yet another way to escape this auto-closing behavior is to make both forms markup more or less similar: for example, remove first two inputs from Register form so it looks exactly like Login form (of course, it's not the solution for topic-starter, just FYI), there are some comments in Register component on https://codesandbox.io/s/30n2v379r1
upd: issue on SUIR repo https://github.com/Semantic-Org/Semantic-UI-React/issues/2888

Use open property, it's boolean if true will keep your modal open.
demo link to keep modal open
<Modal
trigger={<Button onClick={this.handleOpen}>Show Modal</Button>}
open={this.state.modalOpen}
onClose={this.handleClose}
basic
size='small'
>

Related

React Js navigate between pages using Navigate inside the button click event [duplicate]

This question already has an answer here:
Problem in redirecting programmatically to a route in react router v6
(1 answer)
Closed 11 months ago.
I am using latest version of the react js. I want to navigate the add page to after login. here is the my code.
import React,{Component} from 'react';
import { variables } from '../../Variables';
import { Navigate } from 'react-router-dom';
export class Login extends Component{
constructor(props){
super(props);
this.state={
login:[],
name:"",
password:"",
redirect: false
}
}
changelogindetailsname = (e)=>{
this.setState({name:e.target.value})
}
changelogindetailspass = (e)=>{
this.setState({password:e.target.value})
}
loginClick(){
fetch(variables.API_URL+'login',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
name:this.state.name,
password:this.state.password
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
const navigate = Navigate();
navigate("/add" , { replace: "/" } );
},(error)=>{
alert('Faild');
})
}
render(){
const{
name,
password
}=this.state;
return(
<div>
<center>
<h1></h1>
<hr/>
<h3>Welcome Back !</h3>
<p></p>
<div className="container">
<br/>
<br/>
<br/>
<div className="row">
<div className="col">
</div>
<div className="col">
</div>
<div className="col-4">
<style>{"\ .rr{\ float:left;\ }\ "} </style>
<style>{"\ .bb{\ float:right;\ }\ "} </style>
<div className="mb-3">
<label className="form-label rr d-flex"> Username</label>
<div className="input-group input-group-lg">
<input type="text" className="form-control " id="formGroupExampleInput" placeholder="Username"
value={name}
onChange={this.changelogindetailsname}/>
</div>
</div>
<div className="mb-3">
<label className="form-label rr d-flex">Password</label>
<div className="input-group input-group-lg">
<input type="password" className="form-control" id="formGroupExampleInput2" placeholder="Password"
value={password}
onChange={this.changelogindetailspass}/>
</div>
</div>
<div className="d-flex mb-3">
Forgot your password?
</div>
<div className="col">
<div className="form-check rr">
<input className="form-check-input" type="checkbox" value="" id="flexCheckDefault"/>
<label className="form-check-label" htmlFor="flexCheckDefault">
Remember me
</label>
</div>
</div>
<div className="col">
<button type="button" className="btn btn-success bb"
onClick={()=>this.loginClick()} navigate="/Add.js" >Login</button>
</div>
<br/>
<br></br>
<hr/>
<p>Don't have an account?</p>
<div className="mb-3">
<button type="button" className="btn btn-light d-flex"
href="Add.js" >Sign up for Muessoze</button>
</div>
</div>
<div className="col">
</div>
<div className="col">
</div>
</div>
</div>
</center>
</div>
)
}
}
This is compile without error but the runtime browser console get this error
Uncaught (in promise) TypeError: Cannot destructure property 'to' of '_ref2' as it is undefined.
at Navigate (index.tsx:165:1)
at Login.js:44:1
This is the App.js file code
import { BrowserRouter, Route, Routes } from 'react-router- dom';
import './App.css';
import { Login } from './components/Login/Login';
import { Add } from './components/Login/Add';
function App() {
return (
<BrowserRouter>
<Routes>
<Route exact path="/" element={<Login/>}/>
<Route exact path="/add" element={<Add/>}/>
</Routes>
</BrowserRouter>
);
}
export default App;
I have no idea what to do, I tried several times but problem is the same. I think passing parameters is the reason for this error. but still I have no solution for this. please help me.
EDIT ( After OP clarified he is using a class Component ):
Since you are using a class component, you can't use Hooks (Please switch to function components, most react class based code is legacy code! ), but you can decorate your Component with a HOC and pass navigate to it as a prop, we answered a few hours ago to a very similar question :
HOC:
const withNavigate = Component => props => {
const navigate = useNavigate();
const params = useParams();
return <Component {...props} params={params} navigate={navigate} />;
}
const LoginWithNavigate = withNavigate(Login);
Then in your Login Component you can just do this.props.navigate("/") to navigate.
Delete const navigate = Navigate();
Navigate is a React Component you can't use it like that, to use navigate like that you need to use useNavigate hook .
Import {useNavigate} from "react-router-dom"
then inside your React component:
const navigate = useNavigate()
Now it should work, just change replace prop to a boolean value.

Why css file of one component interacted with the css file of another component in ReactJS? How to handle it?

I am trying to make a website template with Reactjs. In the Jumbotron section i make subscription form and in the home section User Entry form. But the css of one component interacted with another's one. How can i handle it?
[1]: https://i.stack.imgur.com/Wd4OQ.png
User EntryJs:-
import React, { Component } from 'react'
import './User Entry.css'
class Form extends Component {
initialState = {
name: "",
age: "",
job: ""
}
state = this.initialState
changeHandler = event => {
const { name, value } = event.target
this.setState({
[name]: value
})
}
render() {
const { name, job, age } = this.state
return (
<form className="form-inline">
<div className="row">
<div className="col-md-3">
<div className="form-group">
<label htmlFor="name">Name:-</label>
<input type="text"
className="form-control"
name="name"
id="name"
value={name}
autoFocus
onChange={this.changeHandler} />
</div>
</div>
<div className="col-md-3">
<div className="form-group">
<label htmlFor="age">Age:-</label>
<input type="text"
className="form-control"
name="age"
id="age"
value={age}
autoFocus
onChange={this.changeHandler} />
</div>
</div>
<div className="col-md-3">
<div className="form-group">
<label htmlFor="job">Job:-</label>
<input type="text"
className="form-control"
name="job"
id="job"
value={job}
autoFocus
onChange={this.changeHandler} />
</div>
</div>
<div className="col-md-3"></div>
</div>
</form>
)
}
}
export default Form
Header JS:-
import React, { Component } from 'react'
import './Header.css'
import { Link, withRouter } from "react-router-dom";
class Header extends Component {
constructor(props) {
super(props)
this.state = {
email: ""
}
}
submitHandler = event => {
event.preventDefault();
alert(`Subscribed Email is : ${this.state.email}`);
}
changeHandler = event => {
this.setState({
email: event.target.value
})
}
render() {
return (
// Navbar Starts
<div>
<div className="row navbar">
<Link to="/" style={{textDecoration:'none'}}><div className="col-md-2 logo">ReactApp</div></Link>
<div className="col-md-6"></div>
<Link to="/" style={{textDecoration:'none'}}> <div className="col-md-1 link"> Home</div> </Link>
<Link to="/about" style={{textDecoration:'none'}}> <div className="col-md-1 link"> About</div> </Link>
<Link to="/counter" style={{textDecoration:'none'}}> <div className="col-md-1 link"> Counter </div></Link>
<Link style={{textDecoration:'none'}}><div className="col-md-1 link">Login</div></Link>
</div>
<div className="jumbotron text-center">
<h1>React-App</h1>
<p>We specialize in <strong>Web Development</strong></p>
{/* Subscribing form starts*/}
<form className="form-inline subscribingForm" onSubmit={this.submitHandler}>
<div className="input-group">
<input type="email"
className="form-control"
value={this.state.email}
onChange={this.changeHandler}
size="80"
placeholder="Email..."
required />
<div className="input-group-btn">
<input type="submit" value="Subscribe" className="subscribingBtn" />
</div>
</div>
</form>
{/* Subscribing form closes*/}
</div>
</div>
)
}
}
export default withRouter(Header);
Where is the .css file loaded, in the root component? It probably is loaded globally and is used on every component.Better use JSS (https://cssinjs.org/?v=v10.3.0)
In general react transpiles all the css and add it in to tag.
And as result you one file css conflicts with other.
If you want to avoid this, you can use modular css.
https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/

how to redirect to home page after login: ReactJS?

How to redirect to homepage after successful login in ReactJS? and also how to show error message whenever user enter wrong credential?
I tried something like below, but it not redirect to homepage after successful login and also not showing login failed prompt whenever user hit wrong credential.
It would be great if anybody could figure out where i did mistake.
./src/Login.js
import React, {Component} from "react";
import {Form} from 'antd';
import { Redirect } from "react-router-dom";
export default class App extends Component{
constructor(props) {
super(props);
this.state ={
username: "",
password: "",
}
this.onFormSubmit = this.onFormSubmit.bind(this)
}
onFormSubmit(values){
console.log(values);
const formData = new FormData();
formData.append("username", values.username);
formData.append("password", values.password);
const options = {
method: 'POST',
body: formData
};
fetch('http://localhost:8000/api/login', options).then(() => {
<Redirect to="/home" />
}).catch((error) => {
console.log(this.props.state)
})
};
render(){
return(
<div>
<Form onFinish={this.onFormSubmit}>
<div class="col-md-12 form-group p_star">
<Form.Item name="username">
<input type="text" class="form-control" placeholder="Username"/>
</Form.Item>
</div>
<div class="col-md-12 form-group p_star">
<Form.Item name="password">
<input type="password" class="form-control"
placeholder="Password"/>
</Form.Item>
</div>
<div class="col-md-12 form-group">
<button type="submit" value="submit" class="btn_3">
log in
</button>
</div>
</Form>
</div>
You can use
window.location = "/home";
OR
this.props.history.push("/home");
go with any of it.
OR
you can go through Programmatically navigate using react router
Well I recommend you to use this.props.history.replace('/home'). Since it prevent the user to navigate back.

how to redirect to a page after successful login: ReactJS?

How to redirect to homepage after successful login in ReactJS? and also how to show error message whenever user enter wrong credential?
I tried something like below, but it not redirect to homepage after successful login and also not showing login failed prompt whenever user hit wrong credential.
It would be great if anybody could figure out where i did mistake.
./src/Login.js
import React, {Component} from "react";
import {Form} from 'antd';
export default class App extends Component{
constructor(props) {
super(props);
this.state ={
username: "",
password: "",
}
this.onFormSubmit = this.onFormSubmit.bind(this)
}
onFormSubmit(values){
console.log(values);
const formData = new FormData();
formData.append("username", values.username);
formData.append("password", values.password);
const options = {
method: 'POST',
body: formData
};
fetch('http://localhost:8000/api/login', options).then(() => {
this.props.history.push('/home')
}).catch((error) => {
alert('Login Failed!')
})
};
render(){
return(
<div>
<Form onFinish={this.onFormSubmit}>
<div class="col-md-12 form-group p_star">
<Form.Item name="username">
<input type="text" class="form-control" placeholder="Username"/>
</Form.Item>
</div>
<div class="col-md-12 form-group p_star">
<Form.Item name="password">
<input type="password" class="form-control"
placeholder="Password"/>
</Form.Item>
</div>
<div class="col-md-12 form-group">
<button type="submit" value="submit" class="btn_3">
log in
</button>
</div>
</Form>
</div>
If the component is a direct child from a you can call this.props.history.push('/url');
If not, you can export the component like this:
import {withRouter} from 'react-router-dom';
....
export default withRouter(ComponentName);
And then you can call this.props.history.push('/url');
To display errors you need to push errors to the state and do this in the render method:
{this.state.errors !== [] && (
{this.state.errors.map(error => (
{/*Display the error*/}
))}
)}
Assuming you use react-router-dom, you can use
<Redirect to="/somewhere/else" />
Be sure to setup a route that match the path you provided to Redirect component

Show Component inside a Collapsible

Hello I'm trying to show a Form Component inside an 'antd' Collapsible when the user clicks on the form icon the Form Component should appear inside the Collapsible below the text that's already there
I'm using the antd library for the Collapsible
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Collapse, Icon } from 'antd';
import Form from './Form';
const { Panel } = Collapse;
const text = `
A dog is a type of domesticated animal.
Known for its loyalty and faithfulness,
it can be found as a welcome guest in many households across the world.
`;
const genExtra = () => (
<Icon
type="form"
onClick={event => {
// If you don't want click extra trigger collapse, you can prevent this:
event.stopPropagation();
console.log('You have click on edit form');
}}
/>
);
const customPanelStyle = {
background: '#f7f7f7',
borderRadius: 4,
marginBottom: 24,
border: 0,
overflow: 'hidden',
};
ReactDOM.render(
<Collapse
bordered={false}
defaultActiveKey={['1']}
expandIcon={({ isActive }) => <Icon type="caret-right" rotate={isActive ? 90 : 0} />}
>
<Panel
header="This is panel header 1"
key="1" style={customPanelStyle}
extra={genExtra()}
>
<p>{text}</p>
</Panel>
</Collapse>,
document.getElementById('container'),
);
this is the Form Component:
import React from 'react';
const Form = () => {
return(
<div id="wrapper">
<div className="group">
<label for="name">Name</label>
<input type="text" id="name" />
</div>
<hr/>
<div className="group">
<label for="email">Email</label>
<input type="email" id="email" />
</div>
</div>
);
}
export default Form;
--
I just want the Form Component to appear inside the collapsible when the user clicks on the little icon in the header I'll leave a link to the stackblitz: https://stackblitz.com/edit/react-pkffgm
You need to move your Collapsible to another class based component, where you can have state to show / hide your Form component,
In newly constructed class based component you need to maintain state like,
constructor(props){
super(props);
this.state ={
showForm: false
}
}
Then in render you can show your Form like this,
<Panel
header="This is panel header 1"
key="1" style={customPanelStyle}
extra={this.genExtra()}
>
<p>{text}</p>
{this.state.showForm && <Form />}
</Panel>
And finally on click of form edit icon you need to change state of showForm like,
genExtra = () => (
<Icon
type="form"
onClick={event => {
// If you don't want click extra trigger collapse, you can prevent this:
event.stopPropagation();
this.setState({showForm: true})
console.log('You have click on edit form');
}}
/>
);
Note: In the Form component you are getting warning for your lable,
<label htmlFor="name">Name</label> //instead of `for` attribute in react we have `htmlFor` attribute.
Demo

Categories

Resources