Render a new component from the current component after click the button - javascript

I am building a login/signup/reset form. I am encountering a problem which is when on the modal of reset password, I would like to click the button to submit email for reset password. After click the button, I want a new success message modal replace the current modal. But the success message always appear below the current reset password modal. How could solve it? Thank you.
Here is the modal component of reset password
import { useState } from "react";
import { updatePasswordFields } from "../constants/formFields";
import FormAction from "./FormAction";
import Input from "./Input";
import MessageContent from "./Message";
const fields = updatePasswordFields;
let fieldsState = {};
fields.forEach((field) => fieldsState[(field.id = "")]);
export default function ForgotPassword() {
const [resetPasswordState, setResetPasswordState] = useState(fieldsState);
const [showMessage, setShowMessage] = useState(false);
const handleChange = (e) =>
setResetPasswordState({
...resetPasswordState,
[e.target.id]: e.target.value,
});
const handleSubmit = (e) => {
e.preventDefault();
setShowMessage(true);
};
return (
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
<div className="">
{fields.map((field) => (
<>
<label>{field.labelText}</label>
<Input
key={field.id}
handleChange={handleChange}
value={resetPasswordState[field.id]}
labelText={field.labelText}
labelFor={field.labelFor}
id={field.id}
name={field.name}
type={field.type}
isRequired={field.isRequired}
placeholder={field.placeholder}
/>
</>
))}
<FormAction handleSubmit={handleSubmit} text="Update Password" />
{showMessage && <MessageContent />}
</div>
</form>
);
}
Here is the success message modal
import React from "react";
import { MdMarkEmailRead } from "react-icons/md";
export default function MessageContent() {
return (
<div>
<div className="text-sky-600 text-center w-full flex jutify-center">
<MdMarkEmailRead size={44} />
</div>
<div className="text-center text-sm mb-10 max-w-[300px] mx-auto">
We have sent the update password link to your email, please check that!
</div>
</div>
);
}
Here is the result what I got so far screenshot

I'm not sure if I get your means..
If you want to show MessageContent() and hide reset password form in the same modal, there is an easy way to get it.
export default function ForgotPassword() {
// ellipsis...
if (showMessage) {
return <MessageContent />
}
return (
<form ...>...</form>
)
}

Related

Passing Variables to/from Modal

