Angular 8.3.15 custom validator with parameter not working as expected - javascript

I'm having some trouble getting a custom validator working. I have other custom and non-custom validators working, but this one that I am passing a parameter to does not work as expected. Within the validator, it is recognizing that the validation code is working, but when looking at the form within field-validation-error, it is returning that the form is valid. Any help would be appreciated, thanks!
Within password.component.ts
this.passwordFormGroup = new FormGroup({
hintQuestionFormControl1: new FormControl(this.currentQuestions[0], Validators.required),
hintAnsFormControl1: new FormControl(this.currentAnswers[0], [Validators.required, EditAccountValidators.checkQuestionsDontContainAnswer('hintQuestionFormControl1')]),
});
Within edditAccountValidators.ts
export class EditAccountValidators {
public static checkQuestionsDontContainAnswer(correspondingQuestion: string): ValidatorFn {
return (control: FormControl) => {
if (control.parent) {
const question = control.parent.get(correspondingQuestion).value;
const answer = control.value;
if (question && answer) {
question.split(" ").forEach(function (wordInQuestion) {
answer.split(" ").forEach(function (wordInAnswer) {
if (wordInQuestion.toLowerCase().includes(wordInAnswer.toLowerCase())) {
console.log('same');
return {answerDoesntContainQuestion : true};
}
});
});
}
}
return null;
}
}
Within field-validation-error.component.ts
import {Component, Input, OnInit} from '#angular/core';
#Component({
selector: 'field-validation-error',
templateUrl: './field-validation-error.component.html',
styleUrls: ['./field-validation-error.component.css']
})
export class FieldValidationErrorComponent implements OnInit {
#Input() validatorName: string;
#Input() form: any;
errorMessage: string;
displayError: boolean;
ngOnInit(): void {
this.errorMessage = this.getValidatorErrorMessage();
this.form.valueChanges.subscribe(() => {
this.displayError = this.form.hasError(this.validatorName);
console.log(this.form);
});
}
private getValidatorErrorMessage() {
return this.validatorName;
}
}
calling Within password.component.html
<field-validation-error
[form]="passwordFormGroup.get('hintAnsFormControl1')"
[validatorName]="'answerDoesntContainQuestion'">
</field-validation-error>

Related

Unit Test for Validator Directive in Angular 11

I am going to write some unit tests for my validator directive, but don't know how, even after googling and reading the Angular website. I will explain the codes (just the parts that are needed) here.
Here is my component.ts code:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup } from '#angular/forms';
import { isValidValidator } from '../../directives/is-valid.directive';
#Component({
selector: 'app-microplate',
templateUrl: './microplate.component.html',
styleUrls: ['./microplate.component.css']
})
export class MicroplateComponent implements OnInit {
form: FormGroup;
ngOnInit(): void {
this.form = new FormGroup({
columns: new FormControl('', [
isValidValidator()
])
});
}
}
Here is my directive.ts code:
import { Directive, Input } from '#angular/core';
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn } from '#angular/forms';
const { isNumbersFieldValid } = require('../utils/utils.js');
export function isValidValidator(): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} | null => {
return isNumbersFieldValid(control.value) ? {isValid: {value: control.value}} : null;
};
}
#Directive({
selector: '[appIsValid]',
providers: [{provide: NG_VALIDATORS, useExisting: IsValidDirective, multi: true}]
})
export class IsValidDirective implements Validator {
#Input('appIsValid') isValid: string;
validate(control: AbstractControl): {[key: string]: any} | null {
return this.isValid ? isValidValidator()(control) : null;
}
}
Here is my directive.spec.ts code:
import { IsValidDirective } from './is-valid.directive';
describe('IsValidDirective', () => {
it('should create an instance', () => {
const directive = new IsValidDirective();
expect(directive).toBeTruthy();
});
// How can I write some unit tests here to check if my directive works well for different input strings?
});
here you can find how to test attribute directives
https://angular.io/guide/testing-attribute-directives
basically you need to create a testComponent in your spec files and apply your directive in that testComponent, your test expectation can be done on the testComponent directly

Why am i having "Cannot read property 'http' of undefined" on this validator?

