Redirecting onClick - javascript

This is a weird situation. So I have this Login component:
export default class Login extends React.Component {
componentDidMount() {
var email = document.getElementById('email').value;
var password = document.getElementById('password').value;
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => document.getElementById('close').click())
.catch(e => console.log(e));
}
render() {
if (firebase.auth().currentUser === null)
return '';
else return <Redirect to='/questions'/>
}
}
And this is my LoginForm
export default class LoginFormComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Modal
show={this.props.show}
onHide={() => this.props.changeShowState(false)}>
<Modal.Header
closeButton>
<Modal.Title> Zaloguj sie </Modal.Title>
</Modal.Header>
<Modal.Body>
<form>
<FormControl
id="email"
type="email"
label="Email address"
placeholder="Enter email"/>
<FormControl id="password" label="Password" type="password"/>
<Button onClick={<Login/>}>Zaloguj</Button>
{/*The problem is ^^^^^ here*/}
</form>
</Modal.Body>
<Modal.Footer>
<Button id="close" onClick={() => this.props.changeShowState(false)}>Close</Button>
</Modal.Footer>
</Modal>
)
}
}
The whole problem is, I want to redirect the page, after the user logs in. I did some research and I figured I have to do it this way.
The problem is the <Login/> element is not rendered. I'm guessing it's just not how React works, but I have no other idea how to get it done. All I want to do is redirect a user after loging in.

You don't have to have it in two components. Your main problem is that you cannot give a React component as an onClick handler.
My take on it would be:
export default class LoginFormComponent extends React.Component {
state = { loggedIn: false, error: false }
constructor(props) {
super(props);
}
handleSubmit() {
var email = document.getElementById('email').value;
var password = document.getElementById('password').value;
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => document.getElementById('close').click())
.catch(e => console.log(e));
if(firebase.auth().currentUser === null)
this.setState({ loggedIn: false, error: true });
else
this.setState({ loggedIn: true, error: false});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{ this.state.error && <span>Could not log in.</span> }
{ this.state.loggedIn && <Redirect to='/questions' /> }
<FormControl
id="email"
type="email"
label="Email address"
placeholder="Enter email"/>
<FormControl id="password" label="Password" type="password"/>
<Button type="submit">Zaloguj</Button>
</form>
)
}
}

I think that you don't have understand how React works.
First of all you don't have to use "document.getElementById('email').value", because React works using state and props.
After that you cannot pass a component to the onClick event handler. The onClick wants a function.
If you want to redirect user you can create a method like:
loginUser(){
window.location = "https:..";
}
Your button will be:
<Button onClick={this.loginUser.bind(this)}>Zaloguj</Button>
However when you work with React is really difficult that you need redirects. Seeing your components it seems like you want to handle React in the PHP way (Login component cannot read data with getElementById in the ComponentDidMount method. You have to use react-router for the app routing and you can use something like MobX or Redux to store user login data. You can even pass props and not use MobX or Redux).

Related

Form dialog don't set state