I implemented a Modal which uses a custom Hook in my App that should function as a login mask for a WiFi network. So far the Modal is working and I also already managed to pass the name of the selected SSID to it. However I'm struggling with getting back a variable into my other component from where I launched the modal.
Modal.js:
import React from 'react';
import { createPortal } from 'react-dom';
const Modal = ({ isShowing, connect, ssid, hide }) => isShowing ? createPortal(
<React.Fragment>
<div className="modal-overlay" />
<div className="modal-wrapper" aria-modal aria-hidden tabIndex={-1} role="dialog">
<div className="modal">
<div className="modal-header">
<button type="button" className="modal-close-button" data-dismiss="modal" aria-label="Close" onClick={hide}>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
<p>Connect to: {ssid}</p>
<label>
<form onSubmit={connect}>
<input
id="password"
name="Password"
type="password"
value={"password"}
/>
<button type="submit">Connect</button>
</form>
</label>
</div>
</div>
</div>
</React.Fragment>, document.getElementById("modal")
) : null;
export default Modal;
useModal.js:
import { useState } from 'react';
const useModal = () => {
const [isShowing, setIsShowing] = useState(false);
const [password, setPassword] = useState("password");
function toggle() {
setPassword("HOW");
setIsShowing(!isShowing);
}
return {
password,
isShowing,
}
};
export default useModal;
Settings.js:
import React from "react";
import { useState, useEffect } from "react";
import Modal from "../../components/Modal";
import useModal from "../../components/useModal";
const electron = window.require('electron');
const { ipcRenderer } = electron;
const Settings = ({ reqReload }) => {
const [wifiList, setWifiList] = useState([{ id: "", ssid: 'No Networks available' }]);
const [ssidSelected, setSsidSelected] = useState("127.0.0.1");
const { isShowing, toggle } = useModal();
const updateWifi = (event, args) => {
setWifiList(args);
};
function openDialogue(ssid) {
setSsidSelected(ssid);
toggle();
};
/*
function connectWifi(password) {
console.log("Aktuelles Passwort: ", password);
toggle();
}
*/
useEffect(() => {
ipcRenderer.send('updateWifi');
ipcRenderer.on('wifi_list', updateWifi);
return function cleanup() {
ipcRenderer.removeListener('wifi_list', updateWifi);
};
}, []);
return (
<div className="settings">
<Modal
isShowing={isShowing}
connect={connectWifi}
ssid={ssidSelected}
hide={toggle}
/>
<div className="settings__header">
<h2></h2>
</div>
<div className="settings__body">
<div className="settings__connections">
<div className="settings__connections__wifi">
<p><i>Available Wifi-Networks:</i></p>
<div className="settings__connections__wifi__list">
{wifiList.map((item, i) => (
<div className="settings__connections__wifi__list__item" key={i}>
<button className="selectNetworkButton" type="button" onClick={() => openDialogue(item.ssid)}>{item.ssid}</button>
</div>
))}
</div>
</div>
</div>
</div>
</div>
)
};
export default Settings;
The code above already contains some things I tried. As stated before, passing the SSID to the modal worked, but I dont have a clue how to get the password back to Settings.js to handle the data there.
I'd be happy if someone can point me in the right direction!
in order to get back a variable from a child component, you can have the variable you would like to get back as a state in your parent component:
const [yourVariable, setYourVariable] = useState('')
then pass setYourVariable as a props to your modal.
this way you can set youVariable from inside the modal component, and get back its value this way :
// inside modal component
setYoutVariable(...)
I stumbled over another article just now and it seems like using a stateless component as my model leads to a dead end. Will have to convert it to a stateful component in order to extract the data from the form.

Add dynamic HTML in React JS?

Why is my code not working? I'm creating a registration form and I'm wanting to add an error message if the passwords do not match. Why is it not letting me dynamically add para tag to my html? Adding some more text here as I'm getting a post is mostly code error......
import React from 'react'
import Navbar from './components/Navbar'
import { Link } from 'react-router-dom'
import './Register.css'
import { useState, useRef } from 'react'
import { createUserWithEmailAndPassword } from "firebase/auth";
import { auth } from './firebase'
function Register() {
const div = useRef(null);
const handleSubmit = event => {
if (password == confirmPassword) {
createUserWithEmailAndPassword(auth, registerEmail, confirmPassword)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ..
});
}
else {
//problem
var passNotMatch = document.createElement('p');
passNotMatch.innerHTML = "Passwords do not match, please try again.";
div.appendChild(passNotMatch);
event.preventDefault();
}
}
return (
<>
<Navbar />
<div className='signup-div'>
<div useRef={div}>
<h2>Register</h2>
<form onSubmit={handleSubmit}>
<input className='input input_email' type="email" placeholder='Email Address' value={registerEmail} onChange={e => setRegisterEmail(e.target.value)} required /> <br />
<input className='input input_password' type="password" placeholder='Set password' value={password} onChange={e => setPassword(e.target.value)} required /> <br />
<input className='input input_password' type="password" placeholder='Confirm password' value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} required /> <br />
<button type='submit' className='register-button'>Register</button>
<Link to='/signin'>Already have an account? Sign In</Link>
</form>
</div>
</div>
</>
)
}
You're using React incorrectly. Directly interacting with the DOM is almost never the right approach in React. Instead, "dynamic" markup is conditionally included in the markup based on state values. For example, consider this markup structure:
return (
<>
<Navbar />
<div className='signup-div'>
<div>
<!-- the rest of your markup, then... -->
{showError ? <p>Passwords do not match, please try again.</p> : null}
</div>
</div>
</>
)
Note the conditional inclusion of the <p> element, based on the boolean value of showError. Which means showError is something you'd track in state:
function Register() {
const [showError, setShowError] = useState(false);
const handleSubmit = event => {
//...
}
//...
}
Its initial value is set to false, so the <p> won't be shown. Then you just update the state to true to show it:
else {
//problem
setShowError(true);
event.preventDefault();
}
You would also set it back to false wherever you want in your code. Perhaps at the beginning of the handleSubmit function for example.
Overall the concept is that you don't directly manipulate the DOM. Instead, you track the current "state" of things in state values. The rendering is based on the current state, and updates to the state trigger a re-render.

