How to set form controls dirty or touched in Angular2? - forms

Hi I am developing web application in angular2. I have form in popup. On closing popup I want to reset all the fields. For example, If required error occurs then if i close and reopen the modal then same error message will be there. On closing popup error message should also go. Below is my html code.
<div *ngIf="isPopupOpen()" [ngClass]="{'modal-pop-close': _isClose}" id="myModal" class="modal-pop">
<!-- Modal content -->
<div class="modal-content-pop">
<span class="close" (click)="close()">×</span>
<h4 class="modal-title pull-left center-text"><i></i> New User</h4>
<form *ngIf="formResetToggle" class="form-horizontal" name="useronboardEditorForm" #f="ngForm" novalidate
(ngSubmit)="f.form.valid ? save() :
(!username.valid && showErrorAlert('User name is required', 'Please enter user name'));">
<div class="form-group-btn">
<label for="username" class="user-name">User Name</label>
<br />
<input [ngClass]="{'has-success': f.submitted && username.valid, 'has-error1' : f.submitted && !username.valid}"
[(ngModel)]="asyncSelected"
[typeahead]="dataSource"
(typeaheadLoading)="changeTypeaheadLoading($event)"
(typeaheadNoResults)="changeTypeaheadNoResults($event)"
(typeaheadOnSelect)="typeaheadOnSelect($event)"
[typeaheadOptionsLimit]="2"
typeaheadOptionField="userName"
[typeaheadMinLength]="3"
placeholder="Search Users"
[disabled]="false"
class="form-controlBtn usernameBtn" type="text" name="username" autocomplete="off" #username="ngModel" required >
<div *ngIf="typeaheadLoading===true" style="margin-left:174px;">Loading</div>
<div *ngIf="typeaheadNoResults===true" style="margin-left:174px;">❌ No Results Found</div>
<span *ngIf="f.submitted" class="glyphicon form-control-feedback" [ngClass]="{'glyphicon-ok ':username.valid, 'glyphicon-remove' : !username.valid}"></span>
<br />
<span *ngIf="f.submitted && !username.valid" class="errorMessageText">
User Name Required!
</span>
<!--</div>-->
</div>
<div>
<div>
<button type="submit" class="btn-primary">Add User</button>
</div>
</div>
<div class="clearfix"></div>
</form>
</div>
</div>
Below is ts file.
import { FormsModule, NgForm } from "#angular/forms";
#Component({
selector: 'onboard-editor',
templateUrl: './onboard-editor.component.html',
styleUrls: ['./onboard-editor.component.css']
})
export class OnBoardEditorComponent implements OnInit {
ngOnInit() {
this.loadUsers();
this.loadingIndicator = true;
let gT = (key: string) => this.translationService.getTranslation(key);
this.columns = [
{ prop: "index", name: '#', width: 30, headerTemplate: this.statusHeaderTemplate, cellTemplate: this.statusTemplate, resizeable: false, canAutoResize: false, sortable: false, draggable: false },
{ prop: 'username', name: 'User Name', cellTemplate: this.nameTemplate, width: 200 },
{ prop: 'emailaddress', name: 'Email Address', cellTemplate: this.nameTemplate, width: 200 },
{ prop: 'isallowed', name: 'Allow/Deny', cellTemplate: this.toggleAllowDenyTemplate, width: 200 },
{ name: '', width: 80, cellTemplate: this.actionsTemplate, resizeable: false, canAutoResize: false, sortable: false, draggable: false }
];
}
close() {
this._isClose = true;
}
In the .Ts file i have around 500 lines of code. But I have not added all code here.
On close() I want to reset the form controls. Can someone help me to fix? Thanks

Related

Need help getting Nuxt 3 form to post emails to my Strapi 4 Subscriber collection

I have the following code but it does not post to my Subscriber collection. When I put in an email address it does not post to my subscriber collection type. Also it does not console.log
Using Nuxt3/Strapi4
<template>
<div class="relative flex justify-center w-full h-64 pb-16 mt-14 subscribe-bg">
<Container>
<div class="w-full mx-auto lg:w-3/6">
<div class="px-10 -mt-12 text-center bg-white rounded-lg shadow-xl py-9 subscribe-box">
<Heading tag="h3" font-style="h3">Subscribe</Heading>
<Heading tag="h2" font-style="h2">Never miss a planner</Heading>
<p
class="w-full px-2 mx-auto text-center pb-7 text-brand-grey-400"
>Subscribe to receice the worlds most cutting edge planner news direct to your inbox. Our newsletter is on fire.</p>
<div class="flex items-center">
<form #submit.prevent="handleSuscribe">
<input-field
id="email"
v-model="email.email"
type="email"
name="email"
placeholder="Your email"
class="w-3/4 mr-8"
/>
<Btn class="h-full" type="submit">Subscribe</Btn>
</form>
</div>
</div>
</div>
</Container>
</div>
</template>
<script setup>
import { useToast } from 'vue-toastification';
const toast = useToast();
const email = ref({ email: "" })
const handleSuscribe = async () => {
await $fetch("http://localhost:1337/api/subscribers", {
method: "POST",
body: {
data: {
email: email.value,
}
}
})
console.log(email.value)
console.log(handleSuscribe)
}
</script>
Tried to convert from the following code from Nuxt 2. It looked pretty simple at first but now I am running into issues.
<template>
<div
class="sm:flex mx-auto items-center m-10 justify-center space-x-6 sm:space-x-20 m-3 sm:m-6 mx-6"
>
<div>
<h1 class="text-lg m-7">Sign Up For NewsLetter</h1>
</div>
<div>
<form #submit="handleSuscribe">
<input
id=""
v-model="email"
class="p-2 m-3 sm:m-0 border border-solid border-t-0 border-l-0 border-r-0 border-b-1 outline-none border-black"
type="email"
name=""
placeholder="email"
/>
<button type="submit" class="button--grey">Subscribe</button>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'NewsLetter',
data() {
return {
email: '',
}
},
methods: {
async handleSuscribe(e) {
e.preventDefault()
this.$swal({
title: 'Successful!',
text: 'Thanks for Subscribing',
icon: 'success',
button: 'Ok',
})
await this.$strapi.$subscribers.create({ Email: this.email })
this.email = '' // clear email input
},
},
}
</script>

