reactive forms radio button default value checked - html

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 */ });
},

Related

Create common input field in Angular

I have created common input field which can be usable across app and it will work with or without reactive form.
For e.g.: I have created common input angular component but it works with reactive form only as it has formGroup and formControlName.
input.html:
<div class="form-control" *ngIf="isRequired" [formGroup]="parentForm">
<label class="label">
{{labelText}}
</label>
<input [type]="inputType" class="input" [control]="control" [formControlName]="formControlNameText" [placeholder]="placeholderText">
</div>
input.ts:
import { Component, OnInit, Input } from '#angular/core';
#Component({
selector: 'app-input',
templateUrl: './input.component.html',
styleUrls: ['./input.component.scss'],
})
export class InputComponent implements OnInit {
#Input() parentForm: any;
#Input() labelText: string;
#Input() inputType: string = "text";
#Input() formControlNameText: string;
#Input() placeholderText: string;
#Input() isRequired: boolean = false;
#Input() requiredMsg: string;
#Input() maxlengthMsg: string;
#Input() control: any;
#Input() type: string;
constructor() { }
ngOnInit() { }
}
Call from one of my form Page:
<app-input parentForm="surveyResponseForm" labelText="test" inputType="text" placeholderText="placeholder"
formControlNameText="authorName" control="" isRequired=true id="authorName">
</app-input>
How do I use this common input if I want to use this without form?
I mean how do I use this selector: app-input in a component which doesn't have any form.
You could add an #Input() property to your component, for example useInForm: boolean, and check its value in your template. If useInForm is true, you would use the [formGroup] and formControlName properties, otherwise you would use a regular element without those properties example in the withoutFormTemplate.
<div class="form-control" *ngIf="isRequired && useInForm; else withoutFormTemplate" [formGroup]="parentForm">
<label class="label">
{{labelText}}
</label>
<input [type]="inputType" class="input" [control]="control" [formControlName]="formControlNameText" [placeholder]="placeholderText">
</div>
<ng-template #withoutFormTemplate>
<input [(ngModel)]="control" [type]="inputType" class="input" [placeholder]="placeholderText">
<ng-template>
I solve more or less same problem by creating a FormGroup. It's not easiest solution, but that working on multiple scenarios.
If not, maybe that give you some clues how to solve your problem...
Form component ts
// Reactive Forms
form: FormGroup;
constructor(private formBuilder: FormBuilder) { }
ngOnInit() {
// Form structure and validators
this.form = this.formBuilder.group({
'user' : this.formBuilder.group({
'username' : ['', Validators.required],
'email' : ['', [Validators.required, Validators.email]]
}),
'identity' : this.formBuilder.group({
'firstname' : ['', Validators.required],
'lastname' : ['', Validators.required],
'address' : this.formBuilder.group({
'street' : ['', Validators.required],
'city' : ['', Validators.required],
})
})
});
}
onSubmit() {
// Get object with same structure as form but only with values
console.log(this.form.value);
alert('Form is ' + (this.form.invalid ? 'invalid' : 'valid'));
}
Form component html
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<form-text [formGroupParent]="form.get(['user'])"
[formGroupControlName]="'username'">
</form-text>
<form-text [formGroupParent]="form.get(['user'])"
[formGroupControlName]="'email'">
</form-text>
<hr>
<form-text [formGroupParent]="form.get(['identity'])"
[formGroupControlName]="'firstname'">
</form-text>
<form-text [formGroupParent]="form.get(['identity'])"
[formGroupControlName]="'lastname'">
</form-text>
<hr>
<form-text [formGroupParent]="form.get(['identity','address'])"
[formGroupControlName]="'street'">
</form-text>
<form-text [formGroupParent]="form.get(['identity','address'])"
[formGroupControlName]="'city'">
</form-text>
<button type="submit">Submit</button>
</form>
Custom input component ts (form-text)
// Needed to bind formControlName
#Input() formGroupParent: FormGroup;
#Input() formGroupControlName: string;
// FormControl store validators
control: FormControl;
ngOnInit() {
// Fetch Form control (validator) from FormGroup parent
this.control = <FormControl>this.formGroupParent.get(this.formGroupControlName);
}
Custom input component html (form-text)
<ng-container [formGroup]="formGroupParent">
<label>{{formGroupControlName}}</label>
<input type="text" formControlName="{{formGroupControlName}}">
</ng-container

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?

Angular 8+ two way binding textarea in reactive forms

I want to bind my textarea input.
HTML:
<form [formGroup]="formGroup">
<custom-element formControlName="firstName"</custom-element>
<textarea formControlName="question" rows="6" placehoder"some text"></textarea>
</form>
TS:
formGroup = this.formBuilder.group({
firstName: [{value: null, disabled: true}],
question:[null]
});
get firstNameControl(): AbstractControl {return this. formGroup.get('firstName');}
get questionControl(): AbstractControl {return this. formGroup.get('question');}
dosomething(): void {
// fill firstname form api work fine
// I can read the value with this.firstNameControl.value
}
Tried to bind textarea but no working solution yet.
message: string;
this.questionControl.valueChanges.subscribe(
val => {
this.message= val;
console.log('questiontext' + this.message);
}
);
or
this.questionControl.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
tap(message => this.message = message),
tap(data => console.log(data))
).subscribe();
if I add [(ngModel)]="message" to the textarea and remove formCotroleName it works.
But than you are combining two way of presenting the form which is not the way to go.
How can I two way bind a textarea or other form element with reactive forms?

Update #f="ngForm" variable after editing profile

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
);

Angular Radio Buttons form with unknown number of elements

I am new to Angular and I have an issue with the radio buttons.
I have an array of strings which I want to use to create a form with radio buttons. I do not know the length or the content of the array - the values are taken from an external service.
How can I do this using a form builder in my Angular Component and in html file? Can it be something like this?
question-dto.ts
export class QuestionDto {
questionText: string;
questionOptions: string[];
}
quiz.component.ts
question: QuestionDto = new QuestionDto();
questionOptionsForm: any;
constructor(private quizService: QuizService,
private formBuilder: FormBuilder) { }
ngOnInit() {
this.initForm();
}
initForm() {
this.questionOptionsForm = this.formBuilder.group({
//INIT RADIO BUTTONS HERE
})
}
quiz.component.html
<div>
<p>
Answers
</p>
<form *ngIf="questionOptionsForm">
<div *ngFor="let option of question.questionOptions">
<label>
<input type="radio" class="form-control">
{{option}}
</label>
</div>
</form>
</div>
You should try FormArray https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/
code would look like:
initForm() {
this.questionOptionsForm = this.formBuilder.group({
options: this.formBuilder.array([this.createOption()])
});
}
createOption():FormGroup {
return this.formBuilder.group({
name: '',
description: ''
});
}