Unable to submit form in Model react

I have a model file in which I want to submit form but I am not able to trigger submit function my file is like
import React, { useState, useEffect } from "react";
import InputField from "./InputField";
import Button from "./Button";
import axios from "axios";
import { Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
function ArticleOptionsModal(props) {
const [articleOption, setArticleOption] = useState("");
useEffect(() => {
if (typeof props.articleopt === "undefined") {
setArticleOption("");
console.log("hhiii");
} else {
setArticleOption(props.articleopt.optionname);
console.log("hhiii");
}
}, [props]);
return (
<form onSubmit={e => handleSubmit(e)}>
<Modal isOpen={props.modal} toggle={props.toggle}>
<ModalHeader toggle={props.toggle}>Times</ModalHeader>
<ModalBody>
<div className='row'>
<div className='col-sm-6'>
<div className='form-group text-left'>
<label htmlFor='' className='small'>
Name
</label>
<InputField
name='username'
placeholder={"Enter Name"}
value={articleOption.optionname}
onChange={e => changeOptionName(e)}
/>
</div>
</div>
)}
</ModalBody>
<ModalFooter>
<Button
name={"Submit"}
type='submit'
btnLongWidth={false}
onClick={props.toggle}
/>
<Button
name={"Cancel"}
dangerButton={true}
btnLongWidth={false}
onClick={props.toggle}
/>
</ModalFooter>
</Modal>
</form>
);
function changeOptionName(e) {
setArticleOption(e.target.value);
}
function handleSubmit(e) {
console.log("hiiiiii");
}
}
export default ArticleOptionsModal;
Here handleSubmit is not triggering when I try to submit form. I tried using diff methods to just trigger this submit method but till now no luck . Any kind of help would be highly appreciated.
The form tag needs to be inside the modal component as otherwise, the event doesn´t bubble up correctly.
As commented, I would suggest using a form library to handle the form management.
Personally I suggest Final Form:
https://github.com/final-form/react-final-form

Hidding a form with onBlur but this have a conflict with submit button

I'm trying to hide the form with the onBlur event, but when I try to click the submit button the onSubmit function doesn't get triggered
I want to hide it after send the form or when the user leaves the div that wraps the form.
https://codesandbox.io/s/rrz10y2mnp
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
test.ts
import React, { Component } from "react";
export default class Test extends Component {
state = {
showing: false
};
showInput = () => {
this.setState({ showing: false });
};
addNew = () => {
this.setState({ showing: true });
};
sendForm = evt => {
evt.preventDefault();
console.log("clicked");
};
render() {
return (
<div>
{!this.state.showing ? (
<button onClick={this.addNew}>Add a new</button>
) : (
<div onBlur={this.showInput} tabIndex="1">
<form onSubmit={this.sendForm}>
<input autoFocus={true} type="text" />
<button type="submit">PUSH</button>
</form>
</div>
)}
</div>
);
}
}
Hide form in the sendForm function that you have. Then it should be fine. If there is some async function in sendForm you can hideForm when promise gets resolved and till then disable input.
The problem is that your calling setState before the form submits. You could use some async code to fix this issue. Here's a rudimentary example simply using setTimeout and waiting 100 milliseconds. There are better ways to do this and many reasons why you shouldn't.
waitToSetState = () => {
setTimeout(() => {
this.setState({ showing: false });
}, 100);
};
...
<div onBlur={this.waitToSetState} tabIndex="1">
<form onSubmit={this.sendForm}>
<input autoFocus={true} type="text" />
<button type="submit">PUSH</button>
</form>
</div>

Could not type any text inside textfield