Can't type in HTML form text/password/number input field (website with Unity WebGL build)

We are developing a site using Angular 9.
We have also integrated a Unity3D WebGL build in it.
When I try to type something in a text/password/number input field inside one of my forms, it doesn't write anything and the field doesn't seem to receive the input; also, the variable I bound the field to is not updated with the new value.
What makes it weirder is that:
I can select the input field (it gets highlighted as if I can start typing)
I can do CTRL+C on the field and what I copied somewhere else is pasted, as expected
I can use the type="number" arrow selectors to set the value of the field
I cannot type from the keyboard in the fields
I can interact as expected with other form tags, such as <select>
If I reload the page, it usually starts working as expected and I can type into the fields
Here is the code from my login form (component.ts above, template HTML below)
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../auth.service'
import { first } from 'rxjs/operators';
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.less']
})
export class LoginComponent implements OnInit {
email: string = "";
password: string = "";
returnUrl: string = "home";
constructor(private router: Router, private route: ActivatedRoute, private authService: AuthService) { }
ngOnInit(): void {
let tmpReturnUrl = this.route.snapshot.queryParams["returnUrl"];
if (tmpReturnUrl != undefined)
{
console.log("true");
this.returnUrl = tmpReturnUrl;
}
else
console.log("false");
setInterval(() => {
console.log("EMAIL: " + this.email);
}, 1000);
}
onSubmit(){
this.authService.login(this.email, this.password)
.pipe(first())
.subscribe(
result => {
console.log("CAIOAOAOAOOA");
this.router.navigate([this.returnUrl]);
},
err => console.log(err)
);
}
}
<div class="card z-depth-5 w-50">
<div class="card-body">
<div class="card-title">Log in</div>
<div class="card-text">
<form #companyLoginForm="ngForm" (ngSubmit)="onSubmit()">
<mat-form-field>
<mat-label>Email: </mat-label>
<input matInput required type="text" name="email" id="email" [(ngModel)]="email">
</mat-form-field>
<mat-form-field>
<mat-label>Password: </mat-label>
<input matInput required type="password" name="password" id="password" [(ngModel)]="password">
</mat-form-field>
<button type="submit" [disabled]="!companyLoginForm.form.valid">Login</button>
</form>
<a routerLink="/company-register">
<button mdbBtn type="button" color="primary" class="relative waves-light">Sign Up</button>
</a>
</div>
</div>
</div>
And here, the code from another form where I also use type="number" and <select> (component.ts above, template HTML below)
import { Component, OnInit, Output } from '#angular/core';
import { BlockFormService } from '../block-form.service';
import { BlockData } from '../blockCardData';
import { BlockUtilsService } from '../block-utils.service';
import { ApiService } from '../../core/api.service'
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-block-form',
templateUrl: './block-form.component.html',
styleUrls: ['./block-form.component.less']
})
export class BlockFormComponent implements OnInit {
updateComplete : Boolean = false;
materials : string[];
products : string[];
varieties : string[];
nations : string[];
// companies : {name: string, id: string}[] = [];
company : string = "";
colors : string[] = ["White", "Grey", "Black", "Brown", "Red", "Green", "Yellow", "Blue"];
blockData : BlockData = {_id : "", blockId: "", company: "", material: "", product: "",
variety: "", color: "", nation: "", modelName : "", imagePreview : "",
price: null, blockNumber: "",
length: null, height: null, width: null,
weight: null
};
imagePreview: File = null;
zipFile: File = null;
invalidUpload: boolean = false;
constructor( private blockFormService: BlockFormService, public blockUtils: BlockUtilsService, private companiesUtils: ApiService )
{ }
ngOnInit(): void {
this.materials = this.blockUtils.getMaterials();
this.colors = this.blockUtils.getColors();
this.companiesUtils.getLoggedCompany().subscribe(companiesResult => {
this.blockData.company = companiesResult._id;
this.company = companiesResult.name;
});
}
onImageSelected(event){
console.log(event.target.files[0]);
if (event.target.files[0].type === "image/png")
{
if (this.invalidUpload)
this.invalidUpload = false;
this.imagePreview = event.target.files[0];
}
else{
if (!this.invalidUpload)
this.invalidUpload = true;
event.target.value = null;
}
}
onMaterialSet(newMaterial): void{
console.log("Material set");
this.products = this.blockUtils.getProducts(newMaterial);
//console.log(this.products);
// if (this.products.length > 0)
// this.blockData.product = this.products[0];
// else
this.blockData.product = "";
this.onProductSet(this.blockData.product);
}
onProductSet(newProduct): void{
console.log("Product set");
this.varieties = this.blockUtils.getVarieties(this.blockData.material, newProduct);
// if (this.varieties.length > 0)
// this.blockData.variety = this.varieties[0];
// else
this.blockData.variety = "";
this.nations = this.blockUtils.getNations(this.blockData.material, this.blockData.product);
if (this.nations.length > 0)
this.blockData.nation = this.nations[0];
else
this.blockData.nation = "";
this.onVarietySet(this.blockData.variety);
}
onVarietySet(newVariety): void{
console.log("Variety set");
// this.nations = this.blockUtils.getNations(this.blockData.material, this.blockData.product);
// if (this.nations.length > 0)
// this.blockData.nation = this.nations[0];
// else
// this.blockData.nation = "";
}
onSubmit(blockForm : NgForm, imageField, zipField): void{
this.blockFormService.sendBlock(this.blockData, this.imagePreview, this.zipFile)
.subscribe(res => {
console.log("Sent!");
this.updateComplete = true;
});
this.blockData = {
_id: "", blockId: "", company: "", material: "", product: "",
variety: "", color: "", nation: "", modelName: "", imagePreview: "",
price: null, blockNumber: "",
length: null, height: null, width: null,
weight: null
};
blockForm.resetForm();
imageField.value = null;
zipField.value = null;
this.imagePreview = null;
this.zipFile = null;
}
}
<div class="form-group">
<div class="text-center" *ngIf='updateComplete'>
Block added successfuly
</div>
<form #blockForm="ngForm" (ngSubmit)="onSubmit(blockForm, imageField, zipField)">
<div class="container">
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>Company: </mat-label>
<!-- <mat-select required [(ngModel)]="blockData.company" name="company-field"
id="company-field">
<mat-option selected [value]="company.id">{{company.name}}</mat-option>
</mat-select> -->
<input matInput disabled [value]="company" type="text" name="company-field" id="company-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Material: </mat-label>
<mat-select #matField required [(ngModel)]="blockData.material" name="kind-field"
id="kind-field" (selectionChange)="onMaterialSet(blockData.material)">
<mat-option *ngFor="let mat of materials" [value]="mat">{{mat}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Product: </mat-label>
<mat-select required [(ngModel)]="blockData.product" name="product-field"
id="product-field" (selectionChange)="onProductSet(blockData.product)">
<mat-option *ngFor="let prod of products" [value]="prod">{{prod}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Block Number: </mat-label>
<input matInput required [(ngModel)]="blockData.blockNumber" type="text" name="blockNumber-field" id="blockNumber-field">
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>Variety: </mat-label>
<mat-select required [(ngModel)]="blockData.variety" name="variety-field" id="variety-field"
placeholder="Variety" (selectionChange)="onVarietySet(blockData.variety)">
<mat-option *ngFor="let variety of varieties" [value]="variety">{{variety}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-3">
<!-- <label for="color-field">Color: </label> -->
<mat-form-field>
<mat-label>Color: </mat-label>
<mat-select required [(ngModel)]="blockData.color" name="color-field" id="color-field" placeholder="Color">
<mat-option *ngFor="let col of colors" [value]="col">{{col}}</mat-option>
</mat-select>
</mat-form-field>
<!-- <input #colField required [(ngModel)]="blockData.color" type="text" name="color-field" id="color-field" placeholder="Color"> -->
<!-- <color-circle #colorField [colors]='["#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#607d8b"]' name="color-field" id="color-field" (onChange)="blockData.color = $event.color.hex"></color-circle> -->
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Nation: </mat-label>
<!-- <mat-select required [(ngModel)]="blockData.nation" name="nation-field"
id="nation-field">
<mat-option *ngFor="let nat of nations" [value]="nat">{{nat}}</mat-option>
</mat-select> -->
<input matInput disabled [(ngModel)]="blockData.nation" type="text" name="nation-field" id="nation-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Price: </mat-label>
<input matInput required [(ngModel)]="blockData.price" type="number" name="price-field" id="price-field">
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<mat-form-field>
<mat-label>Length: </mat-label>
<input matInput required [(ngModel)]="blockData.length" type="number" name="length-field" id="length-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Width: </mat-label>
<input matInput required [(ngModel)]="blockData.width" type="number" name="width-field" id="width-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Height: </mat-label>
<input matInput required [(ngModel)]="blockData.height" type="number" name="height-field" id="height-field">
</mat-form-field>
</div>
<div class="col-3">
<mat-form-field>
<mat-label>Weight: </mat-label>
<input matInput required [(ngModel)]="blockData.weight" type="number" name="weight-field" id="weight-field">
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-3">
<div class="file-field">
<div class="btn btn-primary btn-sm float-left">
<label for="image-field">Upload preview image: </label>
<input #imageField (change)="onImageSelected($event)" name="image-field" id="image-field" type="file" accept=".png, image/png" placeholder="Upload your file">
</div>
</div>
</div>
<div class="col-3">
<div class="file-field">
<div class="btn btn-primary btn-sm float-left">
<label for="zip-field">Upload models' zip: </label>
<input #zipField (change)="zipFile = $event.target.files[0];" name="zip-field" id="zip-field" type="file" placeholder="Upload your file">
</div>
</div>
</div>
</div>
<button type="submit" [disabled]="!blockForm.form.valid || imagePreview == null || zipFile == null || blockData.company === ''">Submit</button>
</div>
</form>
</div>
I hope I was clear enough, any help is appreciated :)
Finally I found the source of the problem. In our website we have integrated a Unity3D WebGL build and, if I moved from the web page with Unity to the login page, the Unity process was still running. Unity had the focus of every input of the keyboard, so it was catching all the inputs.
We resolved it by quitting the Unity application when we change page. This way, input fields can receive inputs from the keyboard again.
Another solution, maybe (I have not tested it), could be to not make Unity get the inputs, as discussed in this Unity forum's thread or by setting WebGLInput.captureAllKeyboardInput to false.

Semantic UI Custom Rule Validation for Select Drop-Down Field

I am trying to add some custom logic to my semantic ui validation but can't figure out what I am doing wrong.
Basically, when the user selects "Yes" from the drop-down, I would like to make the "input_field" mandatory. If the user selects "No", the "input_field" becomes optional and the form can be submitted.
I tried searching for examples and followed some code from the Semantic Ui website but can't figure out what I am missing. Any advice would be appreciated as I am on a deadline for a project I am working on.
Form:
<div class="ui dimmer">
<div class="ui huge text loader">Loading</div>
</div>
<form method="post" action="" class="ui form" autocomplete="on">
<div class="ui segment">
<div class="ui two fields">
<div class='field'>
<div class="ui selection dropdown">
<input type="hidden" class="selectOption" name="select">
<i class="dropdown icon"></i>
<div class="default text">Select an option</div>
<div class="menu">
<div class="item" data-value="Yes">Yes</div>
<div class="item" data-value="No">No</div>
</div>
</div>
</div>
<div class="field">
<input id="input_field" name="input_field" type="text"/>
</div>
</div>
</div>
<button id="submit" class="ui green button" name="submit" type="submit">Submit</button>
</form>
Validation:
<script>
$('.ui.form').form({
keyboardShortcuts: false,
on: 'blur',
inline: 'true',
fields: {
selectOption: {
identifier: 'select',
rules: [
{
type: 'empty',
prompt: 'Please select an option'
}]
},
input_field: {
identifier: 'input_field',
depends: 'select',
rules: [
{
type: 'empty',
prompt: function() {
$('.select').on('change', function() {
if( this.value == 'Yes') {
return "Custom Validation";
}
return false;
}).trigger("change");
}
}]
}
},
onSuccess: function() {
$('.ui.dimmer').dimmer('show');
},
onFailure: function() {
event.preventDefault();
}
}
);
});
</script>
Figured out a solution for this! It might not be the best answer but it works and does what I am looking for.
<div class="ui dimmer">
<div class="ui huge text loader">Loading</div>
</div>
<form method="post" action="" class="ui form" autocomplete="on">
<div class="ui segment">
<div class="ui two fields">
<div class='field'>
<div class="ui selection dropdown">
<input type="hidden" class="selectOption" name="select">
<i class="dropdown icon"></i>
<div class="default text">Select an option</div>
<div class="menu">
<div class="item" data-value="Yes">Yes</div>
<div class="item" data-value="No">No</div>
</div>
</div>
</div>
<div class="field">
<input id="input_field" name="input_field" type="text"/>
</div>
</div>
</div>
<button id="submit" class="ui green button" name="submit" type="submit">Submit</button>
</form>
<script>
$('.ui.form').form({
keyboardShortcuts: false,
on: 'blur',
inline: 'true',
fields: {
selectOption: {
identifier: 'select',
rules: [
{
type: 'empty',
prompt: 'Please select an option'
}]
}
},
onSuccess: function() {
$('.ui.dimmer').dimmer('show');
},
onFailure: function() {
event.preventDefault();
}
}
);
$('.selectOption').on('change', function() {
if ( this.value == 'Yes' ) {
$('.ui.form').form('add rule', 'input_field', ['empty', 'integer']);
$('.ui.form').form('add prompt', 'input_field', 'Enter an integer');
}
if ( this.value == 'No' ) {
$('.ui.form').form('remove prompt', 'input_field');
$('.ui.form').form('remove rule', 'input_field');
}
}).trigger("change");
});
</script>
I was able to implement the validation rule by extending Semantic UI setting rules.
See below example:
$.fn.form.settings.rules.dependsOnFieldValue = function (value, dependFieldValue) {
var identifier = dependFieldValue.split('[')[0];
var dependValue = dependFieldValue.match(/\[(.*)\]/i)[1];
if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
matchingValue = $('[data-validate="'+ identifier +'"]').val();
}
else if($('#' + identifier).length > 0) {
matchingValue = $('#' + identifier).val();
}
else if($('[name="' + identifier +'"]').length > 0) {
matchingValue = $('[name="' + identifier + '"]').val();
}
else if( $('[name="' + identifier +'[]"]').length > 0 ) {
matchingValue = $('[name="' + identifier +'[]"]');
}
return (matchingValue !== undefined)
? !( dependValue.toString() === matchingValue.toString() && value === '')
: false
;
};
Then in the form validation initializer you will pass the desired values as below:
$(".ui.form").form({
fields: {
select: {
identifier: 'select',
rules : [
{
type : 'empty'
}
]
},
input_field: {
identifier : 'input_field',
rules : [
{
type : 'dependsOnFieldValue[select[Yes]]',
}
]
},
...
}
});
Notice that we pass the <select> identifier (in this case also called select) within the first [] and then the value that we want to see to make the input_field mandatory ("Yes" in this case).

