I'm trying to show login and signup in just one page, that I can click on a login link that shows me the login form.
The problem is that when I click on the login link, <a href="" onClick={() => setlogin(true)}>login?</a>, the page gets loaded for 1s and then returns to sign up form.
Code:
import React, { ReactElement, Fragment, useState } from "react";
function LoginSignUp() {
const [login, setlogin] = useState(false);
return (
<Fragment>
{login ? (
<form className="form-signin">
<input
type="email"
id="inputEmail"
className="form-control"
placeholder="Email address"
required
/>
<input
type="password"
id="inputPassword"
className="form-control"
placeholder="Password"
required
/>
<button type="submit">Sign in</button>
</form>
) : (
<form className="form-signup">
<input
type="text"
name="username"
className="form-control"
placeholder="Username"
required
/>
<input
type="email"
name="email"
className="form-control"
placeholder="Email address"
required
/>
<input
type="password"
name="password"
className="form-control"
placeholder="Password"
required
/>
<input
type="password"
name="password2"
className="form-control"
placeholder="Confirm Password"
required
/>
<button type="submit">Sign Up</button>
</form>
)}
<p id="logintxt">
Do you already have an account? ,{" "}
<a href="" onClick={() => setlogin(true)}>
login?
</a>
</p>
</Fragment>
);
}
You can use preventDefault to stop the default behavior of hyperlink which refreshed your page and component's login state data became false again:
Option 1:
function handleClick(e) {
e.preventDefault()
setlogin(true)
}
<a href="/" onClick={handleClick}>login?</a>
Option 2:
Or, you can use # as hyperlink placeholder, it won't refresh the page but will just append a # in browser URL. But it may give you eslint warning that anchor is invalid:
<a href="#" onClick={handleClick}>login?</a>
Option 3:
Or, you can use a span or button:
<span onClick={handleClick}>login?</span>
// OR
<button type="button" onClick={handleClick} class="btn btn-link">login?</button>
... and, make it look like a link using your or bootstrap CSS.
Also, don't leave it blank href="", it will take you to the current URL location but will still refresh your page.
Related
I am creating a CV Application project and I have a button that allows the user to Add Work Experience. When the user clicks the button a form pops up and they are able to fill the information out and click Submit.
I'm trying to make it so once the user hits Submit, the form div stays hidden until the user clicks Add Work Experience again. I've made something similar before in vanilla JS where I simply changed the forms class from display: block to display: none but that doesn't seem possible in React.
import React, { Component } from "react";
class WorkExperience extends Component {
render() {
const workExperience = [
{
title: "title",
company: "company",
location: "location",
description: "description",
},
];
return (
<>
<div id="content" className="content">
<h1 className="title">Work Experience</h1>
<div className="work-experience">
<p>Job Title: {workExperience[0].title}</p>
<p>Company: {workExperience[0].company}</p>
<p>Location: {workExperience[0].location}</p>
<p>Description: {workExperience[0].description}</p>
</div>
</div>
<button className="form-btn">+ Add Work Experience</button>
</>
);
}
}
export default WorkExperience;
And here is the form code I am currently using. This is the form I want to show/hide after clicking the Add Work Experience button shown above.
<form>
<label for="title">Job Title</label>
<input id="title" className="form-row" type="text" name="title" />
<label for="company">Company</label>
<input className="form-row" type="text" name="company" />
<label for="location">Location</label>
<input className="form-row" type="text" name="location" />
<label for="description">Job Description</label>
<textarea rows="4" cols="50" name="description"></textarea>
<button className="save">Save</button>
<button className="cancel">Cancel</button>
</form>
You can use an if statement or a ternary to return different jsx. That would look something like this. There are other ways as well, however this is a basic example of something you could do.
<>
{
shouldShow ?
(
<div id="content" className="content">
<h1 className="title">Work Experience</h1>
<div className="work-experience">
<p>Job Title: {workExperience[0].title}</p>
<p>Company: {workExperience[0].company}</p>
<p>Location: {workExperience[0].location}</p>
<p>Description: {workExperience[0].description}</p>
</div>
</div>
<button className="form-btn">+ Add Work Experience</button>
) : (
<form>
<label for="title">Job Title</label>
<input id="title" className="form-row" type="text" name="title" />
<label for="company">Company</label>
<input className="form-row" type="text" name="company" />
<label for="location">Location</label>
<input className="form-row" type="text" name="location" />
<label for="description">Job Description</label>
<textarea rows="4" cols="50" name="description"></textarea>
<button className="save">Save</button>
<button className="cancel">Cancel</button>
</form>
)
}
</>
Where shouldShow is what determines whether the form is showing or not.
The benefit to this is that if the form is showing, the other content is not added to the DOM and vice versa.
shouldShow would be a variable you could add to state, and when the button is clicked, you toggle the state variable, causing a re-render.
https://reactjs.org/docs/state-and-lifecycle.html
You could also choose to render styles depending on whether or not that component is showing, the key being that boolean state variable that is re-rendering the component.
Use Repeater Felilds to add User Work Experience. It's so easy to handle like this.
Repeater Component
import React from "react";
const Repeater = ({ inputFields, setInputFields }) => {
const handleFormChange = (index, event) => {
let data = [...inputFields];
data[index][event.target.name] = event.target.value;
setInputFields(data);
};
const removeFields = (index) => {
let data = [...inputFields];
data.splice(index, 1);
setInputFields(data);
};
return (
<div className="row">
{inputFields.map((input, index) => {
return (
<>
<div className="form-group col-sm-12 col-md-4 mb-3">
<div className="controls">
<input
type="text"
className="form-control inputset"
id="title"
placeholder="title"
name="title"
data-validation-required-message="This field is required"
aria-invalid="true"
required
value={input.title}
onChange={(event) => handleFormChange(index, event)}
/>
<div className="help-block" />
</div>
</div>
<div className="form-group col-sm-12 col-md-4 mb-3">
<div className="date-picker">
<input
type="text"
className="pickadate form-control inputset"
value={input.company}
onChange={(event) => handleFormChange(index, event)}
name="company"
id="pass"
data-validation-required-message="This field is required"
data-toggle="tooltip"
data-trigger="hover"
data-placement="top"
data-title="Date Opened"
data-original-title=""
required
/>
</div>
</div>
<div className="form-group col-sm-12 col-md-4 d-flex mb-3">
<input
type="text"
className="form-control inputset"
id="location"
placeholder="location"
name="location"
data-validation-required-message="This field is required"
aria-invalid="true"
required
value={input.location}
onChange={(event) => handleFormChange(index, event)}
/>
<input
type="text"
className="form-control inputset"
id="description"
placeholder="description"
name="description"
data-validation-required-message="This field is required"
aria-invalid="true"
required
value={input.description}
onChange={(event) => handleFormChange(index, event)}
/>
{inputFields.length === 1 ? null : (
<button
type="button"
className=" d-flex justify-content-center align-items-center ml-1 btn"
onClick={() => {
removeFields();
}}
>
<i className="uil-trash-alt" />
</button>
)}
</div>
</>
);
})}
</div>
);
};
export default Repeater;
Main Component
use these as states and pass the objects to the Repeater Component. First, the state is empty and when the user clicks on the button Add More Experience The files auto-show.
const [inputFields, setInputFields] = useState([
{ degree_title: "", institue: "", end_date: "" },
]);
const addFields = () => {
let newfield = { degree_title: "", institue: "", end_date: "" };
setInputFields([...inputFields, newfield]);
};
<Repeater
inputFields={inputFields}
setInputFields={setInputFields}
addFields={addFields} />
I wish this solution helps you :) Make sure to change the state object according to your requirements.
Ihave this modal with 2 textarea, but every time that i type some keybord it just stop and go out of the text area.
the problem is on onChange={event => setTitle(event.target.value)} but i dont know what can i do.
<Modal.Body>
<form onSubmit={Patch} className="form">
<div className="control">
<div className="field">
<h2>What's in your mind?</h2>
<textarea
className="input1"
type="text"
value={title}
placeholder="enter your title"
onChange={event => setTitle(event.target.value)}
/>
<
/div>
<div className="field">
<textarea
className="input2"
type="text"
value={content}
placeholder="insert your content"
onChange={event => setContent(event.target.value)}
/>
</div>
<div className="form-btn">
<button onClick={() => setModalshow2(false)} disabled={!title || !content} type="submit" className="btnSend">CREATE</button>
</div>
</div>
</form>
</Modal.Body>
When you type something in the text area, the parent component is also re-rendering. Try with autoFocus attribute
<textarea
className="input2"
type="text"
value={content}
placeholder="insert your content"
onChange={event => setContent(event.target.value)}
autoFocus
/>
Objective:
Need to pre-fill the form if the user has address saved in the DB.
Issue:
I am passing down the address object (coming from backend for the logged in user). :
{
city: "CA"
line1: "testline1"
line2: "testline2"
phone: "7772815615"
pin: "1234"
state: "CA"
user: "5eea03a736b70722c83a7b63"
}
Though I am able to console log it, but I am unable to pre-populate it in the form (rendered by the child component)
Child Component
let addressFinalValue = {};
const addressValue = (e) => {
addressFinalValue[e.target.name] = e.target.value;
};
const propsAddress = props.address;
const [address, setAddress] = useState(propsAddress);
console.log(propsAddress); // < -- ABLE TO CONSOLE LOG IT
return (
<div>
<div className="modal-header ">
<h5 className="modal-title text-center">
{address ? 'Please enter your address' : 'Please confirm your address'}
</h5>
<button className="close" data-dismiss="modal" aria-label="close">
<span className="edit-order-button" aria-hidden="true">Edit order</span>
</button>
</div>
<div className="container my-4">
<form onSubmit={submitHandler}>
{error && <p className="login-error" style={{ color: "red" }}>{error}</p>}
<div className="form-group">
<input id="address-line-1" className="form-control" value={propsAddress.line1}
onChange={addressValue} name="line1" type="text" placeholder="Line 1" />
</div>
<div className="form-group">
<input id="address-line-2" className="form-control" value={propsAddress.line2}
onChange={addressValue} name="line2" type="text" placeholder="Line 2" />
</div>
<div className="form-group">
<input id="city" className="form-control" value={propsAddress.city}
onChange={addressValue} name="city" type="text" placeholder="City" />
</div>
<div className="form-group">
<input id="state" className="form-control" value={propsAddress.state}
onChange={addressValue} name="state" type="text" placeholder="State" />
</div>
<div className="form-group">
<input id="pin" className="form-control" value={propsAddress.pin}
onChange={addressValue} name="pin" type="text" placeholder="PIN" />
</div>
<div className="form-group">
<input id="phone" className="form-control" value={propsAddress.phone}
onChange={addressValue} name="phone" type="text" placeholder="Phone Number" />
</div>
<hr />
<button className="btn btn-success">Save Address & Continue</button>
</form>
</div>
</div> );
Is there something I am missing here? I don't know what it is.
I would achieve this using the following:
Make the child component a class with state. Pass the child component a populate prop, with the address values.
<ChildComponent populate={address} />
constructor(props){
this.state = {
...props.populate
}
}
handleAddressChange(e, addressItem){
this.setState({[addressItem]: event.target.value});
}
Then, in your form, set the value of each form item equal to the stateful address value. For example:
<div className="form-group">
<input id="address-line-1" className="form-control" value={this.state.line1}
onChange={(e) => handleAddressChange(e, 'line1')} name="line1" type="text" placeholder="Line 1" />
</div>
Make sure your onChange event handler is updating the child components this.state.address value using setState.
Checkout this file for more info: https://github.com/ccrowley96/grocerylist/blob/master/client/src/components/AddEditModal/AddEditModal.js
I do something very similar.
I am facing circular dependency issue in my modal where there is signup form and a login button in the signup form for already registered user. Also login form has then signup button for not already registered user. I have heard es6 solves circular dependency issue but i am still getting it. How can i solve this issue?
WARNING in Circular dependency detected:
app/containers/LoginContainer/index.js ->
app/containers/Register/index.js ->
app/containers/LoginContainer/index.js
WARNING in Circular dependency detected:
app/containers/Register/index.js ->
app/containers/LoginContainer/index.js ->
app/containers/Register/index.js
import Login from "containers/LoginContainer";
const mapDispatchToProps = dispatch => ({
showDialog: dialog => dispatch(showDialog(dialog)),
hideDialog: () => dispatch(showDialog("null"))
});
class Register extends React.Component {
render() {
const { show_password, user } = this.state;
return (
<Modal show onHide={() => this.props.hideDialog()}>
<form onSubmit={this.handleSubmit}>
<div className="form-group form-block">
<input
type="text"
name="first_name"
className="form-control-form "
placeholder="First Name"
onChange={this.handleChange}
/>
</div>
<div className="form-group form-block">
<input
type="text"
name="last_name"
className="form-control-form "
placeholder="Last Name"
onChange={this.handleChange}
/>
</div>
<div className="form-group form-block">
<input
type="email"
name="email"
className="form-control-form "
placeholder="Email"
onChange={this.handleChange}
/>
</div>
<div className="form-group form-block">
<input
type={show_password ? "text" : "password"}
name="password"
className="form-control-form"
placeholder="Password"
onChange={this.handleChange}
/>
</div>
</form>
<Modal.Footer>
<a
className="btn-gst"
onClick={() => this.props.showDialog(<Login />)}
>
Login
</a>
</Modal.Footer>
</Modal>
);
}
}
import Register from 'containers/Register';
<Modal show onHide={() => this.props.hideDialog()}>
<form onSubmit={this.handleSubmit}>
<div className="form-group form-block">
<input
type="text"
name="username"
/>
</div>
<div className="form-group form-block">
<input
type="password"
name="password"
required
/>
</div>
<div className="row">
<div className="col-md-6">
<div className="checkbox meta">
<label>
<input type="checkbox" /> Remember me
</label>
</div>
</div>
</form>
<Modal.Footer>
<a
className="btn-gst"
onClick={() => this.props.showDialog(<Register />)}
>
Sign Up
</a>
</Modal.Footer>
</Modal>
This is an extension of the the question I had asked earlier today (it's still unsolved, any help is very much appreciated). I have seen a lot of questions regarding this on stack overflow, and my code is based on something I found on a tutorial website.
I have 2 password forms which I wish to validate. I just want to submit it if they match. Here's my code-
<li>
<div class="input-group col-xs-5 pw">
<input type="password" name="pw" class="form-control" placeholder="Enter a new password" id="new-pw" />
</div>
</li>
<li>
<div class="input-group col-xs-5">
<input type="password" name="cnfrm-pw" id="cnfrm-pw" class="form-control" placeholder="Confirm new password" />
<span class="input-group-btn">
<button class="btn btn-primary" type="submit" id="pw-btn"> <em class="glyphicon glyphicon-circle-arrow-right"> </em> </button>
</span>
</div>
</li>
My javascript-
$(document).ready(function () {
$('#pw-btn').click( function() {
var pwd1 = document.getElementById("new-pw").value;
var pwd2 = document.getElementById("cnfrm-pw").value;
if (pwd1 != pwd2)
{
document.getElementById("cnfrm-pw").setCustomValidity("Passwords Don't Match");
}
else {
document.getElementById("cnfrm-pw").setCustomValidity('');
//empty string means no validation error
}
}
);
});
I am expecting an HTML5 validation form which tells me the passwords dont match, something like this. Nothing happens however.
Is there a mistake in my approach to custom validation? Thank you in advance all, very grateful for the help and advise.
ANSWER
I used the following code to get this working. It was a modification of the submitted answers. Thanks for all the help guys!
HTML:
<form action="#" id="f" method="post">
<li>
<div class="input-group col-xs-5 pw">
<input type="password" name="pw" class="form-control new-pw" placeholder="Enter a new password" id="new-pw" required pattern="(?=.*\d)(.{6,})" />
</div>
</li>
<li>
<div class="input-group col-xs-5">
<input type="password" name="cnfrm-pw" id="cnfrm-pw" class="form-control cnfrm-pw" required placeholder="Confirm new password" />
<span class="input-group-btn">
<button class="btn btn-primary" type="submit" id="pw-btn"> </button>
</span>
</div>
</li>
</form>
JS
$(document).ready(function () { //This confirms if the 2 passwords match
$('#f').on('keyup', '.cnfrm-pw', function (e) {
var pwd1 = document.getElementById("new-pw").value;
var pwd2 = document.getElementById("cnfrm-pw").value;
if (pwd1 != pwd2) {
document.getElementById("cnfrm-pw").setCustomValidity("The passwords don't match"); //The document.getElementById("cnfrm-pw") selects the id, not the value
}
else {
document.getElementById("cnfrm-pw").setCustomValidity("");
//empty string means no validation error
}
e.preventDefault(); //would still work if this wasn't present
}
);
});
.setCustomValidity tooltip will trigger only when the form is submitting.
Javascript
$(document).ready(function() {
$('#f').submit(function(e) {
var pwd1 = document.getElementById("new-pw").value;
var pwd2 = document.getElementById("cnfrm-pw").value;
if (pwd1 != pwd2) {
document.getElementById("cnfrm-pw").setCustomValidity("Passwords Don't Match");
} else {
document.getElementById("cnfrm-pw").setCustomValidity('');
//empty string means no validation error
}
e.preventDefault();
}
);
});
HTML
<form action="#" id="f"><li>
<div class="input-group col-xs-5 pw">
<input type="password" name="pw" class="form-control" placeholder="Enter a new password" id="new-pw" />
</div>
</li>
<li>
<div class="input-group col-xs-5">
<input type="password" name="cnfrm-pw" id="cnfrm-pw" class="form-control" placeholder="Confirm new password" />
<span class="input-group-btn">
<input type="submit" />
</span>
</div>
</li>
</form>
Have a look:
http://codepen.io/anon/pen/WwQBZy
I believe you're missing required attribute:
<input type="password" name="pw" class="form-control" placeholder="Enter a new password" id="new-pw" required />
Notice the required at the end.
Also, if you want to set a minimum:
<input type="password" name="pw" class="form-control" placeholder="Enter a new password" id="new-pw" pattern=".{5,}" title="Minmimum 5 letters or numbers." required />
As for the submitting the form, when the validation passes, you could submit the form using submit() function available in the Web API. You can read about it here.