Update #f="ngForm" variable after editing profile - html

I`m using Angular 7 and reactive forms to create Edit Profile page.
I have all my input values filled in from database. If I want to change first name and last name for example, clicking the update button, everything is looking fine, all fields are updated.
The problem is that if I want to update again only the first name, after clicking the update button, last name has intial value.
So, the problem is that my variable #f="ngForm" is keeping old values (first values) and somehow after update process, #f variable has again first values.
<form [formGroup]="patientEditForm" #f="ngForm" (ngSubmit)="editPatientProfile(f)">
editPatientProfile(f: NgForm ) {
this.submitted = true;
this.isRequesting = true;
this.errors = '';
if (f.valid) {
this.userService.editPatientProfile(this.patientId,
this.patient.nin,
f.value.firstName,
f.value.lastName,
this.email,
f.value.password,
f.value.city,
f.value.country,
f.value.birthdate,
f.value.phoneNumber)
.finally(() => this.isRequesting = false)
.subscribe(
result => {
if (result) {
this.router.navigate(['/patient/account']);
localStorage.setItem('displayMessage1', "true");
window.location.reload();
}
},
errors => this.errors = errors);
}
}
<input type="email" value="{{patient.email}}" disabled class="form-control mb-2 mr-sm-2 mb-sm-0">
this.patientEditForm = this.formBuilder.group({
lastName: ['Test', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]],
firstName: ['Test', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]],
phoneNumber: ['0745119974', [Validators.required, Validators.pattern("[0-9]+")]],
birthdate: ['1996-02-10', [Validators.required,this.validateDOB.bind(this)]],
city: ['Iasi', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]],
password: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(35), this.validatePasswordConfirmation.bind(this)]],
country: ['Romania', [Validators.required, Validators.minLength(3), Validators.maxLength(30), Validators.pattern("[a-zA-Z]+")]]
});

Finally, I solved the problem by setting the new proprieties in subscrive event:
private getPatient() {
this.userService.getPatient(this.patientId)
.subscribe((patient: PatientProfile) => {
this.patient = patient;
this.patientEditForm.controls['lastName'].setValue(patient.lastName);
this.patientEditForm.controls['firstName'].setValue(patient.firstName);
this.patientEditForm.controls['phoneNumber'].setValue(patient.phoneNumber);
this.patientEditForm.controls['birthdate'].setValue(patient.birthdate);
this.patientEditForm.controls['city'].setValue(patient.city);
this.patientEditForm.controls['country'].setValue(patient.country);
},
errors => this.errors = errors
);

Related

Angular reactive form cannot find control with path

Currently, I'm creating a reactive form:
this.entryService.getEntryObservable(weekNumber).subscribe(entries => {
this.entriesArr = entries;
this.entriesReceived = true;
this.populateEntries();
}, error => {
this.entriesErrMsg = error;
});
populateEntries() {
this.entriesForm = this.fb.group({
entries: this.fb.array(this.entriesArr.map(entry => this.fb.group({
type: [entry.type, Validators.required],
hours: [entry.hours, Validators.required],
tasks: [entry.tasks, Validators.required],
}, {updateOn: 'blur'})))
});
}
Now I've added a getter which returns the entries:
get entries() {
return (this.entriesForm.get('entries') as FormArray).controls;
}
This getter is called inside my HTML:
<form [formGroup]="entriesForm" *ngIf="entriesReceived">
<div *ngFor="let entry of entries; let i = index;" [formGroupName]="i">
<mat-form-field appearance="fill">
<mat-label>Stunden...</mat-label>
<input matInput type="number" placeholder="8" min="1" step="1" formControlName="hours">
<span matSuffix>h</span>
</mat-form-field>
.....
</div>
</form>
But somehow I'm getting this error here and I really don't know what I'm doing wrong...
Error: Cannot find control with path: '4 -> hours'
When I log the entries return value I'm getting this structure in the console:
Any suggestions?

reactive forms radio button default value checked

I'd like the radio button to have a default value as checked.
I have tried the following without any success.
form: FormGroup;
gifts: IGift;
this.form = this.fb.group({
phone: ['', [Validators.required, Validators.pattern('^[0][5][0-9]{8}$')]],
email: ['', [CustomValidators.email]],
k_gift: ['', [Validators.required, CustomValidators.gt(0)]],
});
this._giftService.getUserGifts()
.subscribe(g => {
this.gifts = g;
},
error => {
if (error.includes("401")) {
localStorage.removeItem("token");
location.reload();
})
<input type="radio" [value]="gifts.k_gift" aria-checked="false" attr.id="gift{{gift.k_gift}}" formControlName="k_gift" >
<label class='control-label' attr.for="gift{{gift.k_gift}}">
{{gift.desc_k_gift}}
</label>
The value inserted to gifts.k_gift is 1. I have tried [value] = 1 , and tried also k_gift: [1, [Validators.required, CustomValidators.gt(0)]],
Also tried checked in the html input tag.
None worked for me.
How can I set the default of this radio button as checked?
You're using a model-driven form. Instead of using the [value] input in the template, set the model accordingly:
this._giftService.getUserGifts()
.subscribe(g => {
// here
this.gifts = g;
this.form.patchValue({ k_gift: /* insert desired value */ });
},

Trying to access single document from Firestore in Typescript and pass it to HTML

I'm trying to access a single document in my Firestore (the one who has message "b"). I'm able to find the correct document and print it to the console log, but when I try assigning it to a public variable, one which will be accessed in HTML as default values for the table, the console tells me the variable is undefined, and or that it can't be set to doc.data() contents.
I've tried using the where() function, as well as mergemap() but I'm getting errors in my code editor (for mergemap--Property 'mergeMap' does not exist on type 'Observable<{}>'). I've also tried looping through items (which holds all the documents and I AM able to access in my HTML) but I can't figure out a way to get the length of the Observable. I've also tried changing the type of defaultdoc to no avail.
Here's what I've got so far
public defaultdoc: Array<any>;
public items: Observable<any[]>;
constructor(private data: DataService, private fb: FormBuilder, private afs: AngularFirestore) {
}
ngOnInit() {
this.myForm = this.fb.group({
title: ['', Validators.required],
message:['', Validators.required]
})
//this.myForm.valueChanges.subscribe(console.log);
let inputString = "b";
const collection: AngularFirestoreCollection<Item> = this.afs.collection('postreply');
this.items = this.afs.collection('postreply').valueChanges();
this.afs.collection("postreply").get().toPromise().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
//console.log(doc.id, " => ", doc.data());
console.log(doc.data().message)
if(doc.data().message == inputString){
this.defaultdoc.push(doc.data());
console.log(this.defaultdoc)
}
});
});
console.log(this.defaultdoc)
}
Here's the HTML
<td><input type="text" class="form-control" formControlName = message value = {{defaultdoc.message}}/></td>
<td><input type="text" class="form-control" formControlName = title value = {{defaultdoc.title}}/></td>
The default values should appear in the two table rows created in the HTML.
I think your "this" is not pointing out the variable you are using in HTML.
Try using self like this:
public defaultdoc: Array<any>;
public items: Observable<any[]>;
constructor(private data: DataService, private fb: FormBuilder, private afs: AngularFirestore) {
}
ngOnInit() {
this.myForm = this.fb.group({
title: ['', Validators.required],
message:['', Validators.required]
})
//this.myForm.valueChanges.subscribe(console.log);
let inputString = "b";
const collection: AngularFirestoreCollection<Item> = this.afs.collection('postreply');
this.items = this.afs.collection('postreply').valueChanges();
let self = this;
this.afs.collection("postreply").get().toPromise().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
//console.log(doc.id, " => ", doc.data());
console.log(doc.data().message)
if(doc.data().message == inputString){
self.defaultdoc.push(doc.data());
console.log(self.defaultdoc)
}
});
});
console.log(this.defaultdoc)
}
Hope it works!

Angular 6 Forms TypeError: Cannot read property 'valid' of null

I have a simple form with two FormControls, where I subscribe to all valueChanges. But when checking for errors I get this error:
Note that I am first able to log the input, but afterward its null.
Typescript
export class Component {
#Input() product: Product;
form: FormGroup;
errors: any;
messages: any;
constructor(
private fb: FormBuilder,
) { }
ngOnInit(): void {
this.setupMessages();
this.form = this.fb.group({
name: ['', [
Validators.required,
Validators.minLength(3),
Validators.maxLength(100),
]],
description: ['', [
Validators.maxLength(10000),
]],
});
this.form.patchValue(this.product);
this.form.valueChanges.subscribe(data => this.checkErrors());
}
private checkErrors(): void {
for (let field in this.errors) {
this.errors[field] = '';
let input = this.form.get(field);
// I am able to log input
// but input.valid is null
if (!input.valid) {
for (let error in input.errors) {
this.errors[field] = this.messages[field][error];
}
}
}
}
private setupMessages(): void {
this.messages = {
name: {
required: 'Please give your product an awesome name',
minlength: 'The name should be longer than 3 characters',
maxlength: 'Keep your product name under 100 characters',
},
description: {
maxlength: 'Your description is to long',
},
}
this.errors = {
name: '',
descripton: '',
}
}
}
HTML
<form [formGroup]="form">
<dy-input
[required]="true"
[placeholder]="'Give your product an awesome name'"
formControlName="name"
[error]="errors.name"
[maxlength]="100"
>
Name
</dy-input>
<dy-textarea
[placeholder]="'Pointing out details helps to improve sales'"
[error]="errors.description"
formControlName="description"
[height]="'480px'"
[maxlength]="10000"
>
Description
</dy-textarea>
</form>
As you can see, I am using my own custom Form Controls. But I'm quite sure, that the issue is not caused by them, because of the fact, that they don't cause any errors in other forms.
The second time around, your input is null, because of a typo in your errors.
private setupMessages(): void {
this.messages = {
name: {
required: 'Please give your product an awesome name',
minlength: 'The name should be longer than 3 characters',
maxlength: 'Keep your product name under 100 characters',
},
description: {
maxlength: 'Your description is to long',
},
}
this.errors = {
name: '',
descripton: '',
}
}
Note, in this.errors, you have an error key called descripton, but your formgroup key is description (spelled correctly).
You're missing an i in the this.errors version.
Also, in addition to my comment above, maybe worth editing your condition to be if (input && !input.valid) to keep it safe :)

how to get a specific field value from an object retrieved and bind it to a property in the component TypeScript

Hello i have a type script code that populate options from a back end service ,Now how to perform 2 way data binding on or
,And how to get a specific field value from the object retrieved
for Example the Objects i retrieved each one of them is in json format like this :
countryCode:"TUR"
countryId:185
countryName:"Turkey"
countryPhoneCode:"90"
__proto__:Object
my html is like this :------
<div class="form-group ">
<label class="control-label" for="countryCode">Country</label>
<select class="form-control" id="countryCode"formControlName="countryCode">
<option *ngFor="let country of countryList"
[attr.value]="country.countryCode" [selected]="country.countryCode === viewCountryCode">
{{country.countryName}}</option>
</select>
</div>
here is some of my type script:---
registrationForm: FormGroup;
username: AbstractControl;
useremail: AbstractControl;
commercialWebSiteLink: AbstractControl;
corporateWebSiteLink: AbstractControl;
countryCode: String = "jo";
viewCountryCode: string = "jo";
createSignupForm() {
this.registrationForm = this.builder.group({
username: ['', Validators.compose([
Validators.required,
UserNameValidator.userNameRange,
UserNameValidator.OnlyAlphabets
])],
useremail: ['', Validators.compose([
Validators.required,
EmailValidator.mailFormat,
EmailValidator.domainCheckFormat,
EmailValidator.mailLength,
EmailValidator.specialCharacters
])],
countryCode: [''],
commercialWebSiteLink: ['', Validators.compose([
Validators.required,
UrlValidator.urlFormat,
])],
corporateWebSiteLink: ['', Validators.compose([
Validators.required,
UrlValidator.urlFormat,
])],
merchantType: ['PSP']
});
this.username = this.registrationForm.controls['username'];
this.useremail = this.registrationForm.controls['useremail'];
this.commercialWebSiteLink = this.registrationForm.controls['commercialWebSiteLink'];
this.corporateWebSiteLink = this.registrationForm.controls['corporateWebSiteLink'];
this.regestrationErrorMessage = " ";
}
submitsignup(RegistrationForm: any) {
if (!RegistrationForm.errors && RegistrationForm.valid) {
if ((<HTMLInputElement>document.getElementById("termsandConditons")).checked) {
this.isAcceptTerms = false;
} else {
this.isAcceptTerms = true;
}
this.homeService.signUpMarchent(RegistrationForm).subscribe(
response => {
console.log(response);
if (response.success) {
this.signUpDone == true;
} else {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.' + response.code);
if (this.regestrationErrorMessage == '') {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.errGeneralError');
}
}
},
error => {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.errGeneralError');
}
);
}
}
Now i want in my type script to retrieve Country Id from the object i retrieved , And I want to save it in a type script variable when i submit the form ,so i can then submit it to the back end instead of country code
Any Help will please ,
this is how i solved it
<div class="form-group ">
<label class="control-label" for="countryId">Country</label>
<select class="form-control" id="countryId" formControlName="countryId">
<option *ngFor="let country of countryList" [attr.value]="country.countryId" [selected]="country.countryCode === viewCountryCode">
{{country.countryName}}</option>
</select>
</div>
I made a new form control named in the type script class ,countryId: 1 in the createSignupForm().