How to enable required validation in vuelidate based on onChange event of select field

I have to enable required validation for the input field based on the onChange event of select field. I'm using vuelidate package for form validation in my project. Kindly provide solution to accomplish it.
My Template Code Below:
<template>
<section class="page_blk">
<form #submit="submitForm($event)" class="cryp_form">
<div class="input_ctrl_wrp">
<label for="username">Template</label>
<div class="input_select">
<select #change="getTemplate" v-model="$v.adForm.tnc.$model" name="" id="">
<option value="">Select</option>
<option value="New">New</option>
<option :value="term.idTnCTemplate"
v-for="term in termsList"
:key="term.idTnCTemplate">{{term.title}}</option>
</select>
<i class="fal fa-angle-down"></i>
</div>
</div>
<div class="input_ctrl_wrp">
<label for="username">Title</label>
<div class="input_text">
<input v-model="$v.adForm.title.$model" placeholder="" type="text">
</div>
</div>
<div class="input_ctrl_wrp">
<label for="username">Terms Of Trade</label>
<div class="input_textarea">
<textarea v-model="$v.adForm.content.$model" name="" rows="10"></textarea>
</div>
</div>
</form>
</section>
</template>
My Script Below:
<script>
import { required,requiredIf, decimal, numeric } from "vuelidate/lib/validators";
export default {
data() {
return {
adForm: {
tnc: '',
title: '',
content: '',
}
}
},
validations: {
adForm: {
tnc: {
required
},
title: {
required
},
content: {
required: requiredIf( (abc) => {
console.log('abc',abc)
return true;
})
},
schedule: {
required
}
}
},
methods: {
submitForm(e) {
},
getTemplate(e) {
}
},
mounted() {
}
}
</script>
I want to toggle the validation to required for the title and content field, if the user select new and other option from dropdown. Please provide solution to accomplish it. Thanks in advance.