I have created a simple login function where once the user log in, he is redirect to another page. Then I wanted to change the login form with a form dialog. And the problem is here. The login dialog works, but when I enter the username and password, I'm not send to another page but to the same login page :/.
Here is the code:
Login.jsx:
class Login extends Component {
constructor(props) {
super(props);
this.state = {
islogged: false,
loginSettings: {
lUsername: "",
lPassword: ""
}
};
}
handleInput = (event) => {
let loginSettingsNew = { ...this.state.loginSettings };
let val = event.target.value;
loginSettingsNew[event.target.name] = val;
this.setState({
loginSettings: loginSettingsNew
});
};
login = (event) => {
let lUsername = this.state.loginSettings.lUsername;
let lPassword = this.state.loginSettings.lPassword;
if (lUsername === "admin" && lPassword === "password") {
localStorage.setItem("token", "T");
this.setState({
islogged: true
});
} else {
console.log("Erreur");
}
event.preventDefault();
};
render() {
if (localStorage.getItem("token")) {
return <Redirect to="/" />;
}
return (
<div className="Login">
<Dialog handleInput={this.handleInput} login={this.login} />
<p>Username: admin - Password: password</p>
</div>
);
}
}
Dialog.js:
export default function FormDialog() {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button variant="outlined" color="primary" onClick={handleClickOpen}>
Open form dialog
</Button>
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Login</DialogTitle>
<DialogContent>
<form onSubmit={this.login}>
<label>
<span>Username</span>
<input name="lUsername" type="text" onChange={this.handleInput} />
</label>
<label>
<span>Password</span>
<input name="lPassword" type="password" onChange={this.handleInput}/>
</label>
<Button onClick={handleClose} color="primary">Cancel</Button>
<Button type="submit" value="submit" color="primary">Login</Button>
</form>
</DialogContent>
</Dialog>
</div>
);
}
I also have created a sandbox of my code: https://codesandbox.io/s/react-login-auth-forked-r06ht
I thinks that the problem come from the form dialog that can't set the state of islogged of the login function. I tried quite a lot of things but nothing worked, so I would like to ask some help please.
I thank in advance anyone who will take the time to help me .
I notice that your Login component is a class, while the child FormDialog component is a function component using Hooks. There's nothing wrong with that, in itself - particularly if you started with an application using all class components and are slowly converting your components. But I detect some confusion here, because your function component seems to assume it's a class, in a sense. When you need to do things a bit differently.
Specifically, you reference this.login in your function component - but this is meaningless. login is passed in as a prop. In a class component, you would reference it as this.props.login. This doesn't work in a function component - but this.login isn't the substitute. Indeed this will tend to be undefined so this would even give an error. Even if not, it's not correct.
All you need to do is to make use of the argument to your function component - this is where the props object "lives" in a function component. You happen to ignore it by not using any arguments - but you don't have to do this.
So in short, what you need to do is:
replace export default function FormDialog() with export default function FormDialog(props)
replace this.login with props.login
repeat 2) for all other props which you have referenced using this
Ok all fixed. In your App.js you didn't have a home component to redirect to with this path="/". I've created a new component called home.js. Tidied the Routes for you.
<Route path="/login" component={Login} />
<ProtectedRoute path="/dashboard" component={Dashboard} />
<Route exact path="/" component={Home} />
Please check ur code sandbox https://codesandbox.io/s/react-login-auth-forked-24m8e?file=/src/App.js

Referencing Function from another ReactJS Page for Validation

I am currently writing my first React Project for a class assignment. I am trying to make a login page that navigates to a new dashboard page. I do not want any fancy security, so I wanted it just to have "if password === this password then go to dashboard, if not then error message.
I have the button working fine without validation, and I have my handlers for the text input working as I can display what is typed by using this.state.username and this.state.password in my login-form.js file.
The problem I can't figure out is how to reference/use those states in my login-button.js file so I can create that if statement validator? Can anyone help?
Here is my login-form.js file:
import React from 'react';
import "./login-form.css";
import logo from './../../logo-beesecure-2-tm.png';
import Login_btn from './../login-button/login-button';
class Login_Form extends React.Component {
constructor(props){
super(props);
this.state = { username: '', password: '' };
}
handleChange = ({ target }) => {
this.setState({ [target.name]: target.value });
};
render() {
return (
<div className='login-container'>
<img src={logo} className="App-logo" alt="logo" />
<p>LOGIN</p>
<form onSubmit="" className="login-form">
<input
type="text"
placeholder="Username"
name="username"
value={this.state.username}
onChange={this.handleChange}
/>
<input
type="password"
placeholder="Password"
name="password"
value={this.state.password}
onChange={this.handleChange}
/>
</form>
<Login_btn />
<h2>Your username is: {this.state.username}</h2>
<h2>Your password is: {this.state.password}</h2>
</div>
);
}
}
export default Login_Form;
And here is my login-button.js file:
import './login-button.css';
import React from 'react';
import { useHistory } from "react-router-dom";
import Login_Form from '../login-form/login-form';
function Login_btn() {
let history = useHistory();
function handleClick() {
history.push("/dashboard");
}
return (
<button className="Login-Button" onClick={handleClick}>Login</button>
);
}
export default Login_btn;
Thank you in advance!
You can pass in the states from your <Login_Form /> into your <Login_btn /> by using props like so:
<Login_btn username={this.state.username} password={this.state.password} />
Then you can reference the props in your <Login_btn />:
function Login_btn(props) {
let history = useHistory();
function handleClick() {
const { username, password } = props;
history.push("/dashboard");
}
return (
<button className="Login-Button" onClick={handleClick}>Login</button>
);
}
You can read more about props here: https://reactjs.org/docs/components-and-props.html

