Skip to content

Commit 0d670dd

Browse files
authored
AAE-27107 Improve repeatable section widget (#11336)
* AAE-27107 Improve logic * AAE-27107 Add tests * AAE-27107 Fix logic * AAE-27107 Fix test * AAE-27107 Fix updateForm logic
1 parent 54f20b7 commit 0d670dd

File tree

11 files changed

+385
-199
lines changed

11 files changed

+385
-199
lines changed

lib/core/src/lib/form/components/form-renderer.component.html

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,24 @@
8181
<div
8282
class="adf-grid-list-container"
8383
[class.adf-grid-list-container-multiple]="hasMultipleRows"
84-
>
85-
<h4 class="adf-grid-list-container-label">{{ 'FORM.FORM_RENDERER.ROW_LABEL' | translate: {number: rowIndex + 1} }}</h4>
84+
[class.adf-grid-list-container-disabled]="currentRootElement.field.readOnly"
85+
>
86+
<div class="adf-grid-list-row">
87+
<span class="adf-grid-list-row-label">{{ 'FORM.FORM_RENDERER.ROW_LABEL' | translate: {number: rowIndex + 1} }}</span>
88+
89+
@let shouldDisplayRemoveRowButton = !currentRootElement.field.rows[rowIndex].isInitial || (currentRootElement.field.rows[rowIndex].isInitial && currentRootElement.field.params.allowInitialRowsDelete);
90+
@if (shouldDisplayRemoveRowButton) {
91+
<button
92+
mat-icon-button
93+
class="adf-grid-list-row-remove-button"
94+
[disabled]="currentRootElement.field.readOnly"
95+
[matTooltip]="'FORM.FORM_RENDERER.DELETE_ROW' | translate"
96+
(click)="displayDialogToRemoveRow(currentRootElement.field, rowIndex)"
97+
>
98+
<mat-icon>close</mat-icon>
99+
</button>
100+
}
101+
</div>
86102
<section class="adf-grid-list-column-view">
87103
@for (column of row.columns; track $index) {
88104
<div
@@ -100,17 +116,6 @@ <h4 class="adf-grid-list-container-label">{{ 'FORM.FORM_RENDERER.ROW_LABEL' | tr
100116
}
101117
</div>
102118
}
103-
104-
@let shouldDisplayRemoveRowButton = !currentRootElement.field.rows[rowIndex].isInitial || (currentRootElement.field.rows[rowIndex].isInitial && currentRootElement.field.params.allowInitialRowsDelete);
105-
@if (shouldDisplayRemoveRowButton) {
106-
<button
107-
mat-icon-button
108-
class="adf-grid-list-remove-row-button"
109-
(click)="displayDialogToRemoveRow(currentRootElement.field, rowIndex)"
110-
>
111-
<mat-icon>close</mat-icon>
112-
</button>
113-
}
114119
</section>
115120
</div>
116121
}

lib/core/src/lib/form/components/form-renderer.component.scss

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,28 +98,48 @@
9898
padding-right: 3px;
9999
}
100100

101-
&-remove-row-button {
102-
margin-top: 20px;
103-
104-
#{ms.$mat-icon} {
101+
&-row {
102+
display: flex;
103+
flex-direction: row;
104+
align-items: center;
105+
justify-content: space-between;
106+
107+
&-remove-button {
108+
padding: 0;
109+
width: 30px;
110+
height: 30px;
105111
display: flex;
106-
justify-content: center;
107112
align-items: center;
108-
font-size: 20px;
113+
justify-content: center;
114+
115+
#{ms.$mat-icon} {
116+
display: flex;
117+
justify-content: center;
118+
align-items: center;
119+
font-size: 18px;
120+
}
109121
}
110122
}
111123

112124
&-container {
113-
padding: 0 10px;
114-
115-
&-label {
116-
margin: 5px 0 5px -10px;
117-
}
125+
padding: 0 15px;
118126

119127
&-multiple {
120128
border-bottom: 1px solid rgba(0, 0, 0, 0.54);
121129
margin-bottom: 25px;
122130
}
131+
132+
&-disabled {
133+
&.adf-grid-list-container-multiple {
134+
border-bottom: 1px solid
135+
var(--mdc-text-button-disabled-label-text-color, color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent));
136+
}
137+
138+
.adf-grid-list-row-label {
139+
color: var(--mdc-text-button-disabled-label-text-color, color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent));
140+
cursor: default;
141+
}
142+
}
123143
}
124144
}
125145

