Dynamic Angular Forms on User Interaction - javascript

I have a dropdown that the user uses to switch between different Angular forms.
HTML
<form [formGroup]="evalForm">
<mat-form-field appearance="fill">
<mat-label>Select Analysis Group</mat-label>
<mat-select (selectionChange)="groupSelected($event)">
<mat-option *ngFor="let item of groupDropdown | async" [value]="item.value">{{item.text}}</mat-option>
</mat-select>
</mat-form-field>
<ng-container *ngFor="let groups of groupSections;">
<input type="text" [formControlName]="groups?.name">
</ng-container>
</form>
What should the Angular look like to get the reactive forms working when someone selects an item in the dropdown?
What groupSelected() currently does (basic non-working pseudo-code):
groupSelected(selectedItem) {
// 1) Grabs the FormControlNames from the DB
const formControlNamesList = getItemsFromDB(selectedItem);
// 2) Sets FormControlNames for DOM
// [{groups:{name: 'keyOne'}}, {groups:{name: 'keyTwo'}},{groups:{name: 'keyThree'}}]
this.groupSections = setGroupSections(formControlNamesList);
// 3) Creates a formControlNamesList Object in the form
// {"keyOne": FormControl, "keyTwo": FormControl, "keyThree": FormControl}
const formObj = formatForAngularForms(formControlNamesList);
// 4) Set the Reactive Form
this.evalForm = this.fb.group(new FormGroup(formObj));
}
formatForAngularForms(formControlNamesList) {
const formObj = {};
for(let i=0;i<formControlNamesList.length;i++) {
formObj[formControlNamesList[i].name] = new FormControl(null,[Validators.required]);
}
return formObj;
}
At the moment, the console explodes with errors about how it can't find the FormControlName and I suspect it has to do with the timing of when everything gets rendered, but I'm not entirely sure if that's it or not. I need the forms to render completely new forms each time a new value selected from the dropdown. The UI will always be dynamic and each time the dropdown changes the input FormControlNames could be different based on what the DB sends.
I've read that maybe FormArray might be something use but I can't find an example anywhere that matches what I'm looking to do.

