Angular Material 8 formControlName error - getting conflicting messages - html

I am attempting to work with Angular Material (8) Reactive Forms. I am working on a Registration Form. I am getting errors that seem to contradict each other.
**
When I do it this way (file: register.component.html):
**
<!-- Form -->
<form [formGroup]="registerForm" class="text-center" style="color: #757575;">
<div class="form-col">
<div class="col">
<!-- First name -->
<div class="md-form">
<input required type="text" id="materialRegisterFormFirstName" class="form-control"
mdbInput [(ngModel)]="user.firstname"/>
<label for="materialRegisterFormFirstName">First name</label>
</div>
</div>
[... snip ...]
**
I get this error:
**
ERROR Error:
ngModel cannot be used to register form controls with a parent formGroup directive. Try using
formGroup's partner directive "formControlName" instead.
So, I follow the instructions. When I use this approach (adding in formControlName="firstname"),
<div class="form-col">
<div class="col">
<!-- First name -->
<div class="md-form">
<input required type="text" id="materialRegisterFormFirstName" class="form-control"
mdbInput formControlName="firstname" [(ngModel)]="user.firstname"/>
<label for="materialRegisterFormFirstName">First name</label>
</div>
</div>
[... snip ...]
**
I get the following error:
**
forms.js:2312
It looks like you're using ngModel on the same form field as formControlName.
Support for using the ngModel input property and ngModelChange event with
reactive form directives has been deprecated in Angular v6 and will be removed
in Angular v7.
For more information on this, see our API docs here:
https://angular.io/api/forms/FormControlName#use-with-ngmodel
When looking up the problem, I come across this in an old thread:
REFERENCE: ngModel on the same form field as formControlName
From Angular 7 and onward you can't use both formControlName and ngModel together. If you want to use template-driven forms you can go with ngModel and if you want to use reactive forms you can't go with ngModel. (Simple)
**
It sounds like it is saying to remove the formControlName reference. How can this problem be resolved?
**
TIA