Form reset issue after get response via API in react js

I am submitting form via redux API call and getting response but on success response I am trying to reset form but that giving issue -
setState(...): Cannot update during an existing state transition (such as withinrenderor another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to 'componentWillMount'.
here is my from file -
=========================
import React from 'react';
import DefaultLayout from '../Layout/DefaultLayout';
//import $ from 'jquery';
import { connect } from 'react-redux';
import { contactRequest } from '../actions/signupActions';
import { bindActionCreators } from 'redux';
import validator from 'validator';
class Contactus extends React.Component {
constructor(props){
super(props);
document.title = "Contact Us";
this.errorMapping = {"100": "Your message has been submitted.",
"102": "Name cannot be empty.",
"104": "Email cannot be empty.",
"103": "Hotel cannot be empty.",
"105": "Incorrect email format.",
"106": "Phone cannot be empty."}
this.state = {name: '',email:'',message :''};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.baseState = this.state
}
handleInputChange(event) {
this.setState({ [event.target.name]: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.contactRequest(this.state);
}
render(){
const style_1 = {height: '240px'};
const style_2 = {marginRight: '15px'};
const style_3 = {width: 'auto'};
return(
<DefaultLayout>
<section id="content">
<div className="content-wrap">
<div className="container clearfix">
<div className="col-md-6 bottommargin">
<section id="google-map" className="gmap" style={style_1} ></section>
</div>
<div className="col-md-6">
Click here to Send an Email
Send an Email
<div className="modal fade" id="contactFormModal" tabIndex="-1" role="dialog" aria-labelledby="contactFormModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-body">
<div className="contact-widget">
<div className="contact-form-result">
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
return <span key={idx} id="succ_msg">{this.errorMapping[msg]}</span>
} else {
return <span key={idx} id="err_msg">{this.errorMapping[msg]}</span>
}
})
}
</div>
<form className="nobottommargin" id="r_contactform" name="r_contactform" method="post" onSubmit={this.handleSubmit} ref={(el) => this.myFormRef = el} >
<div className="form-process"></div>
<div className="col_half">
<label htmlFor="template-contactform-name">Name <small>*</small></label>
<input type="text" id="template-contactform-name" name="name" value={this.state.name} className="sm-form-control required" onChange={this.handleInputChange} />
</div>
<div className="col_half col_last">
<label htmlFor="template-contactform-email">Email <small>*</small></label>
<input type="email" id="template-contactform-email" name="email" value={this.state.email} className="required email sm-form-control" onChange={this.handleInputChange} />
</div>
<div className="clear"></div>
<div className="clear"></div>
<div className="col_half">
<label htmlFor="template-contactform-message">Message <small>*</small></label>
<textarea className="required sm-form-control" id="template-contactform-message" name="message" value={this.state.message} rows="6" cols="30" onChange={this.handleInputChange}></textarea>
<span className={this.state.messageError ? 'help-block error': '' }>{ this.state.messageError ? this.state.messageError: '' }</span>
</div>
<div className="col_full">
<button className="button button-3d nomargin" type="submit" id="contactform-submit" name="contactform-submit">Send Message</button>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</DefaultLayout>
);
}
}
function mapStateToProps(state){
console.log("View data :"+JSON.stringify(state.Contactdata));
return {
resultMessage: state.Contactdata
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({contactRequest: contactRequest}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps) (Contactus);
getting response in mapStateToProps function and trying to update state where I have applied condition if(msg === 100) .
Please let me know where I am doing wrong.
thanks
The right place to setState is not in the map function, since you are receiving props from redux, you can do it in the componentWillReceiveProps fucntion
class Contactus extends React.Component {
constructor(props){
super(props);
document.title = "Contact Us";
this.errorMapping = {"100": "Your message has been submitted.",
"102": "Name cannot be empty.",
"104": "Email cannot be empty.",
"103": "Hotel cannot be empty.",
"105": "Incorrect email format.",
"106": "Phone cannot be empty."}
this.state = {name: '',email:'',message :''};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.baseState = this.state
}
componentWillReceiveProps(nextProps) {
nextProps.resultMessage.status.forEach((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
}
}
}
handleInputChange(event) {
this.setState({ [event.target.name]: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.contactRequest(this.state);
}
render(){
const style_1 = {height: '240px'};
const style_2 = {marginRight: '15px'};
const style_3 = {width: 'auto'};
return(
<DefaultLayout>
<section id="content">
<div className="content-wrap">
<div className="container clearfix">
<div className="col-md-6 bottommargin">
<section id="google-map" className="gmap" style={style_1} ></section>
</div>
<div className="col-md-6">
Click here to Send an Email
Send an Email
<div className="modal fade" id="contactFormModal" tabIndex="-1" role="dialog" aria-labelledby="contactFormModalLabel" aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-body">
<div className="contact-widget">
<div className="contact-form-result">
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
return <span key={idx} id="succ_msg">{this.errorMapping[msg]}</span>
} else {
return <span key={idx} id="err_msg">{this.errorMapping[msg]}</span>
}
})
}
</div>
<form className="nobottommargin" id="r_contactform" name="r_contactform" method="post" onSubmit={this.handleSubmit} ref={(el) => this.myFormRef = el} >
<div className="form-process"></div>
<div className="col_half">
<label htmlFor="template-contactform-name">Name <small>*</small></label>
<input type="text" id="template-contactform-name" name="name" value={this.state.name} className="sm-form-control required" onChange={this.handleInputChange} />
</div>
<div className="col_half col_last">
<label htmlFor="template-contactform-email">Email <small>*</small></label>
<input type="email" id="template-contactform-email" name="email" value={this.state.email} className="required email sm-form-control" onChange={this.handleInputChange} />
</div>
<div className="clear"></div>
<div className="clear"></div>
<div className="col_half">
<label htmlFor="template-contactform-message">Message <small>*</small></label>
<textarea className="required sm-form-control" id="template-contactform-message" name="message" value={this.state.message} rows="6" cols="30" onChange={this.handleInputChange}></textarea>
<span className={this.state.messageError ? 'help-block error': '' }>{ this.state.messageError ? this.state.messageError: '' }</span>
</div>
<div className="col_full">
<button className="button button-3d nomargin" type="submit" id="contactform-submit" name="contactform-submit">Send Message</button>
</div>
</form>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</DefaultLayout>
);
}
}
This is the reason, you are doing setState inside render method:
{this.props.resultMessage && this.props.resultMessage.status.map((msg, idx) => {
if(msg === 100) {
this.setState({name : "",email : ""});
.....
When msg==100 will be true, you are doing setState, again it will trigger re-rendering, again setState ....... infinite loop.
Remove that setState it will work.
Use componentWillReceiveProps lifecycle method, and do the setState inside that.
componentWillReceiveProps(newProps) {
newProps.resultMessage.status.forEach((msg, idx) => {
if(msg === 100) {
this.setState({
name : "",
email : ""
});
}
}
}