How to add custom validator to reactive forms in Angular5 - angular5

I have the following passwordvalidator which I don't know how to attach into the html. The way I am invoking it now it's not working loginForm.controls.password.errors.passwordValidator
See below in the actual code.
import { FormControl } from "#angular/forms";
export class PasswordValidator {
static getPasswordValidator() {
return function passwordValidator(control: FormControl): { [s: string]: boolean } {
// Write code here..
if (!control.value.match(/^((?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{6,})/)) {
return { invalidPassword: true };
}
return null;
}
}
}
Then this is how I am using it in login.ts
ngOnInit() {
this.loginForm = this.fb.group({
username: ['', [Validators.required, Validators.email]],
password: ['',
Validators.compose([
Validators.required,
PasswordValidator.getPasswordValidator()
]
)]
});
}
But can't find out how to add it to the formcontrol in login.html
<mat-form-field class="example-full-width">
<input id="password" formControlName="password" matInput placeholder="Password">
</mat-form-field>
<br>
<div *ngIf="loginForm.controls.password.invalid && (loginForm.controls.password.dirty || loginForm.controls.password.touched)"
class="alert alert-danger">
<div class="error mat-body-2" *ngIf="loginForm.controls.password.errors.required">
You must fill out your password
</div>
<div class="error mat-body-2" *ngIf="loginForm.controls.password.errors.passwordValidator && !loginForm.controls.password.errors.required">
Invalid email password
</div>

You should check if the key invalidPassword exist in errors of that controls or not like that
<mat-form-field class="example-full-width">
<input id="password" formControlName="password" matInput placeholder="Password">
</mat-form-field>
<br>
<div *ngIf="loginForm.controls.password.invalid && (loginForm.controls.password.dirty || loginForm.controls.password.touched)"
class="alert alert-danger">
<div class="error mat-body-2" *ngIf="loginForm.controls.password.errors.required">
You must fill out your password
</div>
<div class="error mat-body-2" *ngIf="loginForm.controls.password.errors.invalidPassword && !loginForm.controls.password.errors.required">
Invalid email password
</div>

Related

validate form inputs bootstrap4

I have this code in my vue template
<div class="form-row" :class="{'was-validated': this.checkPassword()}">
<div class="col-6">
<label>Password</label>
<input :type="showPassword ? 'text' : 'password'" class="form-control" ref="password" required v-model="password">
<div class="valid-feedback" v-if="!error">
Password match
</div>
<div class="invalid-feedback" v-else>
Password not match
</div>
</div>
<div class="col-6">
<label>Confirm password</label>
<div class="input-group">
<input :type="showPassword ? 'text' : 'password'" class="form-control" ref="passwordCheck" required v-model="passwordCheck" #change="checkPassword()">
<div class="input-group-append">
<button class="btn btn-secondary" #click.prevent="copyToClipboard()"><i class="fas fa-clipboard"></i></button>
</div>
</div>
</div>
</div>
I want to show like the bootstrap4 documentation a green input field if the password matches or a red one if the password aren't matching. I'm trying by adding the was-validated class to the form-row if the demanded method return true but when the view where the password inputs are rendered the two input fields are always red. How I can fix this to give the correct feedback to the user?
Please always share all the relevant parts of the component otherwise, it's hard to tell where the problem resides. Here, you haven't shared your <script> section. Anyway, I guess this should put you on the right track.
<template>
<div class="form-row" :class="{'was-validated': this.checkPassword()}">
<div class="col-6">
<label>Password</label>
<label>
<input :type="showPassword ? 'text' : 'password'" class="form-control" :class="getPasswordClass()"
ref="password" required v-model="password">
</label>
</div>
<div class="col-6">
<label>Confirm password</label>
<div class="input-group">
<label>
<input :type="showPassword ? 'text' : 'password'" class="form-control" :class="getPasswordClass()"
ref="passwordCheck" required v-model="passwordCheck" #input="checkPassword()">
</label>
<div class="input-group-append">
<button class="btn btn-secondary" #click.prevent="copyToClipboard()"><i
class="fas fa-clipboard"></i></button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
password: null,
passwordCheck: null,
error: true,
showPassword: true,
}
},
methods: {
checkPassword() {
this.error = this.password !== this.passwordCheck;
},
getPasswordClass() {
if (!this.password || !this.passwordCheck) {
return '';
}
return this.error ? 'is-invalid' : 'is-valid'
},
copyToClipboard() {
//
}
}
}
</script>
So, in my opinion, you should only set the dynamic class (is-valid or is-invalid) when both inputs are provided. In this example I've added that to both password and passwordCheck fields but I think it's enough to just apply it to the passwordCheck because that's the one checked against the password.
If you only want to check after user leaves the field you could adjust the code like this:
In the template remove:
:class="{'was-validated': this.checkPassword()}"
And update:
#blur="checkPassword()
In the data() add:
blurred: false,
In the methods update:
methods: {
checkPassword() {
this.blurred = true;
this.error = this.password !== this.passwordCheck;
},
getPasswordClass() {
if (!this.blurred) {
return '';
}
return this.error ? 'is-invalid' : 'is-valid'
},
...
}

