preventDefault unless form is successfully submitted - javascript

I have a user form to submit blog posts. I want to display errors on the form if users do not enter acceptable data or miss a field. I used event.preventDefault(); to keep the page from reloading when they push submit. Everything works how I want it to, accept I want the page to reload after the form is successfully submitted. as of right now, the data from the form will submit, but it will not reload the page. How can I get it so the page and form reload as soon as the form successfully submits, but not when there are errors?
Here is my jsx
import React from 'react'
import fireIconImage from '../images/fireIcon.png'
import FireIcon from './FireIcon'
export default function BlogPostForm () {
const [formState, setFormState] = React.useState({ flaire: '', title: '', text: '', fireLevel: ''});
const [isHovered, setIsHovered] = React.useState();
const [isLit, setIsLit] = React.useState();
const [formErrors, setFormErrors] = React.useState({});
/*need to start implementing the validation states,
/*will need an errorState object with a specified error for each field*/
/*handleChange for input fields*/
function handleChange(e) {
const { name, value } = e.target;
setFormState({...formState, [name]: value})
}
/*functions for fire icon handling*/
function handleMouseOver(e) {
setIsHovered(e.target.id);
}
function handleMouseLeave(e) {
setIsHovered();
}
function handleFireIconClick(e) {
setIsLit(e.target.id);
setFormState((prevFormState) => ({...prevFormState, fireLevel: e.target.id}))
}
function handleFireIconClass(fireLevel) {
const classNames = ['fireIcon']
classNames.push(`fireIcon${fireLevel}`)
if (isHovered >= fireLevel) {
classNames.push('isHeld')
}
if (isLit >= fireLevel) {
classNames.push('isLit')
}
return classNames.join(' ');
}
/*render 5 fireIcons */
const fireIconsArray = [];
for (let i = 0; i < 5; i++) {
fireIconsArray.push(
<FireIcon
onClick={handleFireIconClick}
onMouseLeave={handleMouseLeave}
onMouseOver={handleMouseOver}
className={handleFireIconClass(i+1)}
src={fireIconImage}
alt="fire icon"
id={i+1}
key={i+1}
/>
)
}
/*submit function*/
function validate(values) {
const errors = {}
if(!values.flaire) {
errors.flaire = "Flaire is required!"
}
if(!values.title) {
errors.title = "Title is required!"
}
if(!values.text) {
errors.text = "Text is required!"
}
if(!values.fireLevel) {
errors.fireLevel = "Select a fire level!"
}
return errors;
}
function submitForm(event) {
event.preventDefault();
const errors = setFormErrors(validate(formState));
if (errors) {
console.log(errors)
return;
}
/*post to database*/
const data = formState;
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}
fetch('http://localhost:8000', options);
}
/*blogPostForm jsx*/
return (
<form className="postForm">
<h1 className="postFormHeader">Create a blog post!</h1>
<select
required
className="flaireSelect"
name="flaire"
value={formState.flaire}
onChange={handleChange}>
<option disabled={true} value="">Choose a flaire</option>
<option value="JavaScript">JavaScript</option>
<option value="CSS">CSS</option>
<option value="HTML">HTML</option>
<option value="REACT">REACT</option>
<option value="BACKEND">BACKEND</option>
</select>
{formErrors.flaire && <p className="inputError inputErrorCenter">{ formErrors.flaire }</p> }
<input
value={formState.title}
onChange={handleChange}
className="titleBox"
placeholder="title"
type="text"
id="title"
name="title"
/>
{formErrors.title && <p className="inputError">{ formErrors.title }</p> }
<textarea
value={formState.text}
onChange={handleChange}
className="textBox"
placeholder="text"
type="text"
id="blogPost"
name="text"
/>
{formErrors.text && <p className="inputError">{ formErrors.text }</p> }
<div className="fireIconContainer">
{fireIconsArray}
</div>
{formErrors.fireLevel && <p className="inputError inputErrorCenter">{ formErrors.fireLevel }</p> }
<div className="blogPostFormButtonContainer">
<button className="blogPostSubmit" type="submit" onClick={submitForm}>SUBMIT</button>
<button className="blogPostCancel" type="submit">CANCEL</button>
</div>
</form>
)
}