Im trying to make an asynchronous validator for a reactive form control, that checks if a given username already exists. Heres's the async validator code:
userdata.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { FormControl } from '#angular/forms';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UserdataService {
private apiUrl = 'http://apiurl.com/api'; // its not the real url, im just not posting it for privacy reasons
constructor(private http: HttpClient) {}
checkUsername(control: FormControl): Promise<any> | Observable<any> {
let isUsernameValid;
return new Promise<any>(
(resolve, reject) => {
this.http.get(this.apiUrl + '/users?name='+control.value).subscribe(
response => {
isUsernameValid = response;
});
if (isUsernameValid === 'false') {
resolve({'usernameIsInvalid': true})
} else {
resolve(null);
}
}
);
}
}
When I try this validator i get this error:
"core.js:4197 ERROR TypeError: Cannot read property 'http' of undefined"
Now, i think the errr has something to do with using 'this' but I can't understand why isn't working...
It was driving me insane so I tryed to just place a
console.log(this.apiUrl)
inside the function, outside the promise, just for the sake of trying, and i had the same error: "core.js:4197 ERROR TypeError: Cannot read property 'apiUrl' of undefined"...
Please if someone can explain to me what am I doing wrong, and how to solve it i would be thankful.
EDIT:
I'm calling my service from the reactive form ts file, as shown below:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { CustomValidatorsService } from '../services/custom-validators.service';
import { LocationService } from '../services/location.service';
import { UserdataService } from '../services/userdata.service';
#Component({
selector: 'app-userdata-form',
templateUrl: './userdata-form.component.html',
styleUrls: ['./userdata-form.component.scss']
})
export class UserdataFormComponent implements OnInit {
userdataForm: FormGroup;
provinces: any = null;
provincesLoading = false;
cities: any = null;
citiesLoading = false;
constructor(
private locationService: LocationService,
private userdataService: UserdataService,
private customValidators: CustomValidatorsService,
private router: Router,
private route: ActivatedRoute
) { }
ngOnInit(): void {
this.formInit();
this.loadProvinces();
}
formInit() {
let dni: number = null;
let firstname: string = null;
let lastname: string = null;
let email: string = null;
let mobile: number = null;
let phone: number = null;
let birthdate: Date = null;
let username: string = null;
let password: string = null;
this.userdataForm = new FormGroup({
// ... a lot of controls before ...
'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿ\u00f1\u00d1]+(\s*[a-zA-ZÀ-ÿ\u00f1\u00d1]*)*[a-zA-ZÀ-ÿ\u00f1\u00d1]+$/)
], this.userdataService.checkUsername), // <-- here's the async validator
// ... form continues...
}
loadProvinces() {
this.provincesLoading = true;
this.locationService.getProvinces().subscribe(response => {
this.provinces = response;
this.provincesLoading = false;
});
}
As I've mentioned in the comments, your custom validator should implement the AsyncValidator interface:
import { AbstractControl, AsyncValidator, ValidationErrors } from '#angular/forms';
import { catchError, map } from 'rxjs/operators';
// ...
#Injectable({
providedIn: 'root'
})
export class UserDataValidator implements AsyncValidator {
private apiUrl = 'http://apiurl.com/api'; // its not the real url, im just not posting it for privacy reasons
constructor(private http: HttpClient) {}
// This method is defined as an arrow function such that it can be used
// properly - see https://github.com/angular/angular/issues/24981
validate = (control: AbstractControl) => {
return this.http.get(`${this.apiUrl}/users?name=${control.value}`).pipe(
map(isUsernameValid => (isUsernameValid === 'false' ? { usernameIsInvalid: true } : null),
catchError(() => of(null))
);
}
}
This can then be added to your FormGroup as follows:
constructor (private userDataValidator: UserDataValidator) {
this.userdataForm = new FormGroup({
username: new FormControl(username, [
// ... validators
// Validator classes don't currently work - see
// https://github.com/angular/angular/issues/24981
this.userDataValidator.validate
]),
// ... other form controls
}
// ...
Notes
I've also cleaned up your code that does the validation logic to use RxJS' pipeable operators as well as to use template literals)
Disclaimer: I've not tested that the code above actually works
Resources
Angular - Validating form input > Creating asynchronous validators
Allow passing validator classes to the FormControl constructor · Issue #24981 · angular/angular
I think you should create validator function which get service instance in argument, just like in this article:
https://medium.com/#tomaszsochacki/how-to-do-asynchronous-validator-in-angular-7-6e80243a874a
when you pass method like this
'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿ\u00f1\u00d1]+(\s*[a-zA-ZÀ-ÿ\u00f1\u00d1]*)*[a-zA-ZÀ-ÿ\u00f1\u00d1]+$/)
], this.userdataService.checkUsername),
this context in checkUsername method is missed
or you can do this:
'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿ\u00f1\u00d1]+(\s*[a-zA-ZÀ-ÿ\u00f1\u00d1]*)*[a-zA-ZÀ-ÿ\u00f1\u00d1]+$/)
], this.userdataService.checkUsername.bind(this.userdataService)),
bind in first argument pass 'this' context to method when it is called

