I want to create a contact form for my react app, which is a static app (I have no back-end at all, only front-end). I'm trying to do this with a POST request to a certain API, and I found that Axios may be helpful. I want to do something like when the user clicks the Submit button, it calls a function that does all the validations on the form, and then submit the data via a POST action with Axios.
Is this possible, or am I wrong with my approach? Thanks in advance.
Yes, you can. What you'll want to do is listen for the onSubmit event of your form and send the POST request in that listener. You can do the validation inside that method as well.
handleSubmit(e) {
// Stop browser from submitting the form.
e.preventDefault();
// Validate here or directly when setting state.
// ...
// Then send a POST request to your endpoint.
axios
.post('https://your-form.com/endpoint', {
// Your data goes here.
firstName: this.state.firstName,
lastName: this.state.lastName
})
.then(function(response) {
// Done!
console.log(response);
})
}
// In the render method: listen for the submit event.
<form onSubmit={this.handleSubmit} />
Here's a working example:
class Example extends React.Component {
constructor() {
super();
this.state = {
firstName: '',
lastName: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleSubmit(e) {
// Stop browser from submitting the form.
e.preventDefault();
// Validate here or directly when setting state.
// Then send a POST request to your endpoint.
axios
.post('https://reqres.in/api/users', {
firstName: this.state.firstName,
lastName: this.state.lastName
})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
name="firstName"
value={this.state.firstName}
onChange={this.handleChange}
/>
<input
type="text"
name="lastName"
value={this.state.lastName}
onChange={this.handleChange}
/>
<input type="submit" />
</form>
);
}
}
ReactDOM.render(<Example />, document.getElementById('root'));
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.2/axios.min.js"></script>
<div id="root"></div>
Related
I want to submit a hidden form when the page loads. Since the form is hidden, I can’t use a submit button. So how can I automatically submit a form when the page loads in vuejs?
<template>
<div v-html="this.paymentResponse"></div>
</template>
<script>
import EventBus from '../../event-bus'
export default {
data() {
return {
paymentResponse: null
}
},
mounted() {
console.log('mounted')
this.$refs.submitBtn.click();
},
beforeCreate() {
EventBus.$on("payment", response => {
this.paymentResponse = response
})
}
}
</script>
You can trigger the submit button on mounted as follows:
new Vue({
el: '#sg1',
mounted(){
this.$refs.submitBtn.click();
},
methods:{
formSumitted(){
console.log("submitted");
}
}
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="sg1">
<form style="display:none" v-on:submit.prevent="formSumitted">
<button type="submit" ref="submitBtn">Submit</button>
</form>
</div>
UPDATE:
Since the form is passed and rendered using v-html, I don't think you can use ref. Therefore, you can replace it with the id and use vanillla Javascript function to click the button:
document.getElementById("submitBtn").click();
The vue components have a lifeCycle, you can use the methods "created" or "mounted" for submit your form at the begining, when your app start.
new Vue({
data: {
formData: 'some data'
},
created: function () {
// here your code for submit the form
}
})
I have a simple login form written in Angular 2 reactive (data-driven) template. It's working perfectly but when I refresh the page and browser fills e-mail+password (autocomplete), my form's valid property seems false.
But when I press any key or click anywhere in my page while form is invalid, angular updates some states (I guess) and my form become valid.
How can I trigger that state? How can I say angular "Hey, check my form again."? I can't trigger my own validation script because some validation messages are alerts. If I do this, when user open this page, he/she will see these alerts.
I remember, I use trigger('input') trick to update ng-model.
updateValueAndValidity() is what you are looking for. The document is here: AbstractControl. It can force recalculate the value and validation status of the control.
Here's a demo:
form.component.ts
export class FormComponent implements OnInit {
myform: FormGroup;
// explicit validation of each field
emailValid: AbstractControl;
passwordValid: AbstractControl;
constructor(private fb: FormBuilder) {
this.myform = fb.group({
'email': ['', Validators.required],
'password': ['', Validators.required],
});
this.emailValid = this.myform.controls['email'];
this.passwordValid = this.myform.controls['password'];
}
ngOnInit() {
this.myform.get('email').valueChanges.subscribe(()=>forceValidAgain());
this.myform.get('password').valueChanges.subscribe(()=>forceValidAgain());
}
forceValidAgain(){
this.emailValid.updateValueAndValidity();
this.passwordValid.updateValueAndValidity();
}
}
form.component.html
<form [formGroup]="myform" (ngSubmit)="onSubmit(myform.value)">
<div class="form-group">
<label for="email">Email</label>
<input type="email"
class="form-control"
id="email"
name="email"
[formControl]="myform.controls['email']"
[ngClass]="{'is-invalid': !emailValid.valid && emailValid.touched }">
<div
class="invalid-feedback"
*ngIf="emailValid.hasError('required')">
This field is required
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password"
class="form-control"
id="password"
name="password"
[formControl]="myform.controls['password']"
[ngClass]="{'is-invalid': !passwordValid.valid && passwordValid.touched}">
<div
class="invalid-feedback"
*ngIf="passwordValid.hasError('required')">
This field is required
</div>
</div>
</form>
I would suggest creating a method like onValueChanged (that is mentioned in Angular2 docs), bind it to your form, and execute it while the component is initialized. So the binding to the form changes should be done in this way:
this.form.valueChanges.subscribe((data) => {
this.onValueChanged(data)
});
And execution for example just the line after like this:
this.onValueChanged();
This execution should solve your problem via validation during component initialization.
I think that the method implementation from the docs (below) is pretty clear.
onValueChanged(data?: any) {
if (!this.heroForm) { return; }
const form = this.heroForm;
for (const field in this.formErrors) {
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
Docs I am referring to: https://angular.io/docs/ts/latest/cookbook/form-validation.html
I have a submit action for my form which basically validates on submit.
It is working as i expect because when i submit the form it renders the errors. But the issue occurs when i do the submit i do not want to do the ajax request as the form is invalid. I notice that on the first submit the emailError is not set (default) but the second submit the state contains the correct emailError set to true.
I understand from the react docs that setState is not available immeditely as it is pending.
How can i get around this issue?
My code is below
import React, { Component } from 'react';
import isEmail from 'validator/lib/isEmail';
class formExample extends Component
{
constructor(props) {
super(props);
this.state = {
email: '',
emailError: false
};
this.register = this.register.bind(this);
this.updateState = this.updateState.bind(this);
}
updateState(e) {
this.setState({ email: e.target.value });
}
validateEmail() {
if (!isEmail(this.state.email)) {
console.log("setting state");
this.setState({ emailError: true });
return;
}
console.log(this.state);
this.setState({ emailError: false });
}
register(event) {
event.preventDefault();
this.validateEmail();
//only if valid email then submit further
}
render() {
return (
<div className="row">
<div className="col-md-2 col-md-offset-4"></div>
<div className="col-lg-6 col-lg-offset-3">
<form role="form" id="subscribe" onSubmit={this.register}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Email..." name="email" value={this.state.email} onChange={this.updateState} />
<div className="errorMessage">
{this.state.emailError ? 'Email address is invalid' : ''}
</div>
</div>
<div className="input-group input-group-md inputPadding">
<span className="input-group-btn">
<button className="btn btn-success btn-lg" type="submit">
Submit
</button>
</span>
</div>
</form>
</div>
</div>
);
}
}
export default formExample;
in register you call validateEmail, but not return anything, so the rest of the function get's called.
setState is async! so you cannot count on it in the rest of register.
Try this:
validateEmail() {
const isEmailError = !isEmail(this.state.email)
this.setState({ emailError: isEmailError });
return isEmailError;
}
register(event) {
if(this.validateEmail()){
//ajax
};
}
other approach will be:
validateEmail(ajaxCb) {
const isEmailError = !isEmail(this.state.email)
this.setState({ emailError: isEmailError }, ajaxCb);
}
register(event) {
function ajaxCb(){...}
this.validateEmail(ajaxCb)
}
This is my form
<form className="input-group" onSubmit={this.handleSubmit}>
<input className="form-control"
type="text"
placeholder="Insert name"
autofocus="true" />
<span className="input-group-btn">
<button type="submit" className={classNames}>Add</button>
</span>
</form>
This is my event handler:
handleSubmit(e) {
e.preventDefault();
let name = e.target[0].value;
if (name.length > 0) {
this.props.dispatch(createClassroom(name));
}
}
My question is:
what's the proper "redux way" to clearing the form after submitting it?
Do I need to dispatch a different action or should I use the existing createClassroom action?
Note: I'd rather not use redux-form package.
First, you have to make sure that the <input> is a controlled component by passing its respective value from the state:
const { classroom } = this.props;
// in return:
<input type="text" value={ classroom.name } />
Then, the form can be cleared by ideally submitting a RESET action that your classroom reducer acts upon:
const initialState = {};
function classroomReducer(state = initialState, action) {
switch (action.type) {
// ...
case 'RESET_CLASSROOM':
return initialState;
default:
return state;
}
}
Running into a weird problem with Angular forms (running 1.2 rc.2). If I leave the form without a name and prepend each model with a common name, the form sends fine. If I remove the prepended name from each model and give the form that name, the submit action doesn't bind the data and the form tries to send an empty request payload.
This model works fine, except Angular's form validation doesn't instantiate
<form ng-submit="sendForm()">
<input type="text" ng-model="my_form.fullname">
<button type="submit">Submit</button>
<form>
.
app.controller("MyCtrl", function($scope, $http) {
$scope.sendForm = function() {
$http({ method:'POST', url: '...', data: $scope.my_form; })
.then(function(result) { alert("The form was sent"); },
function(reason) { alert("There was a problem"); });
}
}
So now if I add a name attribute to my form and remove it from the models, the form tries to send empty data...
<form name="my_form" ng-submit="sendForm()">
<input type="text" ng-model="fullname">
<button type="submit">Submit</button>
<form>
It seems like my_form no longer exists. In fact, if I don't initialize $scope.my_form = {} on the controller the form won't even send an empty object.
Any advice on how to get the second method to work?
When you give the form a name, that name becomes a variable with meta-data about the fields... dirty flags, errors, etc. It doesn't actually hold the data.
So, when you set ng-model to fullname, the value isn't being set on the my_form object, it is being set directly on your $scope.
Personally, I prefer to do it this way:
<form name="my_form" ng-submit="sendForm(formData)">
<input type="text" ng-model="formData.fullname">
<button type="submit" ng-disabled="my_form.$invalid">Submit</button>
<form>
Then your code looks like this:
app.controller("MyCtrl", function($scope, $http) {
$scope.sendForm = function(formData) {
$http({
method:'POST',
url: '...',
data: formData
})
.then(
function(result) {
alert("The form was sent");
},
function(reason) {
alert("There was a problem");
}
);
}
}