That is because you are using template-driven and reactive form at the same time. You need to use it one of them, you cant use both at same time.
Syntax of template driven form is as below.
.html file
<div class="row">
<div class="col-xs-12">
<form (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
name="courseName"
ngModel>
</div>
<div class="col-sm-2 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control"
name="courseDesc"
ngModel>
</div>
<div class="col-sm-2 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control"
name="courseAmount"
ngModel>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button
class="btn btn-success"
type="submit">Add</button>
<button
class="btn btn-danger"
type="button">Delete</button>
<button class="btn btn-primary" type="button">Clear</button>
</div>
</div>
</form>
</div>
</div>
.ts file
onSubmit(form: NgForm) {
console.log("Course Name is : " + form.value.courseName);
console.log("Course Desc is : " + form.value.courseDesc);
console.log("Course Amount is : " + form.value.courseAmount);
}
Syntax for Reactive Form as below
.html file.
<div class="row">
<div class="col-xs-12">
<form [formGroup]="courseForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-sm-5 form-group">
<label for="courseName">Course Name</label>
<input
type="text"
id="courseName"
class="form-control"
formControlName="courseName">
</div>
<div class="col-sm-2 form-group">
<label for="courseDesc">Course Description</label>
<input
type="text"
id="courseDesc"
class="form-control"
formControlName="courseDesc">
</div>
<div class="col-sm-2 form-group">
<label for="courseAmount">Course Amount</label>
<input
type="number"
id="courseAmount"
class="form-control"
formControlName="courseAmount">
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button
class="btn btn-success"
type="submit">Add</button>
<button
class="btn btn-danger"
type="button">Delete</button>
<button class="btn btn-primary" type="button">Clear</button>
</div>
</div>
</form>
</div>
</div>
.ts file
this.courseForm = new FormGroup({
'courseName': new FormControl(null, Validators.required),
'courseDesc': new FormControl([Validators.required, Validators.minLength(100)]),
'courseAmount': new FormControl(null)
});
for more reference visit

You Cannot use both ngModel and FormControlName or ngModel and formGroup together. Because ngModel is a template forms driven whereas FormControlName and FormGroup are reactive forms driven.
If you want to use both together you are increasing the complexity of the application. If you want to access the value through formControlName then use it like
<form [formGroup]="registerForm" class="text-center" style="color: #757575;">
<div class="form-col">
<div class="col">
<div class="md-form">
<input formControlName="firstName" type="text" id="materialRegisterFormFirstName" class="form-control" mdbInput/>
<label for="materialRegisterFormFirstName">First name</label>
</div>
</div>
</div>
</form>
In component.ts file write like
registerForm = new FormGroup({
firstName: new FormControl([Validator.required]),
});
or else you can build formgroup using formbuilder, fb is an instance of formBuilder
this.registerForm = fb.group({
'fullname': ['', Validators.required],
});
and you can read value like this
this.user.firstName = this.registerForm.get('firstName').value;

Use [ngModelOptions]="{ standalone: true }" on the input element

since you are using reactive forms , no need to use ngModelin your input fields use formControlName insted. ngModel is used in template driven froms
<div class="md-form">
<input required type="text" id="materialRegisterFormFirstName" class="form-control"
mdbInput formControlName="firstname"/>
<label for="materialRegisterFormFirstName">First name</label>
</div>
here you can find better examples https://v8.angular.io/guide/reactive-forms

Related

Jquery validation collide with HTML validation

I want to use jquery validation for simple form using built-in validation method like required and email.
Here is my form
<form id="setup-company" class="form-horizontal form-rest validator" action="{{$updatePath}}">
<div class="form-group">
<label for="name" class="col-sm-6 control-label" style="font-size: 12px;text-transform:uppercase">Nama Institusi *</label>
<div class="col-sm-12">
<input type="text" class="form-control" name="name" value="{{$company->name}}" style="width: 100%;" required>
</div>
</div>
<div class="form-group">
<label for="abbreviation" class="col-sm-6 control-label" style="font-size: 12px;text-transform:uppercase">Singkatan</label>
<div class="col-sm-12">
<input type="text" class="form-control" name="abbreviation" value="{{$company->abbreviation}}" style="width: 100%;">
</div>
</div>
<div class="form-group">
<label for="phone" class="col-sm-6 control-label" style="font-size: 12px;text-transform:uppercase">No. Telp</label>
<div class="col-sm-12">
<input type="number" class="form-control" minlength="10" maxlength="12" name="phone" value="{{$company->phone}}">
</div>
</div>
<div class="form-group">
<label for="email" class="col-sm-6 control-label" style="font-size: 12px;text-transform:uppercase">Email</label>
<div class="col-sm-12">
<input type="email" class="form-control" name="email" value="{{$company->email}}">
</div>
</div>
<button style="float:right;" type="submit" class="btn btn-sm btn-success btn-raised rippler rippler-inverse edit-row">
SIMPAN
</button>
</form>
In the javascript, I initiate jquery validation like this.
$('.form-rest').unbind().submit(function(e) {
e.preventDefault();
var $form = $(this);
// check if the input is valid
if (!$form.valid())
return false;
});
But when I try it, it shows HTML validation like this
When I fill invalid input for phone (which is third input), it seems jquery validation working properly. And when I try to fill blank input for first input, the error message came from jquery validation like this.
Whats the cause of this?
It's totally fine to have the required attribute. You just have to tell the browser that you want to skip the default validation by adding the novalidate attribute to the form element.
The novalidate attribute is a boolean attribute.
When present, it specifies that the form-data (input) should not be validated when submitted.

ngSubmit "myFunction is not a function" typescript, angular

I have an address management app, and I'm trying to save changes on ngSubmit. However, it says that my function is not a function.
my HTML:
<div class="form">
<h4>{{title}}</h4>
<div class="form-container">
<form (ngSubmit)="addFriend()">
<div class="form-group">
<label for="id">Id</label>
<input type="text" name="id" [(ngModel)]="friend.id"
[disabled]="friend.id" class="form-control" required />
</div>
<div class="form-group">
<label for="name">Name</label>
<input type="text" name="name" [(ngModel)]="friend.name"
class="form-control" required />
</div>
<div class="form-group">
<label for="address">Address</label>
<input type="text" name="address" [(ngModel)]="friend.address"
class="form-control" required />
</div>
<div class="form-group">
<label for="phone">Phone</label>
<input type="text" name="phone" [(ngModel)]="friend.phone"
class="form-control" required />
</div>
<div class="form-group">
<a class="btn btn-default" routerLink="">Cancel</a>
<button class="btn btn-primary" >Save</button>
</div>
</form>
</div>
</div>
am I doing something wrong in the html, or would the problem be elsewhere?
The addFriend function is defined in my service.ts file.
You have to define addFriend in your component ts file like
addFriend(){
//some work here
}
Your component template does not have access to your service, but only to your component class methods.
So you need to
1/ inject your service into your component
2/ define in your component a method that calls the service methods
for example in your component :
constructor(private friendsService: FriendsService) {}
....
addFriend(){
return this.friendsService.addFriend();
}

angular6 cannot set the value of ngForm from component.ts

i am developing an basic angular 6 application that fetches the data, display it in the table, each row has delete, edit button this is one component 'detail list', i have another component as 'detail component' that are having controls to add the record in the table, i am fetching the data from the webapi, adding the record and deleting the record using the same webapi, they all are working fine, now i want to edit the record from the table, i am using the same webapi to fetch the data, webapi returning the record, i want to display this record's data in the 'detail component', the same component that is used to add the record, so at the component i am calling ngAfterViewInit()
>
ngAfterViewInit() {
this.service.change.subscribe((data: Patient) => {
alert('in the detail component of ngAfterViewInit');
console.log(data);
this.ModelChange(data);
}) ;
}
and the code for the ModelChange is as follows
ModelChange(data: Patient) {
this.form.controls['PatientCode'].setValue(data.PatientCode);
}
and my html is like
<form #form="ngForm" autocomplete="on" (submit)="OnSubmit(form)">
<div class="row">
<div class="form-group">
<input name="PatientCode" [(ngModel)]="PatientCode"class="form-control" placeholder ="Patient Code" (ngModelChange)="ModelChange(event)" required>
</div>
<div class="col-md -3 form-group">
<input name="FirstName" [(ngModel)] ="FirstName" class="form-control" placeholder="First Name" required>
</div>
<div class=" col-md-5 form-group">
<input name="LastName" [(ngModel)]="LastName" class="form-control" placeholder="Last Name" required>
</div>
</div>
<div class="row">
<div class="form-group">
<input name="MRN" class="form-control" [(ngModel)]="MRN" placeholder="MRN" required>
</div>
<div class="col-md-3 form-group">
<!--<input name="DateOfBirth" class="form-control" placeholder="Date of Birth">-->
<ejs-datepicker name="DateOfBirth" [(ngModel)]="DateOfBirth" id='datepicker' placeholder='Enter Date Of Birth' [value]='value' [min]='minDate' [max]='maxDate'></ejs-datepicker>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<button type="submit" (click)="AddPatient(p)" class="btn btn-success center-block "> Add Patient</button>
</div>
<div class="col-md-13">
<button type="submit" (click)="EditPatient(p)" class="btn btn-success center-block "> Edit Patient</button>
</div>
</div>
</form>
at the console i am getting error that cannot Cannot read property 'controls' of undefined
Please help me out what is the correct way of setting the control property with the fetched data

How to show form validation messages while using [(ngModel)] in Angular 2?

I am struggling for the validation error message.
I have a form and I have used ngModel. Now I am not able to display the error messages Depending on the Pattern. I have written validation in component.ts.
Could anyone help me with the two type of messages
1. Required
2. Validation message for form which is invalid with respect to the pattern (Validation using pattern).
I searched all places for the above with no help, it would be appreciated if anyone could help me with this.
Component.html
<div class="card card-blur">
<div class="card-header">
<p>ACCOUNT INFORMATION</p>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<!-- <p>Profile Image</p>
<img src={{client.ProfileImage}} type="text" name="ProfilePic" style="width:60%"> -->
<ba-picture-uploader [picture]="client.ProfileImage" [defaultPicture]="defaultPicture" [uploaderOptions]="uploaderOptions"></ba-picture-uploader>
</div>
<div class="col-md-9">
<ul style="margin-top:20px;">
<ul style="margin-top:20px;">
<!-- <li>Take picture of id from your phone or mobile camera</li> -->
</ul>
</ul>
</div>
</div>
<form #f="ngForm" (submit)="submit()">
<fieldset>
<div class="row form-inline">
<div class="col-md-6">
<div class="col-md-3"></div>
<div class="col-md-9"></div>
</div>
<div class="col-md-6">
<!-- <div class="form-group" style="margin-left: 16em; margin-top: -5em"> -->
<div class="form-group" style=" margin-top: -3.5em">
<div class="col-md-3">
<label for="organization">Organization</label>
</div>
<div class="col-md-9">
<input [(ngModel)]="client.Organization" type="text" name="Organization" class="form-control" id="organization"
placeholder="Organization">
</div>
</div>
</div>
</div>
<div class="row form-inline">
<div class="col-md-6">
<div class="form-group">
<div class="col-md-3">
<label for="fname">First Name</label>
</div>
<div class="col-md-9">
<input [(ngModel)]="client.ClientFirstName" type="text" name="FirstName" class="form-control" id="fname"
placeholder="First Name">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="col-md-3">
<label for="lname">Last Name</label>
</div>
<div class="col-md-9">
<input [(ngModel)]="client.ClientLastName" type="text" name="lastN" class="form-control" id="lname"
placeholder="Last Name">
</div>
</div>
</div>
</div>
<br />
<div class="row form-inline">
<div class="col-md-6">
<div class="form-group">
<div class="col-md-3">
<label for="email">Email </label>
</div>
<div class="col-md-9">
<input [(ngModel)]="client.ContactEmailID" name="Email" type="email" class="form-control" id="email"
placeholder="Enter email">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="col-md-3">
<label for="pnumber">Phone Number</label>
</div>
<div class="col-md-9">
<input [(ngModel)]="client.ContactMobileNo" name="PhoneNumber" type="text" class="form-control"
(keypress)="onlyNumberKey($event)" id="pnumber" placeholder="Phone Number" minlength="10" maxlength="10">
</div>
</div>
</div>
</div>
<br />
</fieldset>
<button type="submit" class="btn btn-primary btn-sm" style="width:5em">Update</button>
</form>
</div>
<!-- {{f.value | json}} -->
</div>
Component.ts where i have imported validators
this.form = fb.group({
FirstName: [ "", Validators.compose([Validators.pattern(alphabetRegex), Validators.required])],
LastName: ["", ([Validators.pattern(alphabetRegex), Validators.required])],
Email: ["", Validators.compose([Validators.pattern(regexEmail), Validators.required])],
PhoneNumber: ["", Validators.compose([Validators.required])],
});
Before answering your question, I would like to make a suggestion.
In your code, you have mixed the concepts of Reactive/Model driven forms(Component.ts) and template driven forms (Component.html).
If you wish to follow template driven form, please use:
<input type="text" id="fName" class="form-control" required pattern="[A-Z]{5}" [(ngModel)]="FirstName" name="FirstName" #fName="ngModel" />
<div [hidden]="!fName.errors.required">FirstNameis required!</div>
<div [hidden]="!fName.errors.pattern">FirstName must be at least 5 characters long</div>
In this case you need not have the form builder object in .ts file.
If you are using reactive forms
<input type="text" class="form-control" formControlName="FirstName" id="FirstName" placeholder="Enter First Name"/>
<div *ngIf="form.controls.FirstName.errors.required">Field is required.</div>
<div *ngIf="form.controls.FirstName.errors.pattern">Can contain only alphabets and at least three characters required</div>
There are two types of forms in Angular, Template Driven and Reactive forms. It seems you are mixing them. [(ngModel)] belongs to template driven forms, while FormBuilder belongs to reactive forms. To learn about validation in both types, see https://angular.io/guide/form-validation
If you want to use reactive forms, learn more here https://angular.io/guide/reactive-forms
I recommend you pick one and stick with it in given project.
If validation is critical to you, reactive forms are probably the better choice because they provide powerful and flexible validation.
Use FormControl and Validators from #angular/forms for form field validations as below.
this.form = new FormGroup({
FirstName : new FormControl( '', [ Validators.required, Validators.pattern(alphabetRegex) ]),
LastName : new FormControl( '', [ Validators.required, Validators.pattern(alphabetRegex) ]),
Email : new FormControl( '', [ Validators.required, Validators.pattern(regexEmail) ]),
PhoneNumber : new FormControl( '', [ Validators.required ]),
});
Remember to add import FormControl, FormGroup and Validator in your component as below.
import { FormControl, FormGroup, Validators } from '#angular/forms';
You can show validation in HTML as below.
<form #f="ngForm" (submit)="submit()" [formGroup]="myform">
<div class="row form-inline">
<div class="col-md-6">
<div class="form-group">
<div class="col-md-3">
<label for="fname">First Name</label>
</div>
<div class="col-md-9">
<input [(ngModel)]="client.ClientFirstName" type="text" name="FirstName" class="form-control" id="fname"
placeholder="First Name">
</div>
<div>
<span *ngIf="(
myform.get('FirstName').hasError('required') &&
myform.get('FirstName').touched)">Please enter first name</span>
<span class="error-message" *ngIf="(
myform.get('FirstName').hasError('pattern') &&
myform.get('FirstName').touched)">Enter valid first name </span>
</div>
</div>
</div>
</div>
</form>
Hope this will help you.
Add [formGroup] in <form> element and formControlName to form element.
Look at this sample demo - https://stackblitz.com/edit/angular-yeyiuk
If you would like to see the simple template driven form validation working model with angular, you can take a look at the following:
https://github.com/alokstar/Angular4FormValidation
It shows the simple error messages on the fly using data-binding in angular.
Hope it helps!