lib/core/src/lib/form/components/form-renderer.component.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,7 @@ describe('Form Renderer Component', () => {
921921
expect(row).toBeTruthy();
922922

923923
const removeRowButton = testingUtils.getByCSS(
924-
'#field-RepeatableSection0tbw2y-container .adf-grid-list-container .adf-grid-list-remove-row-button'
924+
'#field-RepeatableSection0tbw2y-container .adf-grid-list-container .adf-grid-list-row-remove-button'
925925
);
926926

927927
expect(removeRowButton).toBeTruthy();
@@ -938,7 +938,7 @@ describe('Form Renderer Component', () => {
938938
expect(row).toBeTruthy();
939939

940940
const removeRowButton = testingUtils.getByCSS(
941-
'#field-RepeatableSection0tbw2y-container .adf-grid-list-container .adf-grid-list-remove-row-button'
941+
'#field-RepeatableSection0tbw2y-container .adf-grid-list-container .adf-grid-list-row-remove-button'
942942
);
943943

944944
expect(removeRowButton).toBeFalsy();

lib/core/src/lib/form/components/form-renderer.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { FormSectionComponent } from './form-section/form-section.component';
3232
import { DecimalRenderMiddlewareService } from './middlewares/decimal-middleware.service';
3333
import { MatDialog } from '@angular/material/dialog';
3434
import { ConfirmDialogComponent } from '../../../lib/dialogs/confirm-dialog/confirm.dialog';
35+
import { MatTooltipModule } from '@angular/material/tooltip';
3536

3637
@Component({
3738
selector: 'adf-form-renderer',
@@ -63,7 +64,8 @@ import { ConfirmDialogComponent } from '../../../lib/dialogs/confirm-dialog/conf
6364
NgClass,
6465
HeaderWidgetComponent,
6566
FormSectionComponent,
66-
RepeatWidgetComponent
67+
RepeatWidgetComponent,
68+
MatTooltipModule
6769
],
6870
encapsulation: ViewEncapsulation.None
6971
})

lib/core/src/lib/form/components/widgets/core/form-field.model.spec.ts

Lines changed: 172 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,61 +1272,121 @@ describe('FormFieldModel', () => {
12721272
let form: FormModel;
12731273
let field: FormFieldModel;
12741274

1275+
const fields = {
1276+
'1': [
1277+
{
1278+
id: 'Text0wwp7n',
1279+
name: 'Text',
1280+
type: 'text',
1281+
readOnly: false,
1282+
required: false,
1283+
colspan: 1,
1284+
rowspan: 1,
1285+
placeholder: null,
1286+
minLength: 0,
1287+
maxLength: 0,
1288+
regexPattern: null,
1289+
visibilityCondition: null,
1290+
params: {
1291+
existingColspan: 1,
1292+
maxColspan: 2
1293+
}
1294+
}
1295+
],
1296+
'2': [
1297+
{
1298+
id: 'Integer0rzkwq',
1299+
name: 'Integer',
1300+
type: 'integer',
1301+
readOnly: false,
1302+
colspan: 1,
1303+
rowspan: 1,
1304+
placeholder: null,
1305+
minValue: null,
1306+
maxValue: null,
1307+
required: false,
1308+
visibilityCondition: null,
1309+
params: {
1310+
existingColspan: 1,
1311+
maxColspan: 2
1312+
}
1313+
}
1314+
]
1315+
};
1316+
1317+
const fieldsDisabled = {
1318+
'1': [
1319+
{
1320+
id: 'Text0wwp7n',
1321+
name: 'Text',
1322+
type: 'text',
1323+
readOnly: true,
1324+
required: false,
1325+
colspan: 1,
1326+
rowspan: 1,
1327+
placeholder: null,
1328+
minLength: 0,
1329+
maxLength: 0,
1330+
regexPattern: null,
1331+
visibilityCondition: null,
1332+
params: {
1333+
existingColspan: 1,
1334+
maxColspan: 2
1335+
}
1336+
}
1337+
],
1338+
'2': [
1339+
{
1340+
id: 'Integer0rzkwq',
1341+
name: 'Integer',
1342+
type: 'integer',
1343+
readOnly: false,
1344+
colspan: 1,
1345+
rowspan: 1,
1346+
placeholder: null,
1347+
minValue: null,
1348+
maxValue: null,
1349+
required: false,
1350+
visibilityCondition: null,
1351+
params: {
1352+
existingColspan: 1,
1353+
maxColspan: 2
1354+
}
1355+
}
1356+
]
1357+
};
1358+
1359+
const json = {
1360+
id: 'RepeatableSection0tbw2y',
1361+
name: 'Repeatable Section',
1362+
type: 'repeatable-section',
1363+
tab: null,
1364+
params: {
1365+
initialNumberOfRows: 2,
1366+
allowInitialRowsDelete: true,
1367+
maxNumberOfRows: 5
1368+
},
1369+
numberOfColumns: 2,
1370+
fields
1371+
};
1372+
1373+
const jsonDisabled = {
1374+
id: 'RepeatableSection0tbw2y',
1375+
name: 'Repeatable Section',
1376+
type: 'repeatable-section',
1377+
tab: null,
1378+
params: {
1379+
initialNumberOfRows: 2,
1380+
allowInitialRowsDelete: true,
1381+
maxNumberOfRows: 5
1382+
},
1383+
numberOfColumns: 2,
1384+
fields: fieldsDisabled
1385+
};
1386+
12751387
beforeEach(() => {
12761388
form = new FormModel();
1277-
field = new FormFieldModel(form, {
1278-
id: 'RepeatableSection0tbw2y',
1279-
name: 'Repeatable Section',
1280-
type: 'repeatable-section',
1281-
tab: null,
1282-
params: {
1283-
initialNumberOfRows: 2,
1284-
allowInitialRowsDelete: true,
1285-
newRowsLimit: 3
1286-
},
1287-
numberOfColumns: 2,
1288-
fields: {
1289-
'1': [
1290-
{
1291-
id: 'Text0wwp7n',
1292-
name: 'Text',
1293-
type: 'text',
1294-
readOnly: false,
1295-
required: false,
1296-
colspan: 1,
1297-
rowspan: 1,
1298-
placeholder: null,
1299-
minLength: 0,
1300-
maxLength: 0,
1301-
regexPattern: null,
1302-
visibilityCondition: null,
1303-
params: {
1304-
existingColspan: 1,
1305-
maxColspan: 2
1306-
}
1307-
}
1308-
],
1309-
'2': [
1310-
{
1311-
id: 'Integer0rzkwq',
1312-
name: 'Integer',
1313-
type: 'integer',
1314-
readOnly: false,
1315-
colspan: 1,
1316-
rowspan: 1,
1317-
placeholder: null,
1318-
minValue: null,
1319-
maxValue: null,
1320-
required: false,
1321-
visibilityCondition: null,
1322-
params: {
1323-
existingColspan: 1,
1324-
maxColspan: 2
1325-
}
1326-
}
1327-
]
1328-
}
1329-
});
1389+
field = new FormFieldModel(form, json);
13301390
});
13311391

13321392
describe('add row', () => {
@@ -1408,5 +1468,64 @@ describe('FormFieldModel', () => {
14081468
expect(form.values[field.id]).toEqual(formValues.removeState);
14091469
});
14101470
});
1471+
1472+
describe('disabled state', () => {
1473+
const textWidgetId = 'Text0wwp7n';
1474+
1475+
/**
1476+
*
1477+
* @param expectation expectation function
1478+
*/
1479+
function checkChildrenWidgets(expectation: any) {
1480+
for (const row of field.rows) {
1481+
for (const column of row.columns) {
1482+
for (const child of column.fields) {
1483+
expectation(child);
1484+
}
1485+
}
1486+
}
1487+
}
1488+
it('should make all children fields disabled if repeatable section is disabled', () => {
1489+
field.readOnly = true;
1490+
1491+
checkChildrenWidgets((child) => {
1492+
expect(child.readOnly).toBeTruthy();
1493+
});
1494+
});
1495+
1496+
it('should allow for initial disabled children widgets if repeatable section is enabled', () => {
1497+
field = new FormFieldModel(form, jsonDisabled);
1498+
1499+
checkChildrenWidgets((child) => {
1500+
if (child.id.startsWith(textWidgetId)) {
1501+
expect(child.readOnly).toBeTruthy();
1502+
return;
1503+
}
1504+
1505+
expect(child.readOnly).toBeFalsy();
1506+
});
1507+
});
1508+
1509+
it('should keep initial disabled children widgets if repeatable section is re-enabled', () => {
1510+
field = new FormFieldModel(form, jsonDisabled);
1511+
field.rows[0].columns[0].fields[0].readOnly = true;
1512+
field.readOnly = true;
1513+
1514+
checkChildrenWidgets((child) => {
1515+
expect(child.readOnly).toBeTruthy();
1516+
});
1517+
1518+
field.readOnly = false;
1519+
1520+
checkChildrenWidgets((child) => {
1521+
if (child.id.startsWith(textWidgetId)) {
1522+
expect(child.readOnly).toBeTruthy();
1523+
return;
1524+
}
1525+
1526+
expect(child.readOnly).toBeFalsy();
1527+
});
1528+
});
1529+
});
14111530
});
14121531
});

0 commit comments

Comments
 (0)