You can check the length of the Object that validate() returns to check if there are errors, and if there are none, then you can continue, like so:
function submitForm(event) {
if (!Object.keys(validate(formState)).length === 0) {
event.preventDefault();
console.log(errors);
return;
}
// ...
}
Or place the preventDefault into your errors check, like so:
if (errors) {
event.preventDefault();
console.log(errors);
return;
}
Believe it or not, preventDefault() is not limited to an event handler scope.

If you want to reload the page after a successful save, then after fetch() call .then() & then call window.location.reload() to reload the page
As an example:
function submitForm(event)
{
event.preventDefault();
const errors = setFormErrors(validate(formState));
if (errors)
{
console.log(errors)
return;
}
/*post to database*/
const data = formState;
const options = {
method: 'POST',
headers:
{
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}
fetch('http://localhost:8000', options)
.then((response) => window.location.reload()); // You might want to check the status code or response.

Related

How to submit empty value and make it send None as a string react

I am trying to send an empty value and when I submit it, it send "None" to the data.
Here is my code base:
const [addLoanClause, setAddLoanClause] = useState("");
const handleSubmit = () => {
if (id) {
var loanProposalDetailsUpdateObject = {
...
addLoanClause: addLoanClause,
};
if (dataChanged(loanProposalDetailsUpdateObject)) {
updateUserLoanProposalRequest({
loanProposalDetails: loanProposalDetailsUpdateObject,
}).then(() => {
routeToNextPage(isUserLoanRequestInitiator, router, id);
});
}
else {
routeToNextPage(isUserLoanRequestInitiator, router, id);
}
} else {
props
.createUserLoanRequest({
requestType: transactionType,
status: "draft",
loanProposalDetails: {
...
addLoanClause: addLoanClause,
},
})
.then(data => {
routeToNextPage(isUserLoanRequestInitiator, router, data.id);
});
}
};
<DynamicWidthInput
id="addLoanClause"
value={addLoanClause}
type="textarea"
placeholder="1000 characters"
error={showErrors && getError("addLoanClause")}
onChange={e =>
handleDynamicStateChange(e, setAddLoanClause)
}
size={"xxl"}
rows="5"
/>
How can I achieve it if I want to send empty value in textarea and it will automatically know to send string "None" to the data?
You could define your value to be sent using a ternary referencing the length of the input:
const output = addLoanClause.length > 0 ? addLoanClause : 'None'
So if the length of the input is greater than zero, use the input. Else, use 'None'

How to set default value in Tagify

I have an autocomplite input on my page, but i want to show some values before user begin typing
I read Tagify documentation but find nothing about it
I tried use tagTextProp but it not works
When i set value attribute on my original input then autocomplite stop working
my input on the page
<div class="form-control">
<input id="DetailsAddress" name="address" type="text" class="form-control__control" data-action="form-control" autocomplete="off">
<div class="form-control__label"><?php EP_Lng::_e('Address'); ?></div>
</div>
<div class="form__alert form__alert_error" id="field_address" style="display:none;"></div>
my Tagify js code
cityAutocomplete(input = null) {
input = input || document.getElementById('city_autocomplete')
let url = input.dataset.url || en4.core.baseUrl + 'pets/ajax/city';
let whitelist = input.value ? JSON.parse(input.value) : [];
let tagify = new Tagify(input, {
enforceWhitelist: true,
whitelist: whitelist,
mode: 'select',
value =[{"value":"bar"}],
tagTextProp: 'value',
});
let controller;
tagify.on('input', onInput)
function onInput( e ) {
var value = e.detail.value;
tagify.settings.whitelist.length = 0; // reset the whitelist
controller && controller.abort();
controller = new AbortController();
// show loading animation and hide the suggestions dropdown
tagify.loading(true).dropdown.hide.call(tagify)
let data = new FormData();
data.append('text', value);
fetch(url, {
signal: controller.signal,
method: 'POST',
body: data
})
.then(response => response.json())
.then(whitelist => {
whitelist = whitelist.map(item => {
return {
value: item.label,
id: item.id
}
})
// update inwhitelist Array in-place
tagify.settings.whitelist.splice(0, whitelist.length, ...whitelist)
tagify.loading(false).dropdown.show.call(tagify, value); // render the suggestions dropdown
})
}
tagify.on('change', onChange)
function onChange(e) {
// outputs a String
let location_id = document.getElementById("location_id");
if (!location_id) {
console.warn('Hidden field location_id not found')
return;
}
if (!e.detail.value) {
location_id.value = '';
} else {
let value = JSON.parse(e.detail.value);
location_id.value = value[0].id;
}
}
return tagify
}
How I use it
const addressInput = document.getElementById('DetailsAddress')
this.cityAutocomplete(addressInput)

Vuelidate display error messages based on server side response?

Is there a way to create a validation on an input field based on a server side response with a vuelidate helper? I used a different approach by creating some data fields and then in my form submit check what code is being returned from the server and then displaying the error message from the data. This "kind of" works but now when the user types in the field again the error message remains until the server returns a success code.
My end result / goal would be just display the same error message for each response scenario and when the error is showing from server code responses and user begins to type again the error message is removed until another request is made.
<div class="form-field">
<label for="">
Enter your patient ID
</label>
<input type="text" class="form-input" name="isPatient" id="isPatient" v-model="$v.formData.isPatient.$model" />
<label v-if="($v.formData.isPatient.$dirty && !$v.formData.isPatient.validInput) || invalidPatient"
class="error error--invalidIsPatient">
We're sorry, this patient does not exist.
</label>
</div>
<div class="form-field">
<label for="">
Enter your Childs ID
</label>
<input type="text" class="form-input" name="isChild" id="isChild" v-model="$v.formData.isChild.$model" />
<label v-if="($v.formData.isChild.$dirty && !$v.formData.isChild.validInput) || invalidChild"
class="error error--invalidIsChild">
We're sorry, this child does not exist.
</label>
</div>
<script>
import { validationMixin } from 'vuelidate'
const { required } = require('vuelidate/lib/validators')
const VueScrollTo = require('vue-scrollto')
export default {
name: 'ActivateCard',
mixins: [validationMixin],
data() {
return {
formData: {
isPatient: null,
isChild: null
},
showDemographics: false,
showIdErrors: false,
showConfirmation: false,
invalidPatient: false,
invalidChild: false
}
},
validations: {
formData: {
isPatient: {
validInput: (value, vm) => {
const isValidValue = value != null && value.trim().length
const altValueIsValid = vm.isChild !== null && vm.isChild.trim().length
return isValidValue ? true : altValueIsValid
}
},
isChild: {
validInput: (value, vm) => {
const isValidValue = value !== null && value.trim().length
const altValueIsValid = vm.isPatient !== null && vm.isPatient.trim().length
return isValidValue ? true : altValueIsValid
}
}
}
},
methods: {
submitCardId() {
this.$v.$reset()
this.$v.$touch()
if (!this.$v.$invalid) {
const formData = new FormData()
formData.append('method', 'activate')
formData.append('isPatient', this.formData.isPatient)
formData.append('isChild', this.formData.isChild)
this.$services
.post('', formData)
.then(response => {
const responseCode = response.data.trim()
const responseSuccess = responseCode === 'success'
const responseHdBad = responseCode === 'hd-bad'
const responseCardBad = responseCode === 'card-bad'
const responseBothBad = responseCode === 'both-bad'
console.log(`activate response: ${responseCode}`)
if (responseSuccess) {
this.showDemographics = true
this.invalidPatient = false
this.invalidChild = false
}
if (responseBothBad) {
this.invalidPatient = true
this.invalidChild = true
}
if (responseHdBad) {
this.invalidPatient = true
}
if (responseCardBad) {
this.invalidChild = true
}
})
.catch(err => {
console.log(err + ' Activate Card Error')
})
}
}
}
}
</script>

Updating state when dropdown select is changed React

This onChange event handles the selection of a dataschema then makes a subsequent request to get the queryschemas of the selected dataschema. handleChange is working correctly and renders the appropriate querySchemas in a dropdown list.
handleChange = (e) => {
const dataSchema = this.state.dataSchemas.find(dataSchema => dataSchema.name === e.target.value);
if (dataSchema) {
axios({
method: 'get',
url: `${dataSchema.selfUri}/queryschemas/`,
headers: { 'Accept': "" }
})
.then(response => {
console.log(response)
console.log(JSON.stringify(dataSchema.selfUri));
console.log(dataSchema.id)
this.setState({
querySchemaId: response.data.data[0].id,
querySchemaUri: response.data.data[0].selfUri,
querySchemaName: response.data.data[0].name,
querySchemas: response.data.data, //has list of querySchemas from request
selectedId: dataSchema.id
}, () => {
console.log(this.state.querySchemaId)
console.log(this.state.querySchemaUri)
console.log(this.state.querySchemaName)
console.log(this.state.selectedId)
});
})
.catch(error => console.log(error.response));
}
}
//This is the list of querySchemas returned by the above request
{
"data" : [ {
//array postion [0] --
"id" : "2147483601",
"selfUri" : "/dataschemas/2147483600/queryschemas/2147483601",
"name" : "QS-1"
}, {
//array position [1]
"id" : "2147483602",
"selfUri" : "/dataschemas/2147483600/queryschemas/2147483602",
"name" : "QS-2"
} ]
}
querySchemaChange = e => {
const querySchema = this.state.querySchemas.find(querySchema => querySchema.name === e.target.value);
if (querySchema) {
axios({
method: 'get',
url: `/dataschemas/${this.state.selectedId}/queryschemas/${this.state.querySchemaId}/queries`, //<--- {this.state.querySchemaId} is not updating to show the current querySchema that is selected
headers: { "Accept": "" }
})
.then(response => {
console.log(response)
})
.catch(error => console.log(error.response));
}
}
Then the second call is using the querySchemaId to make a request to the specific URI,
But querySchemaId: response.data.data[0].id, always grabs the first array from the response, obviously. So my issue is if I choose a different querySchema from the drop down it is always using the response in position [0] to make the next call. How can I keep the name that is selected updated in state and use the id attached to it, so it fires the right request?
These are the select elements rendering the dropdowns
render(){
return (
<label>
Pick a DataSchema to filter down available QuerySchemas:
<select value={this.state.value} onChange={this.handleChange}>
{dataSchemas &&
dataSchemas.length > 0 &&
dataSchemas.map(dataSchema => {
return <option value={dataSchema.name}>{dataSchema.name}</option>;
})}
</select>
</label>{" "}
<br />
<label>
Pick a QuerySchema to view its corresponding queries status:
<select value={this.state.querySchemaName} onChange={this.handleChange} onChange={this.querySchemaChange}>
{querySchemas &&
querySchemas.map(querySchema => {
return <option value={querySchema.name}>{querySchema.name}</option>;
})}
</select>
</label>{" "}
<br />
)
}
You forgot to save selected value in the state (for select) and use event data (id) directly (in query url), not from state (setState is async, it will be updated later):
querySchemaChange = e => {
const querySchema = this.state.querySchemas.find(querySchema => querySchema.name === e.target.value);
if (querySchema) {
const {id, name} = querySchema
this.setState({
querySchemaId : id,
querySchemaName: name
});
axios({
method: 'get',
url: `/dataschemas/${this.state.selectedId}/queryschemas/${id}/queries`,
querySchemaName is used for current select value.
Is saving querySchemaId needed now (not used in query)? Is it used elsewhere?

Using Perl with ReactJS

What I am trying to do is run a Perl script with arguments from ReactJS and return results. For my purpose, the same could be achieved if I could run console commands through ReactJS. Eventually, I plan to make this into an electronic app. Any suggested methods? Thank you.
Keep your Perl script hosted at a web API, for instance, http://www.example.com/your/perl/script.pl. Then, in your React code, you would just do the following:
fetch('http://www.example.com/your/perl/script.pl', {
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
'method':'POST',
'body':JSON.stringify({'someargument':'123'}),
})
.then((response) => response.json())
.then((responseJson)=>{
console.info("Response?");
console.info(responseJson);
});
Your Perl script will need to have a JSON parser (I recommend CPAN's JSON lib). Then you will have communication from the front-end (ReactJS) to the back-end (your Perl script). Let the fun begin. =)
If you want to know more about Fetch(): https://scotch.io/tutorials/how-to-use-the-javascript-fetch-api-to-get-data
If you are trying to insert data using perl you can try following code:
In insert.js import following file:
import React, { Component } from 'react';
import './App.css';
export default class Insert extends React.Component {
constructor() {
super();
this.state = {
fields: {},
json_response : []
}
this.instantform= this.instantform.bind(this);
this.change=this.change.bind(this);
}
change= (e)=>{
let fields= this.state.fields;
fields[e.target.name] = e.target.value;
//alert (fields);
this.setState({
fields
});
};
renderListing() {
let recordList = []
this.state.json_response.map(record => {
alert(record.Usernamename);
return recordList.push(
<tr>
<td>{record.Usernamename}</td>
<td>{record.password}</td>
</tr>
)
})
return recordList;
}
Validate your page:
handleValidation(){
var pattern;
let fields = this.state.fields;
let errors = {};
let formIsValid = true;
if (!fields["channel_id"]) {
formIsValid = false;
errors["channel_id"] = "*Please enter your channel_id";
alert('Please enter your channel_id');
}
if (typeof fields["channel_id"] !== "undefined") {
pattern = new RegExp(/^-?\d*$/);
if (!pattern.test(fields["channel_id"])) {
formIsValid = false;
errors["channel_id"] = "*Please enter valid channel id.";
alert('Please enter valid channel id');
}
}
if (!fields["Username"]) {
formIsValid = false;
errors["Username"] = "*Please enter your Username.";
alert('Please enter your Username.');
}
if (typeof fields["Username"] !== "undefined") {
if (!fields["Username"].match(/^[a-zA-Z ]*$/)) {
formIsValid = false;
errors["Username"] = "*Please enter alphabet characters only.";
alert('Please enter alphabet characters only.');
}
}
if (!fields["Hotel_id"]) {
formIsValid = false;
errors["Hotel_id"] = "*Please enter your Hotel_id";
alert('Please enter your Hotel_id');
}
if (typeof fields["Hotel_id"] !== "undefined") {
//regular expression for email validation
//var pattern = new RegExp(/^-?\d*$/);
if (!fields["Hotel_id"].match(/^-?\d*$/)) {
formIsValid = false;
errors["Hotel_id"] = "*Please enter valid Hotel - id.";
alert('Please enter valid Hotel - id.');
}
}
if (!fields["password"]) {
formIsValid = false;
errors["password"] = "*Please enter your password.";
alert('*Please enter your password.');
}
if (typeof fields["password"] !== "undefined") {
if (!fields["password"].match(/((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[##$%]).{6,20})/)) {
formIsValid = false;
errors["password"] = "*Please enter secure and strong password.";
alert('*Please enter secure and strong password');
}
}
this.setState({
errors: errors
});
return formIsValid;
}
Form Onlick method:
instantform =(e)=>{
e.preventDefault();
if(this.handleValidation())
{
//alert("Sucess");
var fields = this.state.fields;
this.setState({ loading: true, disabled: true }, () =>
{
//console.log(fields);
fetch('http://ubuntu:90/common-cgi/trainee/krunal/my-app/src/database/insert.pl',
//fetch('http://192.168.0.50:3000/myfirst_app/src/testing.php',
{
method: 'POST',
headers:
{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(fields)
}).then(res => {
//.then(res => res.text()).then(text => {
alert("Success");
// this.setState({
// json_response: json_response
//})
//JSON.stringify(json_response);
//alert(json_response.Username);
//fields["Username"] = "";
//fields["lastname"] = "";
//fields["email"] = "";
//fields["message"] = "";
//this.setState({fields:fields});
}).catch((error) =>
{
console.error(error.toString());
//console.warn(error);
this.setState({ loading: false, disabled: false });
});
});
}
}
Render:
render() {
return (
<div className="container">
<center>
<div className="keyformwrap">
<form method="post" name="instantform" onSubmit={this.instantform}>
<br />
<label>User name</label>
<input
type="text"
id="Username"
name ="Username"
placeholder="Your User name..."
value = {this.state.fields.Username}
onChange ={e => this.change(e)}
/>
<label>User Lastname</label>
<input type="text" id="Fullname"
name ="Fullname"
placeholder="Your Full name.."
value = {this.state.fields.Fullname}
onChange ={e => this.change(e)}
/>
<label>Department</label>
<input type="text" id="department"
name ="department"
placeholder="Your department.."
value = {this.state.fields.department}
onChange ={e => this.change(e)}
/>
<label>Email </label>
<input
type="text" id="Email"
name ="Email"
placeholder="Your Hotel ID.."
value = {this.state.fields.Email}
onChange ={e => this.change(e)}
/>
<label>Password</label>
<input
type="password"
id="password"
name ="password"
placeholder="Your User Password..."
value = {this.state.fields.password}
onChange ={e => this.change(e)}
/>
<label>Retrive property * </label><input type="submit" value="Submit" />
<p>{JSON.stringify(this.state.fields)}</p>
</form>
</div>
</center>
</div>
);
}
}
App.js:
import React, { Component } from 'react';
import './App.css';
//import './Temp.css';
import Insert from "./Insert.js";
import Design_bookingcom from "./Design_bookingcom.js";
class App extends Component {
render() {
return (
<div >
<Insert />
</div>
);
}
}
export default App;
Perl file
insert.js
#!/usr/bin/perl
use CGI qw(:all);
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Headers;
use HTTP::Response;
use Data::Dumper;
use Encode;
use LWP::Simple::Post("post_xml");
use XML::Simple;
use CGI;
use JSON;
use DBI;
my $cgi = new CGI;
my $json_response;
my $response;
# Header to fatch the data from react js file
print $cgi->header(
-type => 'text/json',
-access_control_allow_origin => '*',
-access_control_allow_headers => 'content-type',
-access_control_allow_methods => 'POST',
-access_control_allow_credentials => 'true',
);
# END
$response = $cgi->param('POSTDATA');
my $json = decode_json($response);
my $username = $json->{'Username'};
my $Email = $json->{'Email'};
my $Fullname = $json->{'Fullname'};
my $department = $json->{'department'};
my $password = $json->{'password'};
my $driverr="mysql";
my $db="krunal";
my $driver="DBI:$driverr:database=$db";
my $userid="root";
my $password="passwd";
my $conn =DBI->connect($driver,$userid,$password) or die $DBI::errstr;
$qry="INSERT INTO employee(emp_id,emp_username,emp_fullname,emp_dept,emp_psasword,emp_email) VALUES('',?,?,?,?,?)";
$statement=$conn->prepare("$qry");
$statement->execute($username,$Fullname,$department,$password,$Email);
$final = $statement->finish();
print $final;

Categories