Cannot read property 'form' of undefined angular 5

I have the following html form in angular
<form (ngSubmit)="signin()" #signinform="ngForm">
<div class="form-group row">
<label for="signinemail" class="col-sm-2 col-form-label">Email:</label>
<div class="col-sm-10">
<input type="email"
class="form-control"
id="signinemail"
name="signinemail"
ngModel
placeholder="Email">
</div>
</div>
<div class="form-group row">
<label for="signinpassword" class="col-sm-2 col-form-label">Password:</label>
<div class="col-sm-10">
<input type="password"
class="form-control"
id="signinpassword"
name="signinpassword"
ngModel
placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input ml-0"
type="checkbox"
id="gridCheck"
name="remembercheckbox"
ngModel>
<label class="form-check-label" for="gridCheck">
Remember Me
</label>
</div>
<small class="form-text text-muted">Forget Password?</small>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Sign In</button>
<button type="button" class="btn btn-outline-dark" (click)="c('Close click')">Close</button>
</div>
</form>
and the following typescript for the form:
import {NgForm} from "#angular/forms";
#ViewChild('signinform') signinform: NgForm;
signin() {
let payload = {
email: this.signinform.form.value.signinemail,
password: this.signinform.form.value.signinpassword,
localstorage: this.signinform.form.value.remembercheckbox
};
this.userservice.gettoken(payload);
this.signedin = true;
}
I have compared this to other forms I have built and yet there is no difference. What could be causing this?
the form element is on the dom when I call. The submit button is within the form. The #ViewChild element syntax is correct and properly imported. I truly don't understand and I am ready to punch a baby.
The code looks fine...You could just try not using view child, and instead do:
<form (ngSubmit)="signin(signinform)" #signinform="ngForm">
signin(form: NgForm) {
console.log(form);
}
I'd definitely try that console though, to make sure the form is being submitted properly.