I have a form, which is getting validated once the control gets the class change from ng-untouched ng-pristine ng-invalid to ng-pristine ng-invalid ng-touched but if i have a form with more controls then i want the user to know which field he/she has missed out on the button submit. how can i do that using angularJS2. I have used ReactiveFormsModule to validate the controls
The following is my code: component
import { Component } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'page',
templateUrl:'../app/template.html'
})
export class AppComponent {
registrationForm: FormGroup;
constructor(private fb: FormBuilder) {
this.registrationForm = fb.group({
username: ['', [Validators.required, Validators.minLength(4)]],
emailId: ['', [Validators.required, this.emailValidator]],
phonenumber: ['', [Validators.required, this.phoneValidation]]
})
}
emailValidator(control: FormControl): { [key: string]: any } {
var emailRegexp = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+#[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
if (control.value && !emailRegexp.test(control.value)) {
return { invalidEmail: true };
}
}
phoneValidation(control: FormControl) {
if (control['touched'] && control['_value'] != '') {
if (!/^[1-9][0-9]{10}$/.test(control['_value'])) {
return { 'invalidPhone': true }
}
}
}
}
The following is my code: module
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { ReactiveFormsModule } from '#angular/forms';
import { AppComponent } from '../app/component';
#NgModule({
imports: [BrowserModule, ReactiveFormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
The following is my code: template
<form [formGroup]="registrationForm" (ngSubmit)="registrationForm.valid && submitRegistration(registrationForm.value)">
<input type="text" formControlName="username" placeholder="username" />
<div class='form-text error' *ngIf="registrationForm.controls.username.touched">
<div *ngIf="registrationForm.controls.username.hasError('required')">Username is required.</div>
</div>
<br />
<input type="text" formControlName="emailId" placeholder="emailId" />
<div class='form-text error' *ngIf="registrationForm.controls.emailId.touched">
<div *ngIf="registrationForm.controls.emailId.hasError('required')">email id is required.</div>
<div *ngIf="registrationForm.controls.emailId.hasError('invalidEmail')">
Email is not in correct format.
</div>
</div>
<br />
<input type="text" formControlName="phonenumber" placeholder="phonenumber" />
<div class='form-text error' *ngIf="registrationForm.controls.phonenumber.touched">
<div *ngIf="registrationForm.controls.phonenumber.hasError('required')">phone number is required.</div>
<div *ngIf="registrationForm.controls.phonenumber.hasError('invalidPhone')">Invalid phone number.</div>
</div>
<br />
<input type="submit" value="Submit" />
</form>
I thought of updating all the invalid controls class to ng-untouched ng-pristine ng-invalid but not sure if this is the right approach
Angular forms don't provide ways to specify when to do validation.
Just set a flag to true when the form is submitted and show validation warnings only when the flag is true using *ngIf="flag" or similar.
<form [formGroup]="registrationForm" (ngSubmit)="submitRegistration(registrationForm.value)">
<div *ngIf="showValidation> validation errors here </div>
showValidation:boolean = false;
submitRegistration() {
if(this.registrationForm.status == 'VALID') {
this.processForm();
} else {
this.showValidation = true;
}
}
Related
I am trying to validate the user field with letters only.
Following the documentation at https://angular.io/api/forms/Validators#pattern
I am not getting the expected result.
Validator.required works.
Validator.minLength works.
But the pattern does not.
I need the user field to have only letters.
Already looked for similar issues here in the forum and tried some implementations but it is not working.
I also tried to add direct into the html tag [pattern]='onlyLetters' and also didn't work.
html
<form (ngSubmit)="onSubmitNewUser()" [formGroup]="userFormGroup" >
<mat-card>
<mat-card-title fxLayoutAlign="center">{{'USERS.NEW'|translate}}</mat-card-title>
<mat-card-content fxLayoutAlign="left" fxLayout="column">
<mat-form-field fxFlex="100%">
<mat-label>{{'USERS.GROUP'|translate}}</mat-label>
<mat-select formControlName="group" >
<mat-option *ngFor="let group of groups" value="{{ group.users_group_id }}">{{ group.users_group_name }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="100%">
<input
[pattern]="pattern"
placeholder="{{'USERS.USERNAME'|translate}}"
type="text"
formControlName="username"
matInput />
<mat-error *ngIf="formControlUsername.hasError('required')" >
{{'VALIDATION.REQUIRED'|translate}}
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="250px" hintLabel="{{'VALIDATION.PASSWORD_HINT'|translate}}">
<input
type="password"
placeholder="{{'USERS.PASSWORD'|translate}}"
matInput
formControlName="password"/>
<mat-hint align="end"> {{ formControlPassword.value?.length }} / 6 </mat-hint>
<mat-error>{{'VALIDATION.MIN_LENGTH'|translate}}</mat-error>
</mat-form-field>
</mat-card-content>
<mat-card-actions fxLayoutAlign="left">
<button
type="submit"
color="primary"
mat-raised-button
[disabled]="userFormGroup.invalid">{{'SAVE'|translate}}</button>
</mat-card-actions>
</mat-card>
</form>
TS file
import { Component, OnInit} from '#angular/core';
import { FormControl, FormGroup, Validators} from '#angular/forms';
import { GroupsModel} from '../_models/groups.model';
import { UsersService} from '../_services/users.service';
#Component({
selector: 'app-users-add',
templateUrl: './users-add.component.html',
styleUrls: ['./users-add.component.scss']
})
export class UsersAddComponent implements OnInit {
pattern = "[a-zA-Z]*";
formControlGroup = new FormControl('',{
validators: [Validators.required]
});
formControlUsername = new FormControl('',{
validators: [
Validators.required,
Validators.pattern(this.pattern)
]
});
formControlPassword = new FormControl('',{
validators: [
Validators.required,
Validators.minLength(6)
]
});
userFormGroup: FormGroup;
groups: GroupsModel[] = [];
constructor(private usersService: UsersService) { }
ngOnInit() {
this.userFormGroup = new FormGroup({
group: this.formControlGroup,
username: this.formControlUsername,
password: this.formControlPassword
});
this.usersService.getGroups().subscribe( data => {
this.groups = data
});
}
onSubmitNewUser() {
console.log(this.userFormGroup.value);
}
}
I'm trying to build a filter pipe in Angular 6, but it's not working properly.
.html
<form>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" name="searchString" placeholder="Type to search..." [(ngModel)]="searchString">
</div>
</div>
</form>
<table class="table">
<tr *ngFor="let user of users | filter2 : searchString">
{{user.name}}
</tr>
</table>
pipe
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter2'
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string): any[] {
if (!items) return [];
if (!searchText) return items;
searchText = searchText.toLowerCase();
return items.filter(it => {
return it.toLowerCase().includes(searchText);
});
}
}
I get this error when I write inside input:
ERROR TypeError: it.toLowerCase is not a function
What am I doing wrong? Thank you for your time!
users
You can try it.name.toString().toLowerCase().includes(searchText);
Component
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
users:any[];
constructor(){
this.users = [
{name:"John"},
{name:"Tom"},
{name:"Carlton"},
{name:"Judy"},
{name:"Ada"}
];
}
}
Html
<form>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" name="searchString" placeholder="Type to search..." [(ngModel)]="searchString">
</div>
</div>
</form>
<table class="table">
<tr *ngFor="let user of users | filter2 : searchString">
{{user.name}}
</tr>
</table>
Pipe
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter2'
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string): any[] {
if (!items) return [];
if (!searchText) return items;
searchText = searchText.toLowerCase();
return items.filter(it => {
return it.name.toLowerCase().includes(searchText);
});
}
}
v-for is iterating over on my fields not to the data that i selected, example i have 3 fields in my database(name,email,username) it will loop 3 times
Result
Profile.vue
<template>
<div>
<h3>Profile</h3>
<user-profile v-for="user in users" :user="user" :key="user.id"></user-profile>
</div>
</template>
<script>
import UserProfile from '../partials/UserProfile.vue'
import User from '../models/User'
import Form from '../core/Form'
export default {
components: {
UserProfile
},
data() {
return {
users: [
users:[],
],
}
},
created() {
axios.get('/user/profile').then(res => this.users = res);
}
};
</script>
UserProfile.vue
<template>
<div class="row">
<form class="col s12" method="POST" #submit.prevent="onSubmit">
<div class="input-field col s12">
<input type="text" id="name" name="name" v-model="form.name" class="validate" autofocus>
<label for="name" class="active">Name</label>
</div>
<div class="input-field col s12">
<input id="email" type="email" name="email" v-model="form.email" class="validate" autofocus>
<label for="email" class="active">Email</label>
</div>
<div class="right-align">
<button class="btn waves-effect waves-light" type="submit" name="action">Update
<i class="material-icons right">send</i>
</button>
</div>
</form>
</div>
</template>
<script>
import Form from '../core/Form'
export default {
props: ['user'],
data() {
return {
form: new Form({
name: this.user.name,
})
}
},
computed: {
//
},
mounted() {
},
methods: {
//
onSubmit() {
axios.post('/user/update', {
name: this.user.name
})
.then(console.log('yeahh'))
.catch(console.log('failed'))
}
}
};
</script>
Your users inside Data looks wrong.
Here is an edited version
Profile
<script>
import UserProfile from '../partials/UserProfile.vue'
import User from '../models/User'
import Form from '../core/Form'
export default {
components: {
UserProfile
},
data() {
return {
users: [
{
name: 'FirstName LastName',
email: 'firstname.lastname#gmail.com'
}
],
}
},
created() {
// User.all(users => this.users = users)
}
};
</script>
Since you're only returning the currently logged in user, you'll have to edit your Profile component a bit:
<template>
<div>
<h3>Profile</h3>
<user-profile :user="user" :key="user.id"></user-profile>
</div>
</template>
<script>
import UserProfile from '../partials/UserProfile.vue'
import User from '../models/User'
import Form from '../core/Form'
export default {
components: {
UserProfile
},
data() {
return {
user: {},
}
},
created() {
axios.get('/user/profile').then(res => this.user = res);
}
};
</script>
Hy guys I'm new to Angular2 and in JS frameworks in general. I'm flowing tutorials on official site and haven't been able to find the solution to this problem.
So I have checkbox which is optional but if the checkbox is "checked" a new input field is shown. this part is not a problem. The problem is that I'm using modal based validation and I can't figure out how to make this new input field required only if the checkbox is checked.
this is may implementation so far:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<!--{{form}}-->
<div formGroupName="test">
<div class="field">
<div class="checkbox">
<input type="checkbox" name="entryRecurring" value="" id="entryRecurring" formControlName="entryRecurring" />
<label for="entryRecurring">
<div class="checkbox_icon"></div>
Recurring Entry
</label>
</div>
</div>
<div *ngIf="form.value.test.entryRecurring">
<div class="field">
<label for="entryRecurringAmount">Repeat Amount</label>
<input type="text" name="entryRecurringAmount" value="" id="entryRecurringAmount" formControlName="entryRecurringAmount" />
</div>
</div>
</div>
<div class="field last">
<button name="submit" id="submit" class="btn btn_sushi" [disabled]="!form.valid">Submit</button>
</div>
import {Component, Input, OnInit, OnChanges} from '#angular/core';
import { Validators } from '#angular/common';
import { REACTIVE_FORM_DIRECTIVES, FormGroup, FormControl, FormBuilder } from '#angular/forms';
import { FormMessages } from './../helpers/formMessages.component';
import {EntriesService} from './entries.service';
import {ValidationService} from '../helpers/validation.service';
import {Category, CategoryByType} from '../../mock/mock-categories';
#Component({
selector: 'entryForm',
templateUrl: 'app/components/entries/entriesEdit.template.html',
directives: [REACTIVE_FORM_DIRECTIVES, FormMessages],
providers: [EntriesService, ValidationService]
})
export class EntriesEditComponent implements OnInit, OnChanges {
#Input() control: FormControl;
public form:FormGroup;
public submitted:boolean = false;
// private selectedId: number;
categories: Category[];
categoriesSortedByType: CategoryByType[];
constructor(
private _fb:FormBuilder,
private _entriesService: EntriesService
// private _router: Router
) {
this.form = this._fb.group({
test: this._fb.group({
entryRecurring: [''],
entryRecurringAmount: [''],
})
});
}
onSubmit() {
this.submitted = true;
// console.log(this.form.value);
if (this.form.dirty && this.form.valid) {
this._entriesService.saveEntry(this.form.value);
}
}
You could do that by using a custom validation service.
import {NgFormModel} from "angular2/common";
import {Component, Host} from 'angular2/core';
#Component({
selector : 'validation-message',
template : `
<span *ngIf="errorMessage !== null">{{errorMessage}}</span>
`,
inputs: ['controlName : field'],
})
export class ControlMessages {
controlName : string;
constructor(#Host() private _formDir : NgFormModel){
}
get errorMessage() : string {
let input = this._formDir.form.find(this.controlName);
let checkBx = this._formDir.form.find('checkBoxName');
if(input.value.trim() === '' && checkBx.checked) {
return 'The input field is now required'
}
return null;
}
}
Then use the new component like bellow
<div *ngIf="form.value.test.entryRecurring">
<div class="field">
<label for="entryRecurringAmount">Repeat Amount</label>
<input type="text" name="entryRecurringAmount" value="" id="entryRecurringAmount" ngControl="entryRecurringAmount" />
<validation-message field="entryRecurringAmount"></validation-message>
</div>
</div>
Hope that helped!
I'm having trouble again with redux-form. I'm calling the handleSubmit function from the parent, and the windows.alert() is calledcorrectly, but the data is not passed to the function. What am I doing wrong?
import React, {Component, PropTypes} from 'react';
import {reduxForm} from 'redux-form';
import memberValidation from './memberValidation';
class DashboardAdding extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
handleSubmit: PropTypes.func.isRequired,
resetForm: PropTypes.func.isRequired
}
render() {
const {
fields: { pseudo, email},
handleSubmit,
resetForm
} = this.props;
return (
<div>
<form className="form-horizontal" onSubmit={handleSubmit.bind(this)}>
<div className={'form-group' + (pseudo.error && pseudo.touched ? ' has-error' : '')}>
<label className="col-sm-2">Pseudo</label>
<div className={'col-sm-8 '}>
<input type="text" className="form-control" id="pseudo" {...pseudo}/>
{pseudo.error && pseudo.touched && <div className="text-danger">{pseudo.error}</div>}
</div>
</div>
<div className={'form-group' + (email.error && email.touched ? ' has-error' : '')}>
<label className="col-sm-2">Email</label>
<div className={'col-sm-8 '}>
<input type="text" className="form-control" id="email" {...email}/>
{email.error && email.touched && <div className="text-danger">{email.error}</div>}
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button className="btn btn-success" onClick={handleSubmit}>
<i className="fa fa-paper-plane"/> Submit
</button>
<button className="btn btn-warning" onClick={resetForm} style={{marginLeft: 15}}>
<i className="fa fa-undo"/> Reset
</button>
</div>
</div>
</form>
</div>
);
}
}
export default reduxForm({
form: 'dashboardForm',
fields: ['pseudo', 'email'],
validate: memberValidation,
asyncBlurFields: ['email']
})(DashboardAdding);
...and the parent calling the handleSubmit:
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import Helmet from 'react-helmet';
import {bindActionCreators} from 'redux';
import {initialize} from 'redux-form';
import {isLoaded, loadMembers} from 'redux/modules/members/members';
import * as addActions from 'redux/modules/members/addSingleMember';
import {addMember} from 'redux/modules/members/addSingleMember';
import { DashboardList } from 'components';
import { DashboardHeader } from 'components';
import { DashboardAdding } from 'components';
import { asyncConnect } from 'redux-async-connect';
#asyncConnect([{
deferred: true,
promise: ({store: {dispatch, getState}}) => {
if (!isLoaded(getState())) {
return dispatch(loadMembers());
}
}
}])
class Dashboard extends Component {
static propTypes = {
members: PropTypes.array,
error: PropTypes.string,
loading: PropTypes.bool,
addMember: PropTypes.func,
initialize: PropTypes.func.isRequired
}
handleSubmit = (data, dispatch) => {
window.alert(data);
dispatch(addMember(JSON.stringify(data)));
this.props.initialize('dashboardForm', {});
}
handleInitialize = () => {
this.props.initialize('dashboardForm', {
pseudo: 'Pibo',
email: 'pibirino#gmail.com'
});
}
render() {
const {members} = this.props;
return (
<div className="container">
<h1>Dashboard</h1>
<Helmet title="Dashboard"/>
<DashboardHeader />
<div>
<DashboardList members={members}/>
<h3>Ici commence le form</h3>
<div style={{textAlign: 'center', margin: 15}}>
<button className="btn btn-primary" onClick={this.handleInitialize}>
<i className="fa fa-pencil"/> Initialize Form
</button>
</div>
</div>
<DashboardAdding onSubmit={this.handleSubmit}/>
</div>
);
}
}
function mapStateToProps(state) {
return {
members: state.members.data,
error: state.members.error,
loading: state.members.loading
};
}
function matchDispatchToProps(dispatch) {
return bindActionCreators({
addActions,
addMember,
initialize: initialize
}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(Dashboard);
The redux-documentation says:
"You are upgrading from a previous version of redux-form that required that {valid: true} be returned".
I suspect that the problem is that, but I really don't understand what that could mean!
My version -> "redux-form": "^3.0.0"
Thanks!
Find the solution where I didn't expect... The form gives the data in json format. JSON.stringify() messed it up.
I hope it can help somebody. Bye