I am using redux-form-material-ui for my form. With below code, i cannot type anything on the textfield. I mean to say nothing gets type in the textfield. There are two textfield in my form and one Autocomplete. One is for device name and another for timeout value. Autocomplete works though. Why is it not showing the text i have typed?
What might be the reason for this issue? Have i done somewhere mistake?
Please see an image attached. I cant write anything in device name and timeout input box. Only autocomplete box can be selected and is shown on input box.
Here is my code
import React, { Component } from 'react';
import _ from 'lodash';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import {
AutoComplete as MUIAutoComplete, MenuItem,
FlatButton, RaisedButton,
} from 'material-ui';
import {
AutoComplete,
TextField
} from 'redux-form-material-ui';
const validate = values => {
const errors = {};
const requiredFields = ['deviceName', 'deviceIcon', 'deviceTimeout'];
requiredFields.forEach(field => {
if (!values[field]) {
errors[field] = 'Required';
}
});
return errors;
};
class DeviceName extends Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.handleNext();
}
render() {
const {
handleSubmit,
fetchIcon,
stepIndex,
handlePrev,
pristine,
submitting
} = this.props;
return (
<div className="device-name-form">
<form>
<div>
<Field
name="deviceName"
component={TextField} {/* cannot type */}
floatingLabelStyle={{ color: '#1ab394' }}
hintText="Device Name"
onChange={(e) => this.setState({ deviceName: e.target.name })}
/>
</div>
<div>
<Field
name="deviceIcon"
component={AutoComplete} {/* works */}
hintText="icon"
openOnFocus
filter={MUIAutoComplete.fuzzyFilter}
className="autocomplete"
dataSource={listOfIcon}
onNewRequest={(e) => { this.setState({ deviceIcon: e.id }); }}
/>
</div>
<div>
<Field
name="deviceTimeout"
component={TextField} {/* cannot type */}
floatingLabelStyle={{ color: '#1ab394' }}
hintText="Device Timeout"
ref="deviceTimeout" withRef
onChange={(e) => this.setState({ deviceTimeout: e.target.name })}
/>
</div>
<div style={{ marginTop: 12 }}>
<RaisedButton
label={stepIndex === 4 ? 'Finish' : 'Next'}
primary
disabled={pristine || submitting}
className="our-btn"
onTouchTap={(e) => handleSubmit(e)}
/>
</div>
</form>
</div>
);
}
}
const mapStateToProps = ({ fetchIcon }) => ({
fetchIcon
});
const DeviceForm = reduxForm({
form: 'DeviceForm',
validate,
})(DeviceName);
export default connect(mapStateToProps)(DeviceForm);
By adding onChange to your Fields, aren't you preventing redux form from accepting the new values from that input field? Is there a reason you are attempting to add these to your Component state?
The examples in the documentation certainly suggest you should not need to do this - http://redux-form.com/6.1.1/examples/material-ui/
I guess you can simplify your form as-
class DeviceName extends Component {
handleSubmit = (values) => {
console.log(values); // Do something with values
}
render() {
const {
....
handleSubmit //***Change
} = this.props;
return (
<div className="device-name-form">
<form onSubmit={handleSubmit(this.handleSubmit)}>
<div>
<Field
name="deviceName"
component={TextField} {/* cannot type */}
floatingLabelStyle={{ color: '#1ab394' }}
hintText="Device Name"
//*** line removed
/>
</div>
.....
.....
<div style={{ marginTop: 12 }}>
<RaisedButton
type="submit" // setting type
label={stepIndex === 4 ? 'Finish' : 'Next'}
primary
disabled={pristine || submitting}
className="our-btn"
/>
</div>
</form>
</div>
);
}
}
I would guess that the problem is in your onChange handlers - you probably need to use target.value rather than target.name:
onChange={(e) => this.setState({ deviceTimeout: e.target.value})
I had the same issue, turned out I used the wrong import. I was using the normal import:
import { Field, reduxForm } from 'redux-form'
Because my store is immutable (using Immutable.js) I had to use the immutable import:
import { Field, reduxForm } from 'redux-form/immutable'
Some kind of error logging for redux-form would have been handy in this case.

Categories

Resources