I am using Reactive Forms to create a page for managing roles and permissions in my application. There are multiple tables of checkboxes that turn on or off a permission on a role, and I am trying to dynamically create these elements using *ngFor. The problem is, my form element only has a boolean value (on or off) and there is corresponding metadata that is needed (display name, list of claims, etc.) that I need to retrieve to display the element properly. My problem is, as I am looping through the form control collection, I need to match it up to the view model (essentially need to get a variable set in my html template for both the model and the form control.
Here is an example of what the page looks like:
here is my form builder:
this.settingsForm = this.fb.group({
roleName: this.exampleRole.name,
dashboard: '',
settingsPermissions: this.fb.array(this.settingsPermissions.map(perm => this.fb.group({
name: perm.title,
permission: perm.val(this.exampleRole.permissions),
}))),
customerProfilePermissions: this.fb.group({
//accessProfiles: {value: true, description:"Some test description", displayName: "Access Customer Profiles" },
accessProfiles: true,
accessPII: false,
editProfiles: false,
linkProfiles: false,
my example definition for the settings permission object:
export class PermissionConfiguration {
title!: string;
permissionClaims: string[] = [];
description: string;
}
and an example of what my template looks like:
<div *ngIf="settingsForm.get('customerProfilePermissions.accessProfiles').value">
<div class="row">
<div class="col-3 col-xl-2">Access To PII </div>
<div class="col-3 col-xl-2"><k-checkbox formControlName="accessPII"></k-checkbox></div>
<div class="col-3 col-xl-2">Ability to view customer personally identifiable information.</div>
</div>
<div class="row">
<div class="col-3 col-xl-2">Edit Profiles </div>
<div class="col-3 col-xl-2"><k-checkbox formControlName="editProfiles"></k-checkbox></div>
<div class="col-3 col-xl-2">Ability to edit certain information on the customer profile tab. Editable fields are defined on a per-client basis during implementation.</div>
</div>
<div class="row">
<div class="col-3 col-xl-2">Link Related Profiles </div>
<div class="col-3 col-xl-2"><k-checkbox formControlName="linkProfiles"></k-checkbox></div>
<div class="col-3 col-xl-2">Ability to add/remove related profiles in the top right of each customer profile.</div>
</div>
what I need is to be able to get the PermissionConfiguration object from the component along with the form control. If I can do that, then I can replace the name and description fields and make the form dynamic.
In the settings Permissions section (different model object) I did the following and it works but is highly inefficient:
<tr formArrayName="settingsPermissions"
*ngFor="let info of settingsForm.get('settingsPermissions')['controls']; let i = index;">
<ng-container [formGroupName]="i">
<td>{{ getPermModel(info.value.name).title }}</td>
<td><k-checkmark-radio formControlName="permission" valueName="Hide" [groupName]="info.value.name" ></k-checkmark-radio></td>
<td><k-checkmark-radio formControlName="permission" valueName="View" [groupName]="info.value.name"></k-checkmark-radio></td>
<td><k-checkmark-radio formControlName="permission" valueName="Edit" [groupName]="info.value.name"></k-checkmark-radio></td>
<td>{{ getPermModel(info.value.name).description}} </td>
</ng-container>
</tr>
Update
GetPermModel Implementation:
getPermModel(name:string): SettingsPermission {
let model = this.settingsPermissions.find(p => p.title == name);
return model;
}
I can imaging two ways to improve it:
this.fb.array(this.settingsPermissions.map(perm => this.fb.group({
name: perm.title,
permission: perm.val(this.exampleRole.permissions),
permModel: this.fb.group({
value: this.getPermModel(perm.title)),
disabled: !this.isResetPassword
}),
}))),
and use it in the HTML
<tr formArrayName="settingsPermissions"
*ngFor="let info of settingsForm.get('settingsPermissions')['controls']; let i = index;">
<ng-container [formGroupName]="i">
<td>{{ info.value.permModel.title }}</td>
<td><k-checkmark-radio formControlName="permission" valueName="Hide" [groupName]="info.value.name" ></k-checkmark-radio></td>
<td><k-checkmark-radio formControlName="permission" valueName="View" [groupName]="info.value.name"></k-checkmark-radio></td>
<td><k-checkmark-radio formControlName="permission" valueName="Edit" [groupName]="info.value.name"></k-checkmark-radio></td>
<td>{{ info.value.permModel.description}} </td>
</ng-container>
</tr>
The form value would contain the permModel
field, which might be not desirable.
getPermModel
@Pipe({
name: 'myCustomPipe',
pure: true <----- here (default is `true`)
})
export class MyCustomPipe {
constructor(private settingsPermissions) { }
transform(name:string): SettingsPermission {
let model = this.settingsPermissions.find(p => p.title == name);
return model;
}
}
settingsPermissions
might be also a pipe param if it's not a good candidate to be injectable.