Angular prefilled form data becomes null when submitting

I have created an Angular form to update the user details. The fields values of the form are filled by the user details fetched from the backend when the form loads. If the user wishes to update any field they can update and submit the form. But the field values of the fields which user didn't change are set as null even though those fields are initialized at the beginning. Can someone please explain how to get the prefilled unchanged field values when submitting the form?
The HTML file is this,
<app-navbar></app-navbar>
<div class="container">
<form [formGroup]="profileForm" style="margin-top: 60px;" disabled="true" (ngSubmit)="onSubmit()">
<input type="file" id="file" (change)="onFileSelected($event)" accept="image\jpeg" formControlName="profPic">
<div class="row">
<!--Profile Picture-->
<div class="col-12 col-md-4 d-flex justify-content-center">
<label for="file">
<a (mouseenter)="hoverIdx = 1"
(mouseleave)="hoverIdx = -1"
id="overlay">
<span [ngClass]="{ 'overlay-icon': true, 'hide': hoverIdx !== 1 }"
class="rounded-circle">
<fa-icon [icon]="cameraIcon" class="icon"></fa-icon>
</span>
<img
[src]="profPic"
class="rounded-circle"
width="300"
height="300"
/>
</a>
</label>
<div class="col-md-2 align-self-end ml-auto p-2" id="deleteIcon">
<fa-icon [icon]="deleteIcon"></fa-icon>
</div>
</div>
<div class="col-12 col-md-8">
<div class="card" style="margin-bottom: 20px;">
<div class="card-body" >
<!---Intro-->
<div class="row" style="font-size: 60px;">
<div class="col-12">Hi, {{ fNme }}</div>
</div>
<!--first name & last name-->
<div class="row" style="margin-top: 10px;">
<div class="col-12 col-md-6">
<mat-form-field appearance="outline">
<input formControlName="fName"
matInput placeholder="First Name"
[value]="fNme"
(change)="fNmeChnge = true"/>
</mat-form-field>
</div>
<div class="col-12 col-md-6">
<mat-form-field appearance="outline">
<input formControlName="lName"
matInput placeholder="Last Name"
[value]="lNme"
(change)="lNmeChnge = true" />
</mat-form-field>
</div>
</div>
<!--row-->
<!-- email & country-->
<div class="row" style="margin-bottom: 25px;">
<div class="col-12 col-md-6">
<mat-form-field appearance="outline">
<input formControlName="email"
matInput placeholder="Email"
[value]="email"
(change)="emailChnge = true"/>
</mat-form-field>
</div>
<div class="col-12 col-md-6">
<mat-form-field appearance="outline" >
<input formControlName="country"
matInput placeholder="Country"
[value]="country"
(change)="countryChnge = true"/>
</mat-form-field>
</div>
</div>
<!--row-->
</div>
</div>
<button type="button" class="btn btn-primary float-right" style="margin-left:10px" type="submit">Save</button>
<button type="button" class="btn btn-outline-primary float-right" (click)="cancel()">Cancel</button>
</div><!--col-md-8-->
</div><!--row-->
</form>
</div><!--container-->
The component file is this,
import { User } from './../shared/user.model';
import { F_NAME, L_NAME, AUTHENTICATED_USER, PROF_PIC, BASE64URL } from './../../app.constants';
import { Component, OnInit, Inject } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { AuthenticationService } from '../service/authentication.service';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '#angular/material/dialog';
import { DialogOverviewExampleDialog } from './dialog';
import { faCamera, faTrashAlt } from '#fortawesome/free-solid-svg-icons';
import { DomSanitizer } from '#angular/platform-browser';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: User;
cameraIcon = faCamera;
deleteIcon = faTrashAlt;
profPic: any;
profileForm: FormGroup;
email: string;
fNme: string;
lNme: string;
country: any;
selectedFile: File = null;
base64Data: any;
fNmeChnge: any;
lNmeChnge: any;
countryChnge: any;
emailChnge: any;
title = 'Profile';
constructor(
private service: AuthenticationService,
public dialog: MatDialog,
private sanitizer: DomSanitizer
) {
}
ngOnInit() {
this.email = sessionStorage.getItem(AUTHENTICATED_USER);
this.profileForm = new FormGroup({
fName: new FormControl(null, [Validators.required]),
lName: new FormControl(null, Validators.required),
email: new FormControl(null, [Validators.required, Validators.email]),
country: new FormControl(null, Validators.required)
});
this.service.getUser(this.email)
.subscribe(res => {
this.fNme = res.fNme;
this.lNme = res.lNme;
this.country = res.country;
this.profPic = BASE64URL + res.profPic ;
});
}
openDialog(): void {
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '500px'
});
}
onFileSelected(event){
this.selectedFile = event.target.files[0] as File;
const reader = new FileReader();
reader.onload = e => this.profPic = reader.result;
reader.readAsDataURL(this.selectedFile);
}
onSubmit() {
const fd = new FormData();
fd.append('file', this.selectedFile);
this.service.uploadImage(fd, this.email);
this.user = new User(this.profileForm.get('fName').value,
this.profileForm.get('lName').value,
this.profileForm.get('country').value,
this.profileForm.get('email').value);
console.log(this.user);
this.service.updateProfile(this.user, this.email);
// .subscribe(res => {
// this.fNme = res.fNme;
// this.lNme = res.lNme;
// this.country = res.country;
// this.profPic = BASE64URL + res.profPic ;
// });
this.ngOnInit();
}
I gets the user data from the server via these codes,
uploadImage(file: FormData, email: string) {
this.http.put<any>(`${API_URL}/profile-picture/${email}`, file)
.subscribe(res => {console.log(res); });
}
updateProfile(user: User, email: string) {
this.http.put<any>(`${API_URL}/profile/${email}`, user).subscribe();
}
getUser(email: string) {
return this.http.get<any>(`${API_URL}/user/${email}`);
}

