This code is a functional component that should render a user detail page(Show details view) OR a form to edit(Edit detail view) this user info depending on the state of isUpdate. This works alright, as the update and save buttons change the state of isUpdate to render the Edit View or Show View respectively.
When I select a user, the page gets the specific user by match.params.id which also works. My problem is when the isUpdate is set to true (the edit form with the original values of the user details is rendered) I expect that the input values change when I type on the input for, but instead the value remains the same as its original value(unable to type new values).
I dont know why I am facing this problem.
UserDetail Component code below:
import React, {Fragment, useEffect, useState} from 'react';
import { connect } from 'react-redux';
import { findUser } from '../../actions/user';
const UserDetails =({match, user, loading, findUser}) => {
const[isUpdate, setIsUpdate]=useState(false);
//fetching user info based on the params id
useEffect(() => {
findUser(match.params.id);
},[])
//setting the initial state of user to the values from the fetched data
const[userData, setUserData]=useState({
name: user.name,
email: user.email,
});
//on Change handler
const onChange = e =>{
setUserData({...userData, [e.target.name]:e.target.value})
}
//User detail rendered to be viewed or edited
return loading ?
(<Fragment>
<div className="loader-container" ></div>
<div className="loader"></div>
</Fragment>) :
(isUpdate ? (
<Fragment>
<div className="detail-container">
<form>
<div className="form-row">
<div className="form-group col-md-6">
<label htmlFor="name">Full Name:</label>
<input
type="name"
className="form-control"
id="name"
name="name"
value={user.name}
onChange={e=>onChange(e)}/>
</div>
<div className="form-group col-md-6">
<label htmlFor="email">Email:</label>
<input
type="email"
className="form-control"
id="email"
name="email"
value={user.email}
onChange={e=>onChange(e)}/>
</div>
</div>
<button type="submit" className="btn btn-primary" onClick={()=>setIsUpdate(false)}>SAVE</button>
</form>
</div>
</Fragment>):
(<Fragment>
<div className="detail-container">
<div className="d-flex justify-content-end mb-20"> <button className="btn btn-warning "
onClick={()=>setIsUpdate(true)}> UPDATE</button>
</div>
<div className="row mb-10">
<div className=" col-md-6">
<div className="detail-label">Full Name:</div>
<div className="detail">{`${user.name}`}</div>
</div>
<div className=" col-md-6">
<div className="detail-label">Email:</div>
<div className="detail">{`${user.email}`}</div>
</div>
</div>
</div>
</Fragment>))
const mapStateToProps = (state) => ({
user: state.user.a_user,
loading: state.user.loading
})
export default connect(mapStateToProps,{findUser})(UserDetails);
Please I would appreciate anyone pointing me in the right direction.
The user data remains constant during the editing session, so the input element cannot work properly. Try to change its declaration using the userData instead:
<input
type="name"
className="form-control"
id="name"
name="name"
value={userData.name}
onChange={e=>onChange(e)}/>
UPDATE: in order to update the userData state whenever the user changes, you could use this trick:
const[userData, setUserData]=useState();
useEffect(
() => {
setUserData({
name: user.name,
email: user.email,
});
},
[user]
);
Take care to handle the initial condition where userData is undefined.
Your form inputs values should be targetting userData instead of user i.e
<input
...name="name"
value={userData.name} />
You need to set your userData in the useEffect method as it seems that for each user, the userData value is using values fetched previously.
useEffect(() => {
findUser(match.params.id)
setUserData(user)
},[])
I'm guessing the findUser method updates the user in the parent component.
This should work.
Related
I´m building up an Angular basic CRUD app for try new things, but wish to know why this is happening.
I´m trying to get the "post" data and I do from a service, this is working fine, the problem is when I´m setting up the form, show the rest of the values, but not the user ID.
This is the code:
HTML
<div class="container">
<h1 class="hidden__content">Modify register</h1>
<div class="row new__register__form__wrapper mt-5">
<h3 class="mb-5">Modify register</h3>
<form [formGroup]="editRegisterForm" (ngSubmit)="editRegister()">
<div class="form-group mb-3">
<input type="text" class="form-control" id="userIdInput" formControlName="user" readonly>
</div>
<div class="form-group mb-3">
<textarea class="form-control" id="titleInput" cols="30" rows="3" placeholder="Write here the title of your post" formControlName="title"></textarea>
</div>
<div class="form-group form-check mb-3">
<select class="form-select" name="completedSelect" id="comletedSelect" formControlName="completed">
<option value="default" hidden>Choose an option</option>
<option value="completed">Completed</option>
<option value="no completed">Not completed</option>
</select>
</div>
<button type="submit" class="btn btn-outline-primary new__register__form__submit">Update register</button>
</form>
</div>
</div>
TypeScript
ngOnInit(): void {
this.registerId = this.route.snapshot.paramMap.get('id');
this.todosService.getAllRegistersById(this.registerId).subscribe((res: any) => {
this.editRegisterForm = this.initEditForm(res);
});
}
initEditForm(response: any){
const { user, title, completed } = response;
let status;
completed === true? (status = 'completed'): (status = 'no completed');
return this.fb.group({
user: [user, [Validators.required]],
title: [title, [Validators.required, Validators.maxLength(199)]],
completed: [status, [Validators.required]]
});
}
Try injecting ChangeDetectorRef in constructor and run markforcheck() after form is initialized.
I would suggest a different approach.
Don't try to reassign a value to editRegisterForm, but instead inside initEditForm, you can do the following:
this.editRegisterForm.get('user').setValue(yourUserValue);
this.editRegisterForm.get('title').setValue(yourTitleValue);
this.editRegisterForm.get('completed').setValue(yourCompletedValue);
This way you're going to update your FormControl's values. Otherwise your approach is probably causing an issue with change detection and I don't see a point to reassign the value of your FormGroup, when you're just trying to update your field's values and there's an API defined for that.
I have a form with a single input which is query for the search url -
<form className={styles.searchInputContainer} role="search" action="/search">
<label htmlFor={id} className={styles.searchLabel}>{constants.search}</label>
<input id={id} className={styles.searchInput} type="search" name="q" placeholder="Search..." autocomplete="off" />
</form>
At the moment, when I hit enter, the url will end with '/search?q=whatever_the_input_is'
I am currently doing logic elsewhere in the file to check if the search bar is on a particular page. With this boolean value (isShoppingPage), I want to optionally append a 'type=shop' to the url when the user hits enter so it automatically only searches through the shop categories. I've tried appending 'type=shop' to the input value but then the url ends up having URL encoding. I'm confused as to how to conditionally add this without changing the name="q" which the input currently has and needs.
Instead of action you can use onSubmit prop of the form.
import React, {useState} from 'react';
const Form = (props) => {
const {styles, id, constants} = props;
const [qValue, setQValue] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
// here you can make API call with q=qValue and type=shop
};
return (
<form className={styles.searchInputContainer} role="search" onSubmit={handleSubmit}>
<label htmlFor={id} className={styles.searchLabel}>{constants.search}</label>
<input id={id} className={styles.searchInput} type="search" name="q" placeholder="Search..." autocomplete="off" value={qValue} onChange={e => setQValue(e.target.value)} />
</form>
)
};
This is guide from react docs
please , how can i get over this error of component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
this prevent the input field from showing what i am typing.
const [sellerName, setSellerName] = useState();
const [storeName, setStoreName] = useState("");
...
<form className="registerInputContainer customerEditInput">
<div className="regInput passForm ">
<span className="userEmail">Owner's Full name (Required)</span>
<div className="passwordContainer editCusInputField">
<input
placeholder="your name"
value={sellerName }
onChange={(e) => setSellerName(e.target.value)}
className="passwordInput regInputField"
/>
</div>
</div>
<div className="regInput passForm ">
<span className="userEmail">Store Name (required)</span>
<div className="passwordContainer editCusInputField">
<input
placeholder=""
required
value={storeName || ""}
onChange={(e) => setStoreName(e.target.value)}
className="passwordInput regInputField"
/>
</div>
</div>
...
</form>
i have tried some of the solution i saw on stackoverflow but they are not working . thanks you all
I'm learning reactjs and I have a problem with the validation in forms
so I want to have a condition if the user don't enter his name a message 'empty field' appear
else alert hello 'his name' appears
My code
import React ,{Component} from 'react';
class Formular extends Component {
constructor(props) {
super(props);
this.state={
nom:'',
prenom:'',
email:'',
password:'',
error:false,
NameErr:''
}
}
handleValidation() {
if (this.state.nom =='')
{ this.state.error=true
this.state.NameErr='empty field'
//console.log( this.state.NameErr)
return(
this.state.NameErr
)
}
}
handleClick(event){
event.preventDefault()
let error = this.handleValidation()
if (!error)
{
alert('hello '+ this.state.nom)
}
}
render() {
/* console.log('nom',this.state.nom)
console.log('prenom',this.state.prenom) */
return (
<div >
<div className="form__group field">
<input type="input" className="form__field"
placeholder="Name" name="name" id='name'
required size='100' value={this.state.nom}
onChange={(event)=>this.setState({nom:event.target.value})} />
<label for="name" className="form__label">Name</label>
</div>
<div className='alert'> {this.state.NameErr} </div>
export default Formular
You must not change the state by force
like this
this.state.NameErr='empty field'
this.state.error=true
You need to use setState
like this example
this.setState({NameErr:'empty field',error:true})
then you can in render method
{ this.state.error && <div className='alert'> {this.state.NameErr}</div>}
Thus the element will only be displayed if there is an error
Mutation of state isn't correct, always mutate state using setState()
this.setState({NameErr:'empty field', error: true})
jsx
{this.state.error && <div className='alert'> {this.state.NameErr} </div>}
First, you should wrap your input in form tag instead simply div.
Next use event onSubmit on your form to trigger submission of the form.
Create un method to check if your value is not empty, then do what you want
render () {
return <form onSubmit={handleClick}>
<div className="form__group field">
<input
id='name' name="name" type="text"
className="form__field"
size='100' required
placeholder="Name" value={this.state.nom}
onChange={(event)=>this.setState({nom:event.target.value})}
/>
<label for="name" className="form__label">Name</label>
</div>;
<div className='alert'> {this.state.NameErr} </div>
</form>;
}
NT: type attribute of input should be "text" and not "input"
EDIT: Like said other guys, change also your changing state.
How to redirect to homepage after successful login in ReactJS? and also i want to show error message whenever user enter wrong credential.
I tried something like below, but it not redirect to homepage whenever user hit their right credential. and also not showing login failed prompt whenever user hit wrong credential.
It would be great if anybody could help me out what i am trying to solve is.
./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>
How to redirect to homepage after successful login in ReactJS?
pushing to history like the way you're doing in the example should work.
and also i want to show error message whenever user enter wrong credential.
there is a nice customizable library called react-toastify.
if you want to do your own custom error message popup, create a parent component that displays the pop-up when a function called toggleError for ex. is called.