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.
Related
I have react app with with complex component layout with multiple forms.
I know that placing one form inside another is not allowed. But I have a component which renders a form and must be placed inside my form. To prevent forms be rendered one inside another I use react portal.
But when I try to submit form rendered with portal, first form is also submitted that is unexpected. Looks like I miss something important.
How to prevent first form submit when submitting the second?
Thank you
Simplified example is here
import { createPortal } from "react-dom";
const Portal = ({ children, elm }) => createPortal(children, elm);
export default function App() {
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 1");
}}
>
First form <input type="text" value="1" />
<Portal elm={document.querySelector("body")}>
Second form{" "}
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 2");
}}
>
<input type="text" value="2" />
<input type="submit" value="submit 2" />
</form>
</Portal>
</form>
</div>
);
}
I had the same problem, as #EisaRezaei said in the first comment, using e.stopPropagation() in the form inside the portal, and submit type buttons, everything worked fine
While using
vee-validate#4.4.5
vue#3.1.4
I encountered following problem:
<Form #submit="onSubmit" :validation-schema="schema">
<div class="mb-3">
<label for="edit-email" class="form-label">E-mail</label>
<Field
id="edit-email"
class="form-control"
name="email"
type="text"
:validateOnInput="true"
/>
<ErrorMessage class="invalid-feedback" name="email" />
</div>
<button #click="checkEmail" type="button">Check e-mail address</button>
<!-- non-important part of the form -->
</Form>
I'd like to manually validate <Field /> when the button is clicked (error message should appear) and then I want to use the field's value to perform another action.
I wrote following code:
import { useFieldValue } from 'vee-validate';
// setup
setup() {
const schema = object({
email: string().required().email().label("e-mail"),
});
function verifyEmail(v) {
const emailValue = useFieldValue("email");
console.log(emailValue); // empty ComputedRefImpl
}
return {
schema,
verifyEmail,
};
},
}
And this doesn't work.
emailValue is returned as ComputedRefImpl with an undefined value.
I guess I'm mixing Components & Composition API flavors of vee-validate. But still don't know how to resolve this issue.
Created sandbox with this: https://codesandbox.io/s/vue3-vee-validate-form-field-forked-xqtdg?file=/src/App.vue
Any help will be much appreciated!
According to vee-validate's author:
https://github.com/logaretm/vee-validate/issues/3371#issuecomment-872969383
the useFieldValue only works as a child of a useForm or useField.
So it doesn't work when <Field /> component is used.
I have two inputs, one textarea and three labels. When input or textarea is in foucs, I want to add some class for some animation on label, but I can not select that specific label. Is there a way to do this?
here is a code
<form onSubmit={this.handleSubmit}>
<div className="contact-form">
<div className="contact-form_group">
<label htmlFor="name" className={`contact-label name`}>
Ime
</label>
<input onChange={this.handleChange} onFocus={this.handleFocus} id="name" value={this.state.name} className="contact-form_input" type="text" name="name" />
</div>
<div className="contact-form_group">
<label htmlFor="email" className={`contact-label email`}>
Email
</label>
<input onChange={this.handleChange} onFocus={this.handleFocus} id="email" value={this.state.email} className="contact-form_input" type="email" name="email" />
</div>
<div className="contact-form_group">
<label htmlFor="message" className={`contact-label message`}>
Message
</label>
<textarea className="contact-form_textarea" id="message" cols="3" rows="8" onChange={this.handleChange} onFocus={this.handleFocus} value={this.state.msg} name="msg" />
</div>
<Button className="button" type="submit" children="Send" />
</div>
If you're not worried about browser compatibility you could use the cutting edge CSS selector :focus-within
.contact-form > div:focus-within label
color: red
BUT I wouldn't actually recommend that just yet. It's still part of the working draft and not widely supported.
In react, you could keep track of the active element's name and conditionally apply a class on render to the label. So onFocus/onBlur set focusedElement, eg
onFocus(e) {
this.setState({focusedElement: e.currentTarget.getAttribute('name')})
}
and then in render do something like
className={`contact-label name ${this.state.focusedElement === 'name' ? 'focused' : ''}`}
Here's a working example -
class TodoApp extends React.Component {
constructor(props) {
super(props)
this.state = {
focusedElement: null
};
}
onFocus(e) {
this.setState({
focusedElement: e.currentTarget.getAttribute('name')
});
}
onBlur(e) {
this.setState({
focusedElement: null
});
}
render() {
return ( <
div >
<
label className = {
this.state.focusedElement === 'name' ? 'focused' : ''
} > Label For Name < /label> <
input name = 'name'
type = 'text'
onFocus = {
this.onFocus.bind(this)
}
onBlur = {
this.onBlur.bind(this)
}
/>
<
label className = {
this.state.focusedElement === 'other' ? 'focused' : ''
} > Label For Other Value < /label> <
input name = 'other'
type = 'text'
onFocus = {
this.onFocus.bind(this)
}
onBlur = {
this.onBlur.bind(this)
}
/> < /
div >
);
}
}
ReactDOM.render( < TodoApp / > , document.querySelector("#app"))
.focused {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
You don't need to add a class to let your css if the input/textarea it's on focus. CSS can handle this for you.
input:focus {
background-color: 'red'; // or do some animation here
}
React doesn't have a very efficient way of handling nested child components in a way similar to this. The best way to handle styling for specific nodes/children would be to use classes and then css to style appropriately.
In your case you would do something like this:
.contact-form_input:focus {
background-color: #eee;
}
If you wanted to add some styling on hover or some additional animation it would be done in a similar way (using CSS):
.contact-form_input:hover {
background-color: #aaa;
-webkit-animation: fadein 0.5s;
animation: fadein 0.5s;
}
It would not be appropriate to incorporate JQuery with ReactJS as other posters have suggested.
There is a React synthetic event for onFocus. You could update the state as the focus changes and change each inputs className.
JSFiddle
<div className="form__group">
<label htmlFor="input1" className={focus === "input1" ? "focused__input" : "input"}>Input 1</label>
<input name="input1" onChange={this._onChange.bind(this)} onFocus={this._onFocus.bind(this, "input1")}/>
</div>
You can define ref to that label and on focus you can get the value of that lable using
// Define ref to label
// Get label object on focus change event and update the class accordingly for label
var object = this.refs.labelName;
You can use jquery npm install --save jquery
and use jquery's addClass method.
import $ from 'jquery'
.....
<form onSubmit={this.handleSubmit}>
<div className='contact-form'>
<div className='contact-form_group'>
<label htmlFor='name' className={`contact-label name`} id='l1' >Ime</label>
<input onChange={this.handleChange}
onFocus={()=>{$(#l1).addClass('classNameYouWantToAdd')}} id='name'
value={this.state.name}
className='contact-form_input'
type='text' name='name'/>
</div>
<div className='contact-form_group'>
<label htmlFor='email' className={`contact-label email`} id='l2'>Email</label>
<input onChange={this.handleChange}
onFocus={()=>{$(#l2).addClass('classNameYouWantToAdd')}} id='name'
id='email' value={this.state.email} className='contact-form_input' type='email' name='email'/>
</div>
<div className='contact-form_group'>
<label htmlFor='message' className={`contact-label message`}>Message</label>
<textarea className='contact-form_textarea' id='message' cols='3' rows='8' onChange={this.handleChange} onFocus={this.handleFocus} value={this.state.msg} name='msg'></textarea>
</div>
<Button className='button' type='submit' children='Send' />
</div>
</form>
So, I want to create a card component many times I want on a click of a button but the problem is that it just creates the cardComponent one time. What should I do? Is there anyone that I could create these.
This is the code:
class GCARD extends Component {
constructor(props) {
super(props);
// This state changes so the card is generated
this.state = {
change: '',
}
this.handel = this.handel.bind(this);
}
handel = (element) => {
// This is the element which creates the card.
element = <CardComponent data="Give a little detail about the thing's you like!"
heading= "Create Your Own Card" image="./owl.jpg"/>
this.setState({
change: element
});
}
render() {
return (
<div>
<div className="form-div">
<div>
<p className="form-title">Create Your Own Card</p>
<hr/>
</div>
<div>
<label className="form-label">Main Heading </label>
<input className="form-input" type="text"/>
<br/><br/>
<label className="form-label">Some Info</label>
<input className="form-input1" type="text"/>
<br/><br/>
{/* Just focus on the button */}
<button onClick={this.handel} className="form-btn">CREATE</button>
</div>
</div>
<div>
{this.state.change}
</div>
</div>
);
}
}
Your current code only replaces the element. You want to use an array instead e.g. use it like this
this.setState({
change: this.state.change.concat(element)
});
The problem on your code is that you override every time the same component. I changed your code for you to fix this:
class GCARD extends Component {
constructor(props) {
super(props);
// This state changes so the card is generated
this.state = {
change: [],
}
this.handel = this.handel.bind(this);
}
handel = (element) => {
// This is the element which creates the card.
let components = this.state.change;
element = <CardComponent data="Give a little detail about the thing's you like!"
heading="Create Your Own Card" image="./owl.jpg" />
components.push(element);
this.setState({
change: components
});
}
render() {
return (
<div>
<div className="form-div">
<div>
<p className="form-title">Create Your Own Card</p>
<hr />
</div>
<div>
<label className="form-label">Main Heading </label>
<input className="form-input" type="text" />
<br /><br />
<label className="form-label">Some Info</label>
<input className="form-input1" type="text" />
<br /><br />
{/* Just focus on the button */}
<button onClick={this.handel} className="form-btn">CREATE</button>
</div>
</div>
<div>
{this.state.change.map(comp => (comp))}
</div>
</div>
);
}
}
There are many different ways you can approach this. I would recommend binding an onClick handler to your create button which would push an object into an array, which then, in turn, you could use to set the state. Then in your render, map over the state to return each card. Remeber you may need to use appropriate CSS for margins, inline-flex etc.
eg:
clickHander(){
let arr = [];
arr.push({
<card/>
})
this.setState({change: arr})
}
render(){
const card = this.state.change.map((card) => { return ( card )})
return (
<div>
{card}
</div>
)
}
Hope this helps!
I'm using a switch checkbox in render, so one important attribute to detect if it's checked or not is defaultChecked. I set the state previously in the componentWillReceiveProps. I try first putting the state as attribute but I'm getting an error Unexpected token when it compiles the code with babel.js. After I try using dangerouslySetInnerHTML but it's still not working (bottom error).
First try:
<input type="checkbox" name="onoffswitch" {this.state.required} />
App.jsx
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
required: ''
};
};
componentWillReceiveProps( nextProps ){
//more code
this.setState({
required: 'defaultChecked'
});
};
render() {
return(
<div id="section">
<div className="bottom-question">
<div>
<div className="onoffswitch-add pull-left">
<input type="checkbox"
name="onoffswitch"
dangerouslySetInnerHTML={this.state.required} />
<label className="onoffswitch-label-add" htmlFor="switch-required">
<div className="onoffswitch-inner-add"></div>
<div className="onoffswitch-switch-add"></div>
</label>
</div>
</div>
</div>
</div>
)
}
}
Error:
The full text of the error you just encountered is:
input is a void element tag and must neither have `children`
nor use `dangerouslySetInnerHTML`. Check the render method of EditInput
you want to use the checked property to apply a check to the checkbox input in javascript
<input type="checkbox" name="onoffswitch" checked={this.state.required === 'defaultChecked'} />
when you set the state of required to be whatever you want it to be (in this case you are using the string 'defaultChecked') you need to tell the input to check itself or not based on that.
I would recommend you refactor the state variable to be a boolean and call it checked like so
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: false
};
};
componentWillReceiveProps( nextProps ){
//more code
this.setState({
checked: true
});
};
render() {
return(
<div id="section">
<div className="bottom-question">
<div>
<div className="onoffswitch-add pull-left">
<input type="checkbox"
name="onoffswitch"
checked={this.state.checked} />
<label className="onoffswitch-label-add" htmlFor="switch-required">
<div className="onoffswitch-inner-add"></div>
<div className="onoffswitch-switch-add"></div>
</label>
</div>
</div>
</div>
</div>
)
}
}
I think you want <input required={this.state.required} />
React has an attribute for this.
<input type="checkbox" name="onoffswitch" disabled={this.state.required} />
where this.state.required is a boolean
You would want to have a disabled prop for your button that is true when the checkbox is not checked, and false when it is.
To do this, start with a state variable that stores the checkbox's value. Then add a function that is fired on the onChange event which toggles the state from true-> false and vice versa.
The button should then be disabled when the checkbox is unchecked.
class MyApp extends React.Component {
constructor() {
super();
this.state = {
checkboxState: false
};
}
toggleCheckbox = () => {
this.setState({checkboxState: !this.state.checkboxState});
}
render() {
return (
<form>
<input type="checkbox" name="onoffswitch" onChange={this.toggleCheckbox} />
<input type="submit" disabled={!this.state.checkboxState} value="submit" />
</form>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>