Cannot read property 'post' of undefined, in nuxt js

I am making registration form in nuxt js, it takes data from api, I have installed axios and auth module, I wrote base url in nuxt.config.js file. It shows TypeError: Cannot read property 'post' of undefined
```template>
<div>
<section class="content">
<div class="register_form m-auto text-center form-group">
<form method="post" #submit.prevent="register" >
<h1 class ="register_title">REGISTER</h1>
<h2 class="register_text">PLEASE REGISTER TO USE THIS WEBSITE</h2>
<input class="form-control" type="text" placeholder = 'USERNAME' v-model="username" name="username" required>
<input class="form-control" type="password" placeholder = 'PASSWORD' v-model="password" name="password" required>
<button type="submit" to="#" class="register_btn">
REGISTER
</button>
</form>
</div>
</section>
</div>
</template>
<script>
export default {
layout: 'loginLayout',
data(){
return {
username: '',
password: ''
}
},
methods: {
async register() {
try {
await this.$axios.post('register', {
username: this.username,
password: this.password
})
this.$router.push('/')
}
catch (e) {
console.log(e)
}
}
}
}
</script>```
try to use
await this.$axios.$post instead of await this.$axios.$post

Angular2: How to enable save button if any model value changed on edit page

I am new for angular 2. I have a page where we can edit details of customer profile. How to enable save button if any property of has been changed. I know it is possible in angular1 by using $watch.
It is simple. dirty check your form if you are using #angular/forms.
create form
export class HeroDetailComponent4 {
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.heroForm = this.fb.group({
name: ['', Validators.required ],
street: '',
city: '',
state: '',
zip: '',
power: '',
sidekick: ''
});
}
}
HTML:
<h2>Hero Detail</h2>
<h3><i>A FormGroup with multiple FormControls</i></h3>
<form [formGroup]="heroForm" novalidate>
<button (click)="submit()" [disabled]="!heroForm.dirty" type="button">Submit</button>
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
use heroForm.dirty to check whether form data is changed. it will set to true if any control inside heroForm has been changed.
<button (click)="submit()" [disabled]="!heroForm.dirty" type="button">Submit</button>
Refer angular docs for more info
you can use form control validation for it.
some thing like this in html template:
<form fxLayout="column" [formGroup]="form">
<mat-form-field class="mb-1">
<input matInput [(ngModel)]="userProfileChangeModel.firstName" placeholder="نام"
[formControl]="form1.controls['fname']">
<small *ngIf="form1.controls['fname'].hasError('required') && form1.controls['fname'].touched"
class="mat-text-warn">لطفا نام را وارد نمایید.
</small>
<small *ngIf="form1.controls['fname'].hasError('minlength') && form1.controls['fname'].touched"
class="mat-text-warn">نام باید حداقل 2 کاراکتر باشد.
</small>
<small *ngIf="form1.controls['fname'].hasError('pattern') && form1.controls['fname'].touched"
class="mat-text-warn">لطفا از حروف فارسی استفاده نمائید.
</small>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button (click)="editUser()" color="primary" [disabled]="!form1.valid" type="submit">
ذخیره
</button>
</mat-card-actions>
</form>
and like this in ts file:
this.form = this.bf.group({
fname: [null, Validators.compose([
Validators.required,
Validators.minLength(2),
Validators.maxLength(20),
Validators.pattern('^[\u0600-\u06FF, \u0590-\u05FF]*$')])],
});
if:
[disabled]="!form1.valid"
is valid save button will be active
bast regards.
You can use disabled option like below :
<button [disabled]="isInvalid()" type="button" (click) = "searchClick()" class="button is-info">
<span class="icon is-small">
<i class="fa fa-search" aria-hidden="true"></i>
</span>
<span>Search</span>
</button>
you can create isInvalid() in your ts file and check if that property is empty or not and return that boolean value
and for hide button on a state you can use *ngIf in line directive.
This worked for me, pls try.
In your html,
<input type="text" [ngModel]="name" (ngModelChange)="changeVal()" >
<input type="text" [ngModel]="address" (ngModelChange)="changeVal()" >
<input type="text" [ngModel]="postcode" (ngModelChange)="changeVal()" >
<button [disabled]="noChangeYet" (click)="clicked()" >
<span>SUBMIT</span>
</button>
In your component
export class customer implements OnInit {
name: string;
address: string;
postcode: string;
noChangeYet:boolean = true;
constructor() {}
changeVal(){ // triggers on change of any field(s)
this.noChangeYet = false;
}
clicked(){
// your function data after click (if any)
}
}
Hope this is what you need.
Finally I resolved this issue.
import { Component, Input, Output, OnInit, AfterViewInit, EventEmitter, ViewChild } from '#angular/core';
#Component({
selector: 'subscribe-modification',
templateUrl: './subscribe.component.html'
})
export class SampleModifyComponent implements OnInit, AfterViewInit {
disableSaveSampleButton: boolean = true;
#ViewChild('sampleModifyForm') sampleForm;
ngAfterViewInit() {
setTimeout(() => {
this.sampleForm.control.valueChanges.subscribe(values => this.enableSaveSampleButton());
}, 1000);
}
enableSaveSampleButton() {
console.log('change');
this.disableSaveSampleButton = false;
}
}
HTML
<button id="btnSave" class="btn btn-primary" (click)="save()" />