Angular 4: reactive form control is stuck in pending state with a custom async validator

I am building an Angular 4 app that requires the BriteVerify email validation on form fields in several components. I am trying to implement this validation as a custom async validator that I can use with reactive forms. Currently, I can get the API response, but the control status is stuck in pending state. I get no errors so I am a bit confused. Please tell me what I am doing wrong. Here is my code.
Component
import { Component,
OnInit } from '#angular/core';
import { FormBuilder,
FormGroup,
FormControl,
Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { EmailValidationService } from '../services/email-validation.service';
import { CustomValidators } from '../utilities/custom-validators/custom-validators';
#Component({
templateUrl: './email-form.component.html',
styleUrls: ['./email-form.component.sass']
})
export class EmailFormComponent implements OnInit {
public emailForm: FormGroup;
public formSubmitted: Boolean;
public emailSent: Boolean;
constructor(
private router: Router,
private builder: FormBuilder,
private service: EmailValidationService
) { }
ngOnInit() {
this.formSubmitted = false;
this.emailForm = this.builder.group({
email: [ '', [ Validators.required ], [ CustomValidators.briteVerifyValidator(this.service) ] ]
});
}
get email() {
return this.emailForm.get('email');
}
// rest of logic
}
Validator class
import { AbstractControl } from '#angular/forms';
import { EmailValidationService } from '../../services/email-validation.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
export class CustomValidators {
static briteVerifyValidator(service: EmailValidationService) {
return (control: AbstractControl) => {
if (!control.valueChanges) {
return Observable.of(null);
} else {
return control.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.switchMap(value => service.validateEmail(value))
.map(data => {
return data.status === 'invalid' ? { invalid: true } : null;
});
}
}
}
}
Service
import { Injectable } from '#angular/core';
import { HttpClient,
HttpParams } from '#angular/common/http';
interface EmailValidationResponse {
address: string,
account: string,
domain: string,
status: string,
connected: string,
disposable: boolean,
role_address: boolean,
error_code?: string,
error?: string,
duration: number
}
#Injectable()
export class EmailValidationService {
public emailValidationUrl = 'https://briteverifyendpoint.com';
constructor(
private http: HttpClient
) { }
validateEmail(value) {
let params = new HttpParams();
params = params.append('address', value);
return this.http.get<EmailValidationResponse>(this.emailValidationUrl, {
params: params
});
}
}
Template (just form)
<form class="email-form" [formGroup]="emailForm" (ngSubmit)="sendEmail()">
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<fieldset class="form-group required" [ngClass]="{ 'has-error': email.invalid && formSubmitted }">
<div>{{ email.status }}</div>
<label class="control-label" for="email">Email</label>
<input class="form-control input-lg" name="email" id="email" formControlName="email">
<ng-container *ngIf="email.invalid && formSubmitted">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Please enter valid email address.
</ng-container>
</fieldset>
<button type="submit" class="btn btn-primary btn-lg btn-block">Send</button>
</div>
</div>
</form>
There's a gotcha!
That is, your observable never completes...
This is happening because the observable never completes, so Angular does not know when to change the form status. So remember your observable must to complete.
You can accomplish this in many ways, for example, you can call the first() method, or if you are creating your own observable, you can call the complete method on the observer.
So you can use first()
UPDATE TO RXJS 6:
briteVerifyValidator(service: Service) {
return (control: AbstractControl) => {
if (!control.valueChanges) {
return of(null);
} else {
return control.valueChanges.pipe(
debounceTime(1000),
distinctUntilChanged(),
switchMap(value => service.getData(value)),
map(data => {
return data.status === 'invalid' ? { invalid: true } : null;
})
).pipe(first())
}
}
}
A slightly modified validator, i.e always returns error: STACKBLITZ
OLD:
.map(data => {
return data.status === 'invalid' ? { invalid: true } : null;
})
.first();
A slightly modified validator, i.e always returns error: STACKBLITZ
So what I did was to throw a 404 when the username was not taken and use the subscribe error path to resolve for null, and when I did get a response I resolved with an error. Another way would be to return a data property either filled width the username or empty
through the response object and use that insead of the 404
Ex.
In this example I bind (this) to be able to use my service inside the validator function
An extract of my component class ngOnInit()
//signup.component.ts
constructor(
private authService: AuthServic //this will be included with bind(this)
) {
ngOnInit() {
this.user = new FormGroup(
{
email: new FormControl("", Validators.required),
username: new FormControl(
"",
Validators.required,
CustomUserValidators.usernameUniqueValidator.bind(this) //the whole class
),
password: new FormControl("", Validators.required),
},
{ updateOn: "blur" });
}
An extract from my validator class
//user.validator.ts
...
static async usernameUniqueValidator(
control: FormControl
): Promise<ValidationErrors | null> {
let controlBind = this as any;
let authService = controlBind.authService as AuthService;
//I just added types to be able to get my functions as I type
return new Promise(resolve => {
if (control.value == "") {
resolve(null);
} else {
authService.checkUsername(control.value).subscribe(
() => {
resolve({
usernameExists: {
valid: false
}
});
},
() => {
resolve(null);
}
);
}
});
...
I've been doing it slightly differently and faced the same issue.
Here is my code and the fix in case if someone would need it:
forbiddenNames(control: FormControl): Promise<any> | Observable<any> {
const promise = new Promise<any>((resolve, reject) => {
setTimeout(() => {
if (control.value.toUpperCase() === 'TEST') {
resolve({'nameIsForbidden': true});
} else {
return null;//HERE YOU SHOULD RETURN resolve(null) instead of just null
}
}, 1);
});
return promise;
}
I tries using the .first(). technique described by #AT82 but I didn't find it solved the problem.
What I eventually discovered was that the form status was changing but it because I'm using onPush, the status change wasn't triggering change detection so nothing was updating in the page.
The solution I ended up going with was:
export class EmailFormComponent implements OnInit {
...
constructor(
...
private changeDetector: ChangeDetectorRef,
) {
...
// Subscribe to status changes on the form
// and use the statusChange to trigger changeDetection
this.myForm.statusChanges.pipe(
distinctUntilChanged()
).subscribe(() => this.changeDetector.markForCheck())
}
}
import { Component,
OnInit } from '#angular/core';
import { FormBuilder,
FormGroup,
FormControl,
Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { EmailValidationService } from '../services/email-validation.service';
import { CustomValidators } from '../utilities/custom-validators/custom-validators';
#Component({
templateUrl: './email-form.component.html',
styleUrls: ['./email-form.component.sass']
})
export class EmailFormComponent implements OnInit {
public emailForm: FormGroup;
public formSubmitted: Boolean;
public emailSent: Boolean;
constructor(
private router: Router,
private builder: FormBuilder,
private service: EmailValidationService
) { }
ngOnInit() {
this.formSubmitted = false;
this.emailForm = this.builder.group({
email: [ '', [ Validators.required ], [ CustomValidators.briteVerifyValidator(this.service) ] ]
});
}
get email() {
return this.emailForm.get('email');
}
// rest of logic
}

Send data from child to parent component

I have a button on my child component that should send information to its parent component but this button is not sending this information. I'm probably missing something but I still didn't notice it.
Here's the code from the button inside my child component (there are two buttons: selectPessoaJuridica and selectPessoaFisica:
import { Component, Input, Output, EventEmitter} from '#angular/core';
import { FormBuilder, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule} from '#angular/forms';
import {FinalizaDisputaService} from '../services/finaliza-disputa.service';
import {FinalizaDisputaComponent} from './finaliza-disputa.component'
#Component({
moduleId: module.id,
selector: 'titular',
templateUrl: 'dados-titular.component.html'
})
export class TitularComponent {
// we will pass in address from App component
#Input('group')
public titularForm: FormGroup;
#Input() submitted:any;
#Input() indexNumber:any;
#Output() modelChanged = new EventEmitter<boolean>();
public isJuridica = false;
classe = {
pessoa_fisica: 'selected',
pessoa_juridica: ''
};
constructor(private _fb: FormBuilder, private finalizaAcordo:FinalizaDisputaService) {}
selectPessoaFisica(e:boolean){
e = false;
this.classe.pessoa_fisica = "selected";
this.isJuridica = false;
this.classe.pessoa_juridica = "";
this.modelChanged.emit(e)
}
selectPessoaJuridica(e:boolean){
e = true;
this.classe.pessoa_fisica = "";
this.classe.pessoa_juridica = "selected";
this.isJuridica = true;
console.log("ativou", e)
this.modelChanged.emit(e);
}
}
So, what this should do is notify the parent that e is now false.
This is the html from parent component:
<titular (modelChanged)="recebeValidators($event)" [indexNumber]="indice" [submitted]="submitted" [group]="formDadosBancarios.controls.dados_titular.controls[i]"></titular>
And this is the code from parent component where I should receive the value from e (recebeValidators ):
import { Component, OnChanges, OnInit, Input } from '#angular/core';
import { Http } from '#angular/http';
import { FormBuilder, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule, AbstractControl, ValidatorFn } from '#angular/forms';
import { FinalizaDisputaService } from '../services/finaliza-disputa.service';
import {DisputaService} from '../../disputas/services/disputas.service';
import { dadosAcordo } from '../model/dados-acordo.interface';
import { TitularComponent } from './dados-titular.component';
import {Routes, RouterModule, Router, ActivatedRoute} from '#angular/router';
#Component({
moduleId: module.id,
selector: 'detalhes',
templateUrl: `finaliza-disputa.component.html`,
providers: [FinalizaDisputaService]
})
export class FinalizaDisputaComponent implements OnInit {
public dados: dadosAcordo;
disputa:any;
public formDadosBancarios: FormGroup;
public submitted: boolean;
public events: any[] = [];
public servError: any;
public indice = 0;
public loading = false;
soma = 0;
public servSuccess: any;
#Input() e:boolean;
cpf_REGEXP = /^\d+$/;
constructor(private _fb: FormBuilder, private service:DisputaService, private finalizaAcordo: FinalizaDisputaService,
private route:ActivatedRoute, private router:Router) {}
ngOnInit() {
this.route.params.subscribe(params => {
let id = params['id'];
this.service
.buscaPorId(id)
.subscribe(disputa => {
this.disputa = disputa;
console.log(disputa.campanha);
console.log(this.disputa.propostas_realizadas);
},
erro => console.log(erro));
})
this.formDadosBancarios = this._fb.group({
id: [''],
termos_condicoes: [false, Validators.requiredTrue],
dados_titular: this._fb.array([
this.initTitular()
])
})
}
/**
* initTitular- Inicializa o grupo de formulário dinâmico e suas validações
* #returns ''
*/
initTitular() {
return this._fb.group({
titular: ['', [<any>Validators.required, <any>Validators.minLength(3)]],
cnpj: [''],
cpf: ['', <any>Validators.required],
data_nasc: ['', <any>Validators.required],
agencia: ['', <any>Validators.required],
banco: ['', <any>Validators.required],
conta: ['', <any>Validators.required],
tipo: ['', <any>Validators.required],
pessoa_juridica: [false],
valor_deposito: ['']
})
}
// this is where I receive e
recebeValidators(model: dadosAcordo, e: any) {
console.log("test", e);
const array = <FormArray>this.formDadosBancarios.get('dados_titular');
const cpf = array.at(this.indice).get("cpf");
const cnpj = array.at(this.indice).get('cnpj');
const data_nasc = array.at(this.indice).get('data_nasc');
const cpfCtrl: AbstractControl = this.formDadosBancarios.get(['dados_titular', this.indice, 'cpf']);
const pessoa_juridicaCtrl: AbstractControl = this.formDadosBancarios.get(['dados_titular', this.indice, 'pessoa_juridica'])
const cnpjCtrl: AbstractControl = this.formDadosBancarios.get(['dados_titular', this.indice, 'cnpj']);
const data_nascCtrl: AbstractControl = this.formDadosBancarios.get(['dados_titular', this.indice, 'data_nasc']);
const reqValidators: ValidatorFn[] = [Validators.required, Validators.pattern(this.cpf_REGEXP)];
if (e == true) {
data_nascCtrl.clearValidators();
cpfCtrl.clearValidators();
cnpjCtrl.setValidators(reqValidators);
}else{
cnpjCtrl.clearValidators();
cpfCtrl.setValidators(reqValidators);
data_nascCtrl.setValidators(reqValidators);
}
data_nascCtrl.updateValueAndValidity();
cpfCtrl.updateValueAndValidity();
cnpjCtrl.updateValueAndValidity();
}
But instead of printing false it is printing undefined. Can someone help me? thanks
It seems you're shadowing a class attribute with the function parameter "e" in the "recebeValidators" function.
The code:
console.log("test", this.e);
should actually be:
console.log("test", e);
To rule out the possibility of a possible casting error in the EventEmitter, try not reusing the parameter function. Example:
selectPessoaFisica(e:any) {
e = false;
this.modelChanged.emit(e)
}
could be rewritten as:
selectPessoaFisica() {
this.modelChanged.emit(false);
}
There's also an extra parameter in the receiving function:
This:
recebeValidators(model: dadosAcordo, e: boolean) {
Should be:
recebeValidators(e: boolean) {
You should type casting it
#Output() modelChanged = new EventEmitter<boolean>();
Also you are referring a wrong variable and you should be passing only one argument as it is in the parent component and remove the this keyword
recebeValidators(e: boolean) {
console.log("test", e);
}

Populate FormGroup with null value and

Getting error in Chrome Console: EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property 'applicationName' of null.
Model:
export class BasicInfoModel {
applicationName: string;
localDirectoryPath: string;
}
Controller emitting data to parent component, parent component there it is saved to services.
Controller:
import { Component, Output, OnInit, EventEmitter} from '#angular/core';
import { FormGroup, FormControl, REACTIVE_FORM_DIRECTIVES, Validators,
FormBuilder, FormArray}from "#angular/forms";
import { Observable } from "rxjs/Rx";
import { BasicInfoModel } from '../basicinfomodel';
import { BasicInfoService} from '../app.dev.basicinfo.service';
#Component({
selector: 'basic-info',
templateUrl: './basicInfo.html',
styleUrls: ['../../ComponentStyles.css'],
directives: [REACTIVE_FORM_DIRECTIVES]
})
export class BASIC_INFOComponent implements OnInit {
observableBasic: BasicInfoModel;
basicInfoForm: FormGroup;
#Output() basicInfoUpdate = new EventEmitter<JSON>();
#Output() basicInfoFormValid = new EventEmitter<Boolean>();
constructor(private formBuilder: FormBuilder, private BasicInfoService:
BasicInfoService) { }
onSubmit() {
debugger;
this.observableBasic;
this.basicInfoUpdate.emit(this.basicInfoForm.value);
}
ngOnInit() {
this.basicInfoForm = new FormGroup({
'applicationName': new FormControl('', Validators.required),
'localDirectoryPath': new FormControl('', Validators.required)
});
this.basicInfoForm.valueChanges.subscribe(data => console.log('form
changes', data));
this.BasicInfoService.currentBasicInfo
.subscribe(
(basic: BasicInfoModel) => {
this.observableBasic = basic;
});
(<FormGroup>this.basicInfoForm).setValue(this.observableBasic, { onlySelf: true });
}
}
What i want to achieve:
When i build my code, i want my formGroup should be populated with null values.
when i filled the data and saved it to behaviourSubject in my services, latter when i revisit the page my formGroup should be in sync with data services.
Modified the Controler by adding : (this.observableBasic != undefined)
ngOnInit() {
this.basicInfoForm = new FormGroup({
'applicationName': new FormControl('', Validators.required),
'localDirectoryPath': new FormControl('', Validators.required)
});
this.BasicInfoService.currentBasicInfo
.subscribe((basic: BasicInfoModel) => { this.observableBasic = basic; });
if (this.observableBasic != undefined) {
(<FormGroup>this.basicInfoForm).setValue(this.observableBasic, { onlySelf: true });
}
this.basicInfoForm.valueChanges.subscribe(data => console.log('form changes', data));
}

Categories

Resources