I am migrating code from angular beta to RC5 version.
and i am facing issue with the model based forms used.
As i have to much forms already developed in angular 2 beta. its hard for me to changes model based forms to template based forms.
any help in forms migration is highly appreciated.
my existing code is like this
profile.ts
import {FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES} from '#angular/forms';
import {FormBuilder, FormGroup, FormControl, Validators} from '#angular/forms';
this.firstName = new FormControl();
this.lastName = new FormControl();
this.email = new FormControl();
this.addressLine = new FormControl();
this.postal = new FormControl();
this.postalArea = new FormControl();
this.form = builder.group({
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
addressLine: this.addressLine,
postal: this.postal,
postalArea: this.postalArea,
photo: this.photo
});
and template in profile.HTML is like follows
<form class="form-default" [formGroup]="form">
<input type="text" class="form-control" id="firstName" [(ngModel)]="model.firstName" formControlName="firstName" maxlength="200">
<input type="text" class="form-control" id="lastName" [(ngModel)]="model.lastName" formControlName="lastName" maxlength="200">
<input type="text" class="form-control" id="email" [(ngModel)]="model.username" readonly formControlName="email" maxlength="100">
</form>
I am facing following error in console.
EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in
/assets/scripts/my-profile/my-profile.html:176:66 ORIGINAL EXCEPTION:
ngModel cannot be used to register form controls with a parent formGroup directive. Try using
formGroup's partner directive "formControlName" instead. Example:
<div [formGroup]="myGroup">
<input formControlName="firstName">
</div>
In your class:
this.myGroup = new FormGroup({
firstName: new FormControl()
});
Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions:
Example:
<div [formGroup]="myGroup">
<input formControlName="firstName">
<input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
</div>
Here you can find the answer to the same problem just add:
[ngModelOptions]="{standalone: true}"
to have the both ngModel and formControl in your html you have to have a model in your component (e.g. firstName in the following example) that you bind to from your html and also you need to build a form group including your desired formControl (e.g. firstNameControl in the following example)
component:
this.firstName: string;
this.form = builder.group({
firstNameControl: this.firstName,
});
html
<form [formGroup]="form">
<input type="text" [(ngModel)]="firstName" [formControl]="form.controls.firstNameControl"></input>
</form
Related
I'm having some trouble with displaying error messages for the maxlength attribute in Angular.
Problem
Since the maxlength attribute don't allow more characters than the specified amount, I'm having trouble displaying my error message. Is there any way to turn of the default behavior (allow the user to type more characters), in order to display my error message.
Code for textarea
<textarea maxlength="10"
[(ngModel)]="title.value"
#title="ngModel"></textarea>
Code for Angular validation
<div *ngIf="title.errors && (title.dirty || title.touched)"
class="alert alert-danger">
<div [hidden]="!title.errors.maxlength">
Only 10 characters allowed.
</div>
</div>
If you want me to provide any additional information, please let me know.
you can work with Reactive forms to validate properly your form,
here is a simple example how to use reactive forms :
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
#Component({
selector: 'title-form',
template: `
<form novalidate [formGroup]="myForm">
<label>
<span>Full title</span>
<input type="text" placeholder="title.." formControlName="title">
</label>
<div*ngIf="myForm.controls['title'].touched && myForm.get('title').hasError('required')">
Name is required
</div>
<div *ngIf="myForm.controls['title'].touched && myForm.controls['title'].hasError('maxlength')">
Maximum of 10 characters
</div>
</form>
`
})
export class TitleFormComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.myForm = this.fb.group({
title: ['', [Validators.required, Validators.maxLength(10)]],
});
}
}
hope it helps u :)
You can achieve it by setting the condition directly on the length of the input. A span tag with *ngIf can show/hide the error message:
HTML
<textarea class="form-control" id="title"
type="number" name="title" [(ngModel)]="titleModel"></textarea>
<span style="color:red" *ngIf="titleModel?.length > 10">
10 max
</span>
Class:
...
titleModel = 'I have more than 10 characters'
...
DEMO
How to validate a form in angular 4 by clicking on external link (ie out side from tag). If the form is valid do some actions with form data else show validation messages. If form is valid I don't want to submit the form just need to get the form field values.
This is my answer post to another question:
The easy way is to use reactive forms, like this:
Code:
import {ReactiveForm, FormBuilder, Validators} from '#angular/form';
export class SignupFormComponent implements OnInit {
userForm: FormGroup;
firstName: string;
constructor(private _formBuilder:FormBuilder){}
ngOnInit() {
this.userForm = this._formBuilder.group({
'firstName': ['',[Validators.required,Validators.minLength(5)]]
});
}
onSubmit() {
console.log(this.firstName);
}
}
HTML:
<form [formGroup]="userForm" (ngSubmit)="onSubmit()" name="userForm">
<div class="form-group">
<label>First Name</label>
<input type="text" [(ngModel)]="firstName" class="form-control" formControlName="firstName">
<p *ngIf="userForm.controls.firstName.invalid && (userForm.controls.firstName.dirty || userForm.controls.firstName.touched)"> Error message </p>
</div>
<button type="submit" class="btn btn-primary" [disabled]="userForm.invalid">Submit </button>
</form>
Component:
ngOnInit() {
this.record = new FormGroup({
movement: new FormControl(''),
weight: new FormControl('', [Validators.required, Validators.minLength(1), Validators.maxLength(3)]),
date: new FormControl('', [Validators.required]),
comments: new FormControl('', [Validators.required, Validators.minLength(3), Validators.maxLength(25)]),
});
}
View:
<div class="column col-6">
<div class="form-group">
<label class="form-label">Weight</label>
<input formControlName="weight" class="form-input" type="text" placeholder="Weight" />
</div>
</div>
<div class="column col-6">
<div class="form-group">
<label class="form-label">Date</label>
<input formControlName="date" class="form-input" type="text" placeholder="Date" />
</div>
</div>
I've got the above validation working just fine, but I need to change the validators on weight to only accept numerical values and the validators on date to accept a specific format (##/##/####).
I've been searching forever and haven't found any built-in methods of doing this. Does anyone have any suggestions? Thanks!
There are only a small number of built-in form validation rules in Angular.
required
minLength
maxLength
pattern (which you could use for email)
EDIT:
More built in:
min
max
email
nullValidator
requiredTrue
Validators API (thank you, #developer033)
If you want to do anything beyond that, you will have to code your own. They are not difficult.
You can find an example on how to build and use a custom validator at the link below.
Custom validation
If you happen to have a Pluralsight subscription, Deborah Kurata has a great course on Angular Reactive Forms, and there is a clip or two on custom form validation in the Validation module.
I have a built a model-driven (reactive) form, as shown here, in Angular 2.
My html looks like this:
<form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value, userForm.valid)">
<label for="firstName">First Name:</label>
<input type="text" formControlName="firstname" id="firstName" required>
<label for="lastname">Last Name:</label>
<input type="text" formControlName="lastname" id="lastName" required>
<br>
<label for="email">Email:</label>
<input type="email" formControlName="email" id="email">
<br>
</form>
In my .ts file:
import { FormGroup, FormControl, FormBuilder, Validators } from '#angular/forms';
...
ngOnInit() {
this.paymentForm = this.formBuilder.group({
firstname: ['', Validators.required],
lastname: ['', Validators.required],
email: ['',],
})
this.userForm.valueChanges.subscribe(value => {
console.log(value);
});
}
I've added the required attribute in my template as well, as suggested by angular docs
Quoting:
required remains, not for validation purposes (we'll cover that in the code), but rather for css styling and accessibility.
What I want is to cycle through each form field and add a * to the associated label if the field is required.
So, First Name reads First Name *; and so on.
How would I go about doing that. Thanks.
#Directive({
selector: '[required]'
})
export class LabelRequiredDirective {
constructor(private elRef:ElementRef){}
ngAfterContentInit() {
this.elRef.nativeElement.labels.forEach(l => l.textContent += ' *');
}
}
Because the selector matches every element that has the required attribute, it is applied to all elements where the label should be updated.
Sadly nativeElement.labels is only supported in Chrome. For other browsers another strategy is necessary to get the label associated with an input element (See also Find html label associated with a given input)
I am starting with angular2. I have a simple template driven form and I can access the data in console. But I am having problem with passing the data. Here is my code.
import {Component} from "angular2/core";
#Component({
selector: 'my-template-driven',
template:`
<h2>Sign-up form</h2>
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<div>
<label for="email">Mail</label>
<input ngControl="email" type="text" id="email" required #email="ngForm">
<span class="validation-error" *ngIf="!email.valid">Not Valid</span>
</div>
<div>
<label for="password">Password</label>
<input ngControl="password" type="text" id="password" required #password="ngForm">
<span class="validation-error" *ngIf="!password.valid">Not Valid</span>
</div>
<div>
<label for="confirm-password">Confirm Password</label>
<input ngControl="confirm-password" type="text" id="confirm-password" required #passwordConfirm="ngForm">
<span class="validation-error" *ngIf="!passwordConfirm.valid">Not Valid</span>
</div>
<button type="submit" [disabled]="!f.valid || password.value !== passwordConfirm.value">Submit</button>
</form>
<h2>You Submitted</h2>
`
})
export class TemplateDrivenFormComponent {
user: {email: '', password: ''};
onSubmit(form){
//console.log(form);
this.user.email = form.value['email'];
//this.user.password = form.controls['password'].value;
}
}
I am getting this angular2.js:23941 ORIGINAL EXCEPTION: TypeError: Cannot set property 'email' of undefined error constantly. How can I access the data of the form submitted.
You don't declare your local correctly, and you must initialize it when you declare it, or in your constructor maybe
user: any;
constructor() {
this.user = {email: "", password: ""} as any;
}
after : you must provide the type.
Html input must have "ngModel" attribute in it.