in the below code i wanted to perform reactive form validation. so i referred to some questions and tutorial for example this one:
https://jasonwatmore.com/post/2018/05/10/angular-6-reactive-forms-validation-example
despite i followed the steps correctly, however when i run the App i receive the following errors
NG0301: Export of name 'ngModel' not found!
the respective spec file was modified as shown below and the required import add to the app.module.ts. please have a look at the code and files posted below and let me know how to fix this error
html code:
<div class="modal-body">
<form [formGroup]="distanceMeasuremrntForm" (ngSubmit)="measureDistanceForCoordinates()" #form="ngForm" class="clr-form clr-form-horizontal" autocomplete="off">
<clr-input-container>
<label >{{ "DISTANCE_MEASUREMENT.START_LONGITUDE" | translate }}:</label>
<input
id="startLngTextId"
required
maxlength="25"
clrInput
type="text"
name="name1"
[(ngModel)]=iMeasureDistanceParametersPasser.startLongitude
#name1="ngModel"
formControlName="startLngControlName"
[ngClass]="{ 'is-invalid': submitted && f.startLngControlName.errors }"
/>
<div *ngIf="submitted && f.startLngControlName.errors" class="invalid-startLng">
<div *ngIf="f.startLngControlName.errors.required">First Name is required</div>
</div>
</clr-input-container>
<clr-input-container>
<label>{{ "DISTANCE_MEASUREMENT.START_LATITUDE" | translate }}:</label>
<input
id="startLatTextId"
required
maxlength="25"
clrInput
type="text"
name="name2"
[(ngModel)]=iMeasureDistanceParametersPasser.startLatitude
#name2="ngModel"
formControlName="startatControlName"
[ngClass]="{ 'is-invalid': submitted && f.startatControlName.errors }"
/>
<div *ngIf="submitted && f.startatControlName.errors" class="invalid-startLat">
<div *ngIf="f.startatControlName.errors.required">First Name is required</div>
</div>
</clr-input-container>
<clr-input-container>
<label>{{ "DISTANCE_MEASUREMENT.END_LONGITUDE" | translate }}:</label>
<input
id="endLngTextId"
required
maxlength="25"
clrInput
type="text"
name="name3"
[(ngModel)]=iMeasureDistanceParametersPasser.endLongitude
#name3="ngModel"
formControlName="endLngControlName"
[ngClass]="{ 'is-invalid': submitted && f.endLngControlName.errors }"
/>
<div *ngIf="submitted && f.endLngControlName.errors" class="invalid-endLng">
<div *ngIf="f.endLngControlName.errors.required">First Name is required</div>
</div>
</clr-input-container>
<clr-input-container>
<label>{{ "DISTANCE_MEASUREMENT.END_LATITUDE" | translate }}:</label>
<input
id="endLatTextId"
required
maxlength="25"
clrInput
type="text"
name="name4"
[(ngModel)]=iMeasureDistanceParametersPasser.endLatitude
#name4="ngModel"
formControlName="endLatControlName"
[ngClass]="{ 'is-invalid': submitted && f.endLatControlName.errors }"
/>
<div *ngIf="submitted && f.endLatControlName.errors" class="invalid-endLat">
<div *ngIf="f.endLatControlName.errors.required">First Name is required</div>
</div>
</clr-input-container>
<div>
<button
class="btn btn-primary"
type="button"
>
{{ "DISTANCE_MEASUREMENT.ENTRY_LABEL" | translate }}
</button>
</div>
<div>
<button
class="btn btn-primary"
type="button"
(click)="clearInputs()"
>
{{ "COMMON.CLEAR_DATA" | translate }}
</button>
</div>
<div>
<label *ngIf=showMeasuredDistance>
{{ "DISTANCE_MEASUREMENT.DISTANCE" | translate }}
{{ "DISTANCE_MEASUREMENT.EQUAL" | translate }}
{{ mMeasuredDistanceInKM }}
{{ "DISTANCE_MEASUREMENT.UNIT_KM" | translate }}
</label>
</div>
</form>
<div class="modal-footer">
<button
class="btn btn-outline"
type="button"
(click)="hideWindowOverlay()"
>
{{ "COMMON.CANCEL" | translate }}
</button>
</div>
</div>
spec file:
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { DistanceMeasurmentParametersComponent } from './distance-measurment-parameters.component';
describe('DistanceMeasurmentParametersComponent', () => {
let component: DistanceMeasurmentParametersComponent;
let fixture: ComponentFixture<DistanceMeasurmentParametersComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports:[FormsModule],
declarations: [ DistanceMeasurmentParametersComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DistanceMeasurmentParametersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
app module
import { BrowserModule } from "#angular/platform-browser";
import { NgModule } from "#angular/core";
import { AppComponent } from "./app.component";
#NgModule({
declarations: [
...
...
],
imports: [
BrowserModule,
HotTableModule.forRoot(),
FormsModule,//<-impored
.....,
.....,
ReactiveFormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
providers: [
{
provide: LocationStrategy,
useClass: HashLocationStrategy
},
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: LoadingScreenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');// für http://192.168.211.39/synops-2
//return new TranslateHttpLoader(http);
}
Related
I was trying to build an angular library for custom validator directive which can validate confirm password but as i build that library and publish on local npm and imported in my project it is throwing ERROR TypeError: tView is null error. here is codes
src\lib\confirm-password-validation.directive.ts
import { Directive } from '#angular/core';
import { FormGroup, NG_VALIDATORS, ValidationErrors, Validator } from '#angular/forms';
#Directive({
selector: '[appConfirmPasswordValidation]',
providers:[{
provide:NG_VALIDATORS,
useClass:ConfirmPasswordValidationDirective,
multi:true
}]
})
export class ConfirmPasswordValidationDirective {
constructor() {
console.log('Form Directive')
}
validate(form:FormGroup|any): ValidationErrors | null {
if(!form.controls.password || !form.controls.confirmPassword){
return null;
}
if(form.controls.password.errors && form.controls.confirmPassword.errors){
return null;
}
if(form.controls.password.value !== form.controls.confirmPassword.value){
form.controls.confirmPassword.setErrors({matchPassword:true});
return {matchPassword:true}
}
return null;
}
}
src\lib\confirm-password-validation.module.ts
import { NgModule } from '#angular/core';
import { ConfirmPasswordValidationComponent } from './confirm-password-validation.component';
import { ConfirmPasswordValidationDirective } from './confirm-password-validation.directive';
#NgModule({
declarations: [
ConfirmPasswordValidationComponent,
ConfirmPasswordValidationDirective
],
imports: [],
exports: [
ConfirmPasswordValidationComponent,
ConfirmPasswordValidationDirective
]
})
export class ConfirmPasswordValidationModule { }
src\public-api.ts
/*
* Public API Surface of confirm-password-validation
*/
export * from './lib/confirm-password-validation.service';
export * from './lib/confirm-password-validation.component';
export * from './lib/confirm-password-validation.module';
export * from './lib/confirm-password-validation.directive';
After publish i have installed in my project
src\app\app.module.ts
import { NgModule } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { BrowserModule } from '#angular/platform-browser';
import { ConfirmPasswordValidationModule } from 'confirm-password-validation';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
ConfirmPasswordValidationModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
src\app\app.component.html
<div class="w-100 d-flex justify-content-center align-items-center" style="height: 100vh;">
<div class="card p-5">
<form [formGroup]="userForm" (ngSubmit)="submit()" appConfirmPasswordValidation>
<div class="mb-3 mt-3">
<label for="email" class="form-label">Email:</label>
<input type="email" class="form-control" id="email" placeholder="Enter email" formControlName="email">
</div>
<div class="mb-3">
<label for="pwd" class="form-label">Password:</label>
<input type="password" class="form-control" placeholder="Enter password" formControlName="password">
</div>
<div class="mb-3">
<label for="pwd" class="form-label">Confirm Password:</label>
<input type="password" class="form-control" placeholder="Enter password" formControlName="confirmPassword">
<p>
<span *ngIf="confirmPassword?.hasError('matchPassword')">
Password Mismatch
</span>
</p>
</div>
<div class="form-check mb-3">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember"> Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
ERROR
My Html file is as follows:
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID: [(ngModel)]</b></label>
<input type="text" placeholder="Enter mail ID" [(ngModel)]="mail" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" [(ngModel)]="mail" name="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
My Typescript file is as follows:
import { Component, NgModule, OnInit } from '#angular/core';
import { Router, RouterModule, Routes } from '#angular/router';
import { MyProductPageComponent } from '../my-product-page/my-product-page.component';
#Component({
selector: 'app-my-home-page',
templateUrl: './my-home-page.component.html',
styleUrls: ['./my-home-page.component.css']
})
export class MyHomePageComponent implements OnInit {
phoneNumber = "";
mailID = "";
constructor(private router: Router) {
}
ngOnInit(): void {
}
myFunc() {
localStorage.setItem("phoneNumber", this.phoneNumber);
localStorage.setItem("mail", this.mailID);
this.router.navigate(['/products']);
}
}
const routes: Routes = [
{ path: 'MyProductPageComponent', component: MyProductPageComponent },
]
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
I want to fetch Phone number and Mail ID entered in form and save that in Local Storage. And redirect to the next page. Please help.
Am getting this error: Declaration expected.
you need to use ngmodel to bind the value with input control and same you can access in your component.
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID: </b></label>
<input type="text" [(ngModel)]="mailID" placeholder="Enter mail ID" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" name="phoneNumber" [(ngModel)]="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
Add variables to phone/mail in your .ts components
Use this to variables in myFunc() to get the value of the variables
Use ngModel to bind the variables with the input of the user (set ngModel on the input not label).
Use import { NgModule } from '#angular/core'; in the app.module and NOT in your component
see working code
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID:</b></label>
<input type="text" placeholder="Enter mail ID" [(ngModel)]="mail" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" [(ngModel)]="phoneNumber" name="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
phoneNumber = "";
mailID = "";
myFunc() {
localStorage.setItem("phoneNumber", this.phoneNumber);
localStorage.setItem("mail", this.mailID);
}
const routes: Routes = [
{ path: 'MyProductPageComponent', component: MyProductPageComponent },
]
The path variable should not have a component and you are using router.navigate('/products')
const routes: Routes = [
{ path: 'products', component: MyProductPageComponent },
]
These variables which are used in the ts should bind with the ngModel used in the template
phoneNumber = "";
mailID = "";
<h2>Welcome User!!!</h2>
<form class="container" action="/product">
<div>
<label for="mail"><b>Email-ID: </b></label>
<input type="text" placeholder="Enter mail ID" [(ngModel)]="mailID" name="mail" required>
<label for="psw"><b>Phone Number</b></label>
<input type="text" placeholder="Enter Phone Number" [(ngModel)]="phoneNumber" name="phoneNumber" required>
<button (click)="myFunc()">NEXT</button>
</div>
</form>
I'm try to make custom Validators that give user message when he/she leave a space on text but i received this error.
1-Cannot read property 'removeSpaceFromUserName' of undefined
2-Cannot read property 'required' of null
at Object.eval [as updateDirectives]
Here's the html of the component
<form [formGroup]='form'>
<div class="form-group">
<label for="username">Username</label>
<input
formControlName='username'
id="username"
type="text"
class="form-control">
<div *ngIf="username.touched && username.touched" class="alert alert-danger">
<div *ngIf="username.errors.required"> You need to enter user name</div>
<div *ngIf="username.errors.minlength"> Min Length is
{{ username.errors.minLength.requiredLength}}
</div>
<div *ngIf="UserNameValiditors.removeSpaceFromUserName">
removeSpaceFromUserName </div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
formControlName='password'
id="password"
type="text"
class="form-control">
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
Here's the custom validator class
import { AbstractControl, ValidationErrors } from "#angular/forms";
export class UserNameValiditors {
static removeSpaceFromUserName(control: AbstractControl): ValidationErrors | null {
if ((control.value as string).indexOf(' ') >= 0) {
return {
removeSpaceFromUserName: true
};
}
else {
return null;
}
}
}
import { Component } from '#angular/core';
import { FormControl , FormGroup , Validators } from "#angular/forms";
import { UserNameValiditors } from './UserNameValditors';
#Component({
selector: 'signup-form',
templateUrl: './signup-form.component.html',
styleUrls: ['./signup-form.component.css']
})
export class SignupFormComponent {
form= new FormGroup(
{
username : new FormControl('',
[
Validators.required,
Validators.minLength(3) ,
UserNameValiditors.removeSpaceFromUserName
]) ,
password : new FormControl('',Validators.required)
});
get username()
{
return this.form.get('username');
}
}
You can try with this solution.
I have create a demo on Stackblitz
app.component.ts
myForms: FormGroup;
constructor(fb: FormBuilder) {
this.myForms = fb.group({
username: [null, Validators.compose([
Validators.required, Validators.minLength(3), usernameValidator])],
password: [null, [
Validators.required]]
});
}
app.component.html
<form [formGroup]="myForms">
<label>User Name :
<input type="text" formControlName="username">
</label><br>
<div class="errors" *ngIf="myForms.get('username').invalid && (myForms.get('username').touched || myForms.get('username').dirty)">
<div *ngIf="myForms.get('username').hasError('required')">
username is required
</div>
<div *ngIf="myForms.get('username').errors.minlength">
username must be at least 3 characters
</div>
<div class="error-text" *ngIf="myForms.get('username').hasError('removeSpaceFromUserName')">
removeSpaceFromUserName
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
formControlName='password'
id="password"
type="text"
class="form-control">
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
Use hasError() to check if certain error is present on the form.
html code
<div *ngIf="username.hasError('required')"> You need to enter user name</div>
<div *ngIf="username.hasError('minlength')"> Min Length is {{ username.hasError('minLength')}}
</div>f
<div *ngIf="username.hasError('removeSpaceFromUserName')">
removeSpaceFromUserName </div>
</div>
Your working code is here
I'm implementing a simple login/register app with Angular 4. What I want to achieve is to have the default view displaying the login form, and only when I click on a Register link I want to display the register form, that has to replace the login form.
Right now I have to click on the Login link to display it. I'll paste some code.
App Module
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { RouterModule } from '#angular/router';
import { AppComponent } from './components/app/app.component';
import { LoginComponent } from './components/login/login.component';
import { RegisterComponent } from './components/register/register.component';
import { HomeComponent } from './components/home/home.component';
import { UserService } from './services/user/user.service';
import { User } from './services/user/user';
#NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot([
{
path: 'login',
component: LoginComponent
},
{
path: 'register',
component: RegisterComponent
},
{
path: 'home',
component: HomeComponent
}
])
],
declarations: [
AppComponent,
LoginComponent,
RegisterComponent,
HomeComponent
],
providers: [UserService, User],
bootstrap: [AppComponent]
})
export class AppModule { }
App Component Template
<div id="container">
<div id="parent">
<div id="left"></div>
<div id="right">
<nav>
<a routerLink="/login" routerLinkActive="active">Login</a>
<a routerLink="/register" routerLinkActive="active">Register</a>
</nav>
<router-outlet></router-outlet>
</div>
</div>
</div>
Login Component Template
<form #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)">
<div>
<label for="username">Username</label>
<input id="username" name="username" ngModel #username="ngModel">
</div>
<div>
<label for="password">Password</label>
<input id="password" name="password" ngModel #password="ngModel">
</div>
<span *ngIf="onSubmit(loginForm)">true</span>
<button>Login</button>
</form>
Register Component Template
<form #registerForm="ngForm" (ngSubmit)="onSubmit(registerForm)">
<div>
<label for="name">Nome</label>
<input id="name" name="name" ngModel #name="ngModel">
</div>
<div>
<label for="lastName">Cognome</label>
<input id="lastName" name="lastName" ngModel #lastName="ngModel">
</div>
<div>
<label for="username">Username</label>
<input id="username" name="username" ngModel #username="ngModel">
</div>
<div>
<label for="password">Password</label>
<input id="password" name="password" ngModel #password="ngModel">
</div>
<div>
<label for="passwordRep">Ripeti la password</label>
<input id="passwordRep" name="passwordRep">
</div>
<button>Registrati</button>
</form>
Is there some Router Module setting that I'm missing?
Thanks in advance.
In your routing you need to redirect the user to the login page if you want it as default view. So try the following:
RouterModule.forRoot([
{
path: '',
redirectTo: 'login',
pathMatch: 'full'
},
{
path: 'login',
component: LoginComponent
},
{
path: 'register',
component: RegisterComponent
},
{
path: 'home',
component: HomeComponent
}
])
I'm starting with Angular and I'm on a project where I have to validate the inputs so they can't be left clear, every input must me completed.
It's an html and we have a .ts file.
This is an extract of the html:
<div class="form-group">
<input type="text"
class="form-control"
id="factory"
[(ngModel)]="factory.company">
</div>
I need to validate this factory input but when I was watching tutorials all I needed to do was to write 'required' inside the <input> and that was it but I had a <form> and every input was inside this form, and this html doesn't have a <form> and when I put one the design was horrible and I couldn't work.
Here is an example using required fields (in login page) :
<form [formGroup]='loginForm' (submit)="login(loginForm.value)">
<div class="col-md-6">
<div class="login-mail">
<input type="text" placeholder="Email" formControlName="email" required="">
<i class="fa fa-envelope"></i>
</div>
<div class="login-mail">
<input type="password" placeholder="Password" formControlName="password" pattern=".{8,20}" required="">
<i class="fa fa-lock"></i>
</div>
</div>
<div class="col-md-6 login-do">
<label class="hvr-shutter-in-horizontal login-sub">
<input type="submit" value="login" >
</label>
</div>
<div class="clearfix"> </div>
</form>
in the login.component.ts , u should make some changes:
1) import some modules :
import { FormBuilder, FormGroup, Validators} from '#angular/forms';
2) in oninit function :
loginForm: FormGroup;
constructor(private fb : FormBuilder) {}
ngOnInit(){
this.loginForm = this.fb.group({
email : ["", Validators.required],
password : ["", Validators.required]
});
}
Hope that helps u :)
I would think that you should be able to add a form element. However, if you cannot as you have said then you can add the ngForm directive onto any element to achieve the same behavior as having the form element.
See this plunker for examples using ReactiveFormsModule and FormsModule:
Plunker
//our root app component
import {Component, OnInit, NgModule} from '#angular/core'
import {ReactiveFormsModule, FormsModule, FormControl, Validators} from '#angular/forms'
import {BrowserModule} from '#angular/platform-browser'
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<div class="form-group">
<label>Model Driven Form</label>
<input type="text"
class="form-control"
id="companyModel"
[formControl]="companyModel">
<span [hidden]="companyModel.valid || companyModel.pristine">REQUIRED!</span>
</div>
<div class="form-group" ngForm #myForm="ngForm">
<label>Template Driven Form</label>
<input type="text"
class="form-control"
name="companyTemplate"
ngModel
id="companyTemplate"
#companyTemplate="ngModel"
required>
<span [hidden]="companyTemplate.valid || companyTemplate.pristine">REQUIRED!</span>
</div>
</div>
`,
})
export class App implements OnInit {
name:string;
companyModel: FormControl
constructor() {
this.name = 'Form Validation Demo'
}
ngOnInit() {
this.companyModel = new FormControl('', Validators.required)
}
}
#NgModule({
imports: [ BrowserModule, ReactiveFormsModule, FormsModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}