Aurelia - Unable to access variables in my template

Simple question.
I have a login template - a form for username and password:
<template>
<section>
<h2>${heading}</h2>
<form role="form" submit.delegate="login()">
<div class="form-group">
<label for="userName">User Name</label>
<input type="text" value.bind="userName" class="form-control" id="userName" placeholder="User Name">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" value.bind="password" class="form-control" id="password" placeholder="Password">
</div>
<button type="button" click.delegate="submitLogin()" class="btn btn-default">Login</button>
</form>
<hr>
<div class="alert alert-danger" if.bind="loginError">${loginError}</div>
</section>
I have looked around to find out how I can access these variables in my login.ts file.
In particular I want to eventually send them to the api once the button login has been pressed.
I have a submitLogin() function but I dont know how you access the variables username and password.
Can someone show me how these variable are accessed.
I get a red underscore for username and password..
import { HttpClient } from "aurelia-fetch-client";
import { autoinject } from "aurelia-framework";
import { TokenService } from "../tokenService";
#autoinject
export class Login {
http: HttpClient;
tokenService: TokenService;
heading = "Login";
constructor(tokenService: TokenService, http: HttpClient, ) {
this.tokenService = tokenService;
this.http = http;
}
public submitLogin(): void {
console.log("userName, Password", this. userName, this.password);
}
}
form submit logic can be bound to <form> itself having given the button type submit
<form role="form" submit.delegate="submitLogin()">
<div class="form-group">
<label for="username">User Name</label>
<input type="text" value.bind="username" class="form-control" id="username" placeholder="User Name">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" value.bind="password" class="form-control" id="password" placeholder="Password">
</div>
<button type="submit" class="btn btn-default">Login</button>
</form>
you can make your class fields accessible from the view or otherwise as below
import { HttpClient } from "aurelia-fetch-client"
import { autoinject } from "aurelia-framework"
import { TokenService } from "../tokenService"
#autoinject
export class Login {
heading: string = "Login"
username: string = ''
password: string = '' // these are pubic fields available in your view unless you add 'private' in front of them
constructor(private tokenService: TokenService, private http: HttpClient) { // this way you can keep them private since they are not needed in the view
}
submitLogin() {
const { username, password } = this
if (!!username && !!password) { // or your validations
this.tokenService.login({ username, password })
}
}
}