React Context API and component methods [duplicate]

This question already has answers here:
Access React Context outside of render function
(5 answers)
Closed 3 years ago.
I've followed a few online examples, where they have a counter and an increment function in Context, and on a distant component, call the increment method and the results shows. All great, but ... I am trying to expand on this and create a login box, that sets an isAthenticated flag.
I have a very basic context:
import React from 'react';
const Context = React.createContext();
export class Provider extends React.Component {
state = {
isAuthenticated: false,
user: {
name: "Craig",
email: "craig#here.com"
},
changeEmail: (newEmail) => {
let user = this.state.user;
user.email = newEmail;
console.log(user);
this.setState({ user: user})
},
changeAuthenticated: () => {
this.setState ({ isAuthenticated: !this.state.isAuthenticated });
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer = Context.Consumer;
In it I allow the user to change email, and change isAuthenticated state.
My component (Remove style stuff) looks like this:
import React from 'react';
import { Input, Label, Button, Container } from 'reactstrap';
import { Consumer } from '../context';
class Login extends React.Component {
render() {
return (
<Consumer>
{value => {
return (
<Container style={containerStyle} >
<div style={loginBoxStyle}>
<div>
<h3>Login</h3>
</div>
<div style={loginBoxFieldsStyle}>
<div style={loginBoxFieldStyle}>
<div style={loginBoxLabelStyle}>
<Label for="email">Email:</Label>
</div>
<div style={loginBoxLabelStyle}>
<Input type="email" name="email" id="email" placeholder="Your Email" value={value.user.email} onChange={e=>value.changeEmail(e.target.value)} />
</div>
</div>
</div>
<div style={loginBoxFieldsStyle}>
<div style={loginBoxFieldStyle}>
<div style={loginBoxLabelStyle}>
<Label for="password">Password:</Label>
</div>
<div style={loginBoxLabelStyle}>
<Input type="password" name="password" id="password" placeholder="Your Password" />
</div>
</div>
</div>
<div style={loginBoxButtonStyle}>
<Button color="info" onClick={value.changeAuthenticated}>Login</Button>
</div>
</div>
</Container>
)}
}
</Consumer>
)
}
}
export default Login;
So when I change the email, the Context state is updated. And when I click the Login button, for now, it simply toggles IsAuthenticated.
I don't want the state to update as I type in the email box. I'd prefer to update the state when the Login button is clicked. So I feel I need a local component state, or something, which updates that state when I edit the data in the text boxes. And then updates the Context when I click Login.
But... How do I set up the state? 'values' (from context) is only available inside the Render. I need to set my component state outside of the render. So how would I go about achieving this?
My login button onClick should also fire a local method which has all the validation etc, and then update my route to redirect to a page on success. But then it needs access to the Context.UpdateMethod - from outside of the tags. Not sure how to achieve this.
You should probably just create a sub-component and then use the props to initialize the state.
class Login extends React.Component {
render() {
return (
<Consumer>
{value => (
<Container style={containerStyle}>
<SubComponent
changeAuthenticated={value.changeAuthenticated}
// ...etc

Reusable form fields in React

If i have the following dialog/modal:
<Modal
open={this.state.createAccountModalOpen}
trigger={<Link size="m" theme="bare" href="#" className="main-menu-item" onClick={this.handleOpenModalCreateAccount}>Create account</Link>}
closeIcon
onClose={() => { this.setState({
createAccountModalOpen: false,
}); }}
>
<Header icon='add user' content='Create account' />
<Modal.Content>
<Form />
</Modal.Content>
<Modal.Actions>
<Button color='green' onClick={this.handleSubmit}>
<Icon name='add user' /> Create account
</Button>
</Modal.Actions>
</Modal>
Basically this is a React Semantic-ui Modal/Dialog. Now What i want to do is make Form reusable (the Form component contains 4 input fields), so i can use it in other modals or components. What would be the best way so that when I click on Create account, it gathers the data from the form and then submits it?
Do I have to pass functions to the Form to try store the data in the main Modal component? or is there a better way to get the validated data from the form?
I’m on my phone so I’m limited.
You want to define your custom function in the parent component where you call your Modal. Then pass that function to it as a prop modal onComplete={this.submitEmail}
Then in your modal component call this.props.onComplete in your handleSubmit.
Then from here out you can define the custom function you want to use wiTh the model and pass it through with onComplete={whateverFunction}
In order to only show the inputs that you want you could set up a series of render if statements. Then when you call your Modal you can pass through renderIfText={“email”} and in your model if this.props.renderIfText=email render email input.
import React from 'react';
class ReusableModalForm extends React.Component {
constructor(props){
super(props);
this.state ={
};
}
handleChange(e) {
let {name, value} = e.target;
this.setState({
[name]: value,
usernameError: name === 'username' && !value ? 'username must have a value' : null,
emailError: name === 'email' && !value ? 'email must have a value' : null,
passwordError: name === 'password' && !value ? 'password must have a value' : null,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.onComplete(this.state)
}
render() {
return (
<Modal
open={this.state.createAccountModalOpen}
trigger={<Link size="m" theme="bare" href="#" className="main-menu-item" onClick={this.handleSubmit}>{this.props.buttonText}</Link>}
closeIcon
onClose={() => { this.setState({
createAccountModalOpen: false,
}); }}
>
<Header icon='add user' content='Create account' />
<Modal.Content>
<Form />
</Modal.Content>
<Modal.Actions>
<Button color='green' onClick={this.handleSubmit}>
<Icon name='add user' /> {this.props.buttonText}
</Button>
</Modal.Actions>
</Modal>
);
}
}
export default ReusableModalForm;
In order to make your <Form /> reusable you need to determine what are the inputs/outputs to your Form and allow any potential parent component to access/manipulate it via props.
Perhaps something like:
<CreateAccountForm
input1DefaultValue={...}
input2DefaultValue={...}
onSubmit={yourCreateAccountFormHandler}
/>
Do I have to pass functions to the Form to try store the data in the main Modal component? or is there a better way to get the validated data from the form?
It depends on how you implement Form and your input fields.
I would recommend react-form library or, if you want to have your own implementation - using redux state and wire your inputs/form to redux.
If no redux then you will need to store the state of inputs in the modal.
Whenever you compose components, you share data between them using props. I will be passing "name and label" props to stateless functional component named;
input.js
import React from "react";
const Input = ({name,label}) => {
return (
<div className="form-group">
<label htmlFor={name}>{label}</label>
<input
autoFocus
name={name}
id={name}
className="form-control"
aria-describedby="emailHelp"
/>
);
};
export default Input;
form.js
import React, { Component } from "react";
import Input from "./common/input";
class RegisterForm extends Form {
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input name="username" label="username" />
<input name="email" label="email" />
<input name="password" label="password" />
</form>
</div> ); } }

My inputs start with weird values

I've created very simple form for user to sign in. Here is my code:
import React,{ Component } from 'react';
class SignIn extends Component {
constructor(props) {
super(props);
this.state = {
login:"",
pass:""
}
}
signIn = (e) =>{
e.preventDefault();
alert("in")
}
handleChange = (propertyName) => (e) => {
const state = this.state;
const newState = {
...state,
[propertyName]: e.target.value
};
this.setState(newState);
}
render() {
return (
<div className="text-center">
<form onSubmit={this.signIn}>
<input type="text" id="login" onChange={this.handleChange('login')} value={this.state.login} placeholder="login"/>
<br />
<input type="password" id="pass" onChange={this.handleChange('pass')} value={this.state.pass} placeholder="pass"/>
<br />
<input type="submit" value="sign in" disabled={((this.state.login == "") && (this.state.pass == ""))
? true
: false}/>
</form>
</div>
);
}
}
export default SignIn;
For some reason every time I start my app these inputs already have some text inside. "login" always have "localhost" and "pass" contains some random numbers and letters. Can someone explain me where are these values comming from?
These fields are auto-populated by browser. See explanation here: https://developers.google.com/web/updates/2015/06/checkout-faster-with-autofill
Also you might be interested in this question of how people fighting with it :)
Chrome Browser Ignoring AutoComplete=Off

Categories

Resources