Shouldn't you wait for the answers from backend before proceeding to build the form? If getItemsFromDB() returns an observable you could do async/await:
async groupSelected(selectedItem) {
const formControlNamesList = await getItemsFromDB(selectedItem);

Related

Why is my Angular FormGroup Valid when a control that is marked as required is empty?

I am trying to setup a basic form validation for a select.
In my constructor I have the following FormGroup
this.formSubmission = new FormGroup(
{
triggers: new FormControl(['', [ Validators.required]])
}
)
I have a button on the screen to test the validity of the FormGroup and it always comes back as valid even when there is nothing selected for "triggers".
When clicked the following code executes:
console.log('FormGroup Status: ' + this.formSubmission.status)
This will return VALID.
The HTML portion of this can be found here:
<div [formGroup]="formSubmission">
<mat-form-field appearance="fill">
<mat-label>Triggers</mat-label>
<mat-select
formControlName="triggers" multiple
>
<mat-option *ngFor="let trigger of triggersList" [value]="trigger.TRIGGER_NAME">{{trigger.TRIGGER_NAME}}</mat-option>
</mat-select>
</mat-form-field>
</div>
You defined triggers wrong.
triggers: new FormControl(['', [ Validators.required]])
will result in triggers: array.
First argument is the value, second is the validators, asyncValidators or options
what you probably meant to do is this:
triggers: new FormControl('', [ Validators.required])

Select/Unselect and get values of dynamically generated checkbox using ngModel directive in Angular

I have a set of data response from an API and dynamically generating checkboxes on my HTML file using DataView component of PrimeNG.
The goal is to have a functionality where I can select/unselect all checkbox via button click and store their values in an array, for example.
Here's what I have so far;
Component HTML
<p-dataView [value]="requestList" {...} >
<ng-template let-request pTemplate="listItem">
<p-checkbox
name="reqNo"
inputId="reqNo"
(click)="getCheckBoxValue()"
value="{{ request.requestNo }}"
[(ngModel)]="reqNo"
[ngModelOptions]="{ standalone: true }"
></p-checkbox>
</ng-template>
</p-dataview>
Main TS File
reqNo: any; reqNo is binded using ngModel.
Giving me arrays of values when consoled;
['R08000036', 'R08000002']
Each object in the API response looks like this;
{
requestNo: "R08000036",
requestBy: "SUPER_USER",
requestTs: "2021-02-18T04:27:05.710+0000",
collectTs: "2008-07-30T16:00:00.000+0000",
testReason: "After Visit",
noOfPrisoner: 2,
status: "Printed",
printTs: "2008-07-21T16:00:00.000+0000",
escortingOfficer: "00552",
}
getCheckBoxValue event handler;
getCheckBoxValue() {
console.log(this.reqNo);
}
I'm new to Angular and I think I'm using the ngModel wrong. Can someone please teach me?
You can select all values by setting a new value for reqNo by values from requestList.
selectAll() {
this.reqNo = this.requestList.map(item => item.requestNo);
}
unselectAll() {
this.reqNo = [];
}
Example

how to set the updated value in searched field by default after updation in angularjs ui-select directive?

I am facing problem in angularjs ui-select directive. It works fine, it shows me full data in dropdown. When I select a value from search field and want to update it the it is updated but it can't show by default in the search field. I have to manually search again to see the updated value. Let me paste the code...
Here is the angularjs code
$scope.consignee = [];
$http.get("get-consignee", {
}).then(function(response){
$scope.consignee = response.data;
//$scope.consignee.selected = $scope.consignee[0];
});
Here is the ui-select code
<ui-select ng-model="consignee.selected" theme="select2">
<ui-select-match placeholder="Select Consignee">
<% $select.selected.CONSIGNEE_NAME %>
</ui-select-match>
<ui-select-choices ng-repeat="e in consignee | filter: $select.search">
<div><% e.CONSIGNEE_NAME %></div>
</ui-select-choices>
</ui-select>
Let say I have 5 consignee names in dropdown like!
1. hamad
2. test2
3. yasin Gul
4. hamid
5. munir
So the problem is when I use this $scope.consignee.selected = $scope.consignee[0]; then at 0 index it gives me hamad name after updation even if I update test2 or yasin Gul it gives me hamad by default set in search field. I know I have 0,1,2,3,4 indexes but I want it dynamic not manual. And I want to set only that name which I update. If I update test2 so that it should give me test2 by default set in searched field after updation and same for yasin Gul etc.. Any help would be appreciated Thanks
cons_id is your selected database id.
$scope.consignee = [];
$http.get("get-consignee", {
}).then(function(response){
$scope.consignee = response.data;
var index = $scope.consignee.findIndex(x => x.CONSIGNEE_ID==cons_id); // use this
$scope.consignee.selected = $scope.consignee[index];
});

Can I use [formControl] without also needing [formGroup]?

I am using a dropdown in my UI, but when I come to use [formControl] I am getting the error thrown:
Cannot find control with unspecified name attribute
I am using ReactiveFormsModule in my app.module.ts.
I have Google'd and found that a solution is to use [formGroup] in the parent div, but I'm unsure of how to implement properly as I am defining my formControl from within a subscribe.
myComp.component.html
<div class="exceptional-status">
<select #exceptionalSelect id="excep-status-dropdown" [formControl]="select">
<option disabled value="default">--Exceptional statuses--</option>
<!-- other options here with *ngFor -->
</select>
</div>
myComp.component.ts
select: FormControl;
mySubscription() {
this.myService.myFunct.subscribe(res => {
this.select = new FormControl(res.status)
});
}
Yes, you can use FormControlDirective without FormGroup.
Angular expects FormControl to be defined:
select = new FormControl();
mySubscription() {
this.myService.myFunct.subscribe(res => {
this.select.setValue(res.status)
});
}
Yes, you can use it without FormGroup.
select = new FormControl();
For set the value:-
select.setValue('your data here');
To get the value:-
select.value
Why would you define the form control within the subscribe? My advice would be to structure the form skeleton outside the subscription and just populate the control using
mySubscription() {
this.myService.myFunct.subscribe(res => {
this.controls['select'].patchValue(res.status);
});
}

Angular 4 nested form update

I've got the following 'triple level' nested form:
FormGroup->ArrayOfFormGroups->FormGroup
Top level (myForm):
this.fb.group({
name: '',
description: '',
questions: this.fb.array([])
});
Nested form array element for 'questions':
this.fb.group({
priority: ['1'],
params: this.fb.group({parameter: ['']})
});
Nested form group element for 'params' is a key:value object of random length.
I'm using the following ngFor to go through elements:
<tr *ngFor="let questionConfigForm of myForm.controls.questions.controls; let i=index" [formGroupName]="i">
...
<div *ngFor="let param of objectKeys(questionConfigForm.controls.params.controls)" formGroupName="params">
<input type="text" [formControlName]="param">
I've got the following behavior:
When I'm updating any of the fields on first two form levels I could instantly see changes in corresponding form controls values with {{myForm.value | json}}.
But if I input something in one of 'params' controls I couldn't see any changes in myForm values, but the form data for 'params' controls will be updated if I will make any changes in corresponding 'questions' form.
For me it looks like 'param' form control receives input data, but doesn't trigger some update event, and I don't know how to fix that, except writing my own function to react on (change) and patchValue in form..
So my question is how to make 'params' controls update myForm without that strange behavior?
UPD:
initQuestionConfig() {
return this.fb.group({
priority: ['1'],
params: this.fb.group({parameter: ['']}),
});
}
addQuestionConfig() {
const control = <FormArray>this.myForm.controls['questions'];
const newQuestionCfg = this.initQuestionConfig();
control.push(newQuestionCfg);
}
Finally the problem is solved.
The root of this issue was the way I've cleaned up already existing 'params'.
To remove all parameters from 'questions' I used the following code:
const control = <FormArray>this.myForm.controls['questions'];
control.controls[index]['controls'].params = this.fb.group([]);
And the reason of those glitches was this new 'fb.group' instance.
Now I'm removing params one by one, keeping original formGroup instance and it works as expected:
const control = <FormArray>this.myForm.controls['questions'];
const paramNames = Object.keys(control.controls[index]['controls'].params.controls);
for (let i = 0; i < paramNames.length; i++) {
control.controls[index]['controls'].params.removeControl(paramNames[i]);
}
#MilanRaval thanks for your time again :)
Try this: Give formArrayName and formGroupName like below...
<div formArrayName="testGroup">
<div *ngFor="let test of testGroup.controls; let i=index">
<div [formGroupName]="i">
<div class="well well-sm">
<label>
<input type="checkbox" formControlName="controlName" />
</div>
</div>
</div>
</div>

Categories

Resources