@yuuvis/client-framework 2.9.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -161,6 +161,7 @@ class DataGridComponent {
161
161
  this.el = inject((ElementRef));
162
162
  this.situation = input(Situation.EDIT);
163
163
  this.formElement = input(undefined);
164
+ this.mappedFormElement = signal(undefined);
164
165
  this.formControl = input(undefined);
165
166
  this.classifications = input([]);
166
167
  this.readonly = input(false);
@@ -197,14 +198,18 @@ class DataGridComponent {
197
198
  });
198
199
  this.#loadData = effect(() => {
199
200
  const formElement = this.formElement();
201
+ // if the form element is created from the ObjectTypeField it contains 'columnDefinitions' instead of 'elements'
202
+ // therefore we need to map them here for proper table rendering
200
203
  if (formElement && formElement['columnDefinitions']) {
201
204
  // map columnDefinitions to elements for table rendering
202
205
  formElement['elements'] = formElement['columnDefinitions'].map((colDef) => ({
203
206
  ...colDef,
204
207
  name: colDef.id,
205
- label: this.#systemService.getLocalizedLabel(colDef.id) || colDef.id
208
+ label: this.#systemService.getLocalizedLabel(colDef.id) || colDef.id,
209
+ type: colDef.propertyType
206
210
  }));
207
211
  }
212
+ this.mappedFormElement.set(formElement);
208
213
  const elements = formElement ? formElement['elements'] || [] : [];
209
214
  let data = formElement ? formElement['value'] || [] : [];
210
215
  const columns = elements.map((e) => e.name || e.id);
@@ -239,7 +244,7 @@ class DataGridComponent {
239
244
  minWidth: '25%',
240
245
  data: {
241
246
  formElement: {
242
- ...this.formElement()
247
+ ...this.mappedFormElement()
243
248
  },
244
249
  elementData,
245
250
  situation: this.situation(),
@@ -260,7 +265,7 @@ class DataGridComponent {
260
265
  this.#openEditOverlay(element).subscribe((result) => {
261
266
  if (result) {
262
267
  const updatedData = this.dataSource().map((item) => (JSON.stringify(item) === JSON.stringify(element) ? result : item));
263
- const formElement = this.formElement();
268
+ const formElement = this.mappedFormElement();
264
269
  formElement && this.#updateTable(formElement['elements'], [...updatedData]);
265
270
  }
266
271
  this.selectedRow.set(null);
@@ -272,14 +277,14 @@ class DataGridComponent {
272
277
  const data = [...currentData];
273
278
  if (result) {
274
279
  data.push(result);
275
- const formElement = this.formElement();
280
+ const formElement = this.mappedFormElement();
276
281
  formElement && this.#updateTable(formElement['elements'], data);
277
282
  }
278
283
  });
279
284
  }
280
285
  removeRow(element) {
281
286
  const updatedData = this.dataSource().filter((item) => JSON.stringify(item) !== JSON.stringify(element));
282
- const formElement = this.formElement();
287
+ const formElement = this.mappedFormElement();
283
288
  formElement && this.#updateTable(formElement['elements'], updatedData);
284
289
  }
285
290
  #updateTable(elements, data = []) {
@@ -306,7 +311,6 @@ class DataGridComponent {
306
311
  }
307
312
  const displayedColumns = [...this.displayedColumns().map((col) => col.columnDef)];
308
313
  this.displayedColumnsWithActions.set(displayedColumns);
309
- const cleandColumns = displayedColumns.filter((col) => col !== 'actions');
310
314
  this.dataSource.set(data);
311
315
  }
312
316
  writeValue(obj) {
@@ -358,7 +362,7 @@ class DataGridComponent {
358
362
  useExisting: forwardRef(() => DataGridComponent),
359
363
  multi: true
360
364
  }
361
- ], ngImport: i0, template: "<fieldset [attr.aria-required]=\"isRequired\" [attr.aria-invalid]=\"isInvalid\">\n <legend class=\"ymt-hide-sr\">\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </legend>\n <header class=\"yuv-data-grid__header\">\n <span\n [yuvObjectMetadataElementLabel]=\"formFieldContext()\"\n class=\"yuv-data-grid__header-title label\"\n [ngClass]=\"{ 'yuv-data-grid__header-title--invalid': isInvalid }\"\n aria-hidden=\"true\"\n >\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </span>\n\n @if (!readonly()) {\n <button ymtIconButton (click)=\"addRow()\" class=\"yuv-data-grid__header-action\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </header>\n\n @let displayedCol = displayedColumns();\n @let displayedColActions = displayedColumnsWithActions();\n @let data = dataSource();\n\n <div class=\"yuv-data-grid__table\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"data\" class=\"mat-elevation-z8\">\n <caption class=\"ymt-hide-sr\">\n {{\n tableLabel()\n }}\n </caption>\n\n @for (column of displayedCol; track column) {\n @if (column.columnDef === 'actions') {\n <h1>Actions</h1>\n <ng-container [matColumnDef]=\"column.columnDef\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef aria-label=\"row actions\"></th>\n <td class=\"yuv-data-grid__cell--editable\" mat-cell *matCellDef=\"let element\">\n <div class=\"yuv-data-grid__table-actions\">\n <!-- Only show the button in the last (empty) row -->\n <button ymtIconButton icon-button-size=\"small\" class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTrigger(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n } @else {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td\n [ngClass]=\"{ 'number-cell': column.type === 'integer' || column.type === 'decimal', 'yuv-data-grid__cell--editable': !readonly() }\"\n mat-cell\n *matCellDef=\"let element\"\n >\n <ng-template *yuvRenderer=\"column.cell(element)\"></ng-template>\n </td>\n </ng-container>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell no-data-cell\" [attr.colspan]=\"column.length\"></td>\n </tr>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n </table>\n @if (data.length === 0) {\n <span class=\"no-data\">{{ 'yuv.form.element.data.grid.noData' | translate }}</span>\n }\n </div>\n</fieldset>\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;max-width:100%;width:100%;border:1px solid var(--ymt-outline-variant);border-radius:var(--ymt-corner-s);overflow:hidden}:host .yuv-data-grid__header{display:flex;justify-content:space-between;align-items:center;padding:var(--ymt-spacing-xs)}:host .yuv-data-grid__header-title{transform:scale(var(--mat-mdc-form-field-floating-label-scale, .75))}:host .yuv-data-grid__header-title--invalid{background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);align-self:baseline}:host .yuv-data-grid__cell--editable{-webkit-user-select:none;user-select:none}:host .yuv-data-grid__table{overflow:auto;white-space:nowrap}:host .yuv-data-grid__table.small{height:var(--table-size-small)}:host .yuv-data-grid__table.medium{height:var(--table-size-medium)}:host .yuv-data-grid__table.large{height:var(--table-size-large)}:host .yuv-data-grid__table.extra-large{height:var(--table-size-extra-large)}:host .yuv-data-grid__table .no-data{display:block;width:100%;background-color:var(--ymt-surface);text-align:center;padding:var(--ymt-spacing-s);font:var(--ymt-font-body);color:var(--ymt-text-color-subtle);font-style:italic}:host .yuv-data-grid__table-actions{display:flex;align-items:center;justify-content:flex-end}:host.yuv-data-grid{display:block}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i4.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "directive", type: RendererDirective, selector: "[yuvRenderer]", inputs: ["yuvRenderer"] }, { kind: "directive", type: ObjectMetadataElementLabelDirective, selector: "[yuvObjectMetadataElementLabel]", inputs: ["yuvObjectMetadataElementLabel"] }, { kind: "directive", type: YmtIconButtonDirective, selector: "button[ymtIconButton],button[ymt-icon-button],a[ymtIconButton],a[ymt-icon-button]", inputs: ["disabled", "disableRipple", "aria-disabled", "disabledInteractive", "icon-button-size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
365
+ ], ngImport: i0, template: "<fieldset [attr.aria-required]=\"isRequired\" [attr.aria-invalid]=\"isInvalid\">\n <legend class=\"ymt-hide-sr\">\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </legend>\n <header class=\"yuv-data-grid__header\">\n <span\n [yuvObjectMetadataElementLabel]=\"formFieldContext()\"\n class=\"yuv-data-grid__header-title label\"\n [ngClass]=\"{ 'yuv-data-grid__header-title--invalid': isInvalid }\"\n aria-hidden=\"true\"\n >\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </span>\n\n @if (!readonly()) {\n <button ymtIconButton (click)=\"addRow()\" class=\"yuv-data-grid__header-action\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </header>\n\n @let displayedCol = displayedColumns();\n @let displayedColActions = displayedColumnsWithActions();\n @let data = dataSource();\n\n <div class=\"yuv-data-grid__table\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"data\" class=\"mat-elevation-z8\">\n <caption class=\"ymt-hide-sr\">\n {{\n tableLabel()\n }}\n </caption>\n\n @for (column of displayedCol; track column) {\n @if (column.columnDef === 'actions') {\n <!-- <h1>Actions</h1> -->\n <ng-container [matColumnDef]=\"column.columnDef\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef aria-label=\"row actions\"></th>\n <td class=\"yuv-data-grid__cell--editable\" mat-cell *matCellDef=\"let element\">\n <div class=\"yuv-data-grid__table-actions\">\n <!-- Only show the button in the last (empty) row -->\n <button ymtIconButton icon-button-size=\"small\" class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTrigger(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n } @else {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td\n [ngClass]=\"{ 'number-cell': column.type === 'integer' || column.type === 'decimal', 'yuv-data-grid__cell--editable': !readonly() }\"\n mat-cell\n *matCellDef=\"let element\"\n >\n <ng-template *yuvRenderer=\"column.cell(element)\"></ng-template>\n </td>\n </ng-container>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell no-data-cell\" [attr.colspan]=\"column.length\"></td>\n </tr>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n </table>\n @if (data.length === 0) {\n <span class=\"no-data\">{{ 'yuv.form.element.data.grid.noData' | translate }}</span>\n }\n </div>\n</fieldset>\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;max-width:100%;width:100%;border:1px solid var(--ymt-outline-variant);border-radius:var(--ymt-corner-s);overflow:hidden;position:relative}:host .yuv-data-grid__header{display:flex;justify-content:space-between;align-items:center;padding:var(--ymt-spacing-xs)}:host .yuv-data-grid__header-title{transform:scale(var(--mat-mdc-form-field-floating-label-scale, .75))}:host .yuv-data-grid__header-title--invalid{background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);align-self:baseline}:host .yuv-data-grid__cell--editable{-webkit-user-select:none;user-select:none}:host .yuv-data-grid__table{overflow:auto;white-space:nowrap}:host .yuv-data-grid__table.small{height:var(--table-size-small)}:host .yuv-data-grid__table.medium{height:var(--table-size-medium)}:host .yuv-data-grid__table.large{height:var(--table-size-large)}:host .yuv-data-grid__table.extra-large{height:var(--table-size-extra-large)}:host .yuv-data-grid__table .no-data{display:block;width:100%;background-color:var(--ymt-surface);text-align:center;padding:var(--ymt-spacing-s);font:var(--ymt-font-body);color:var(--ymt-text-color-subtle);font-style:italic}:host .yuv-data-grid__table-actions{display:flex;align-items:center;justify-content:flex-end}:host.yuv-data-grid{display:block}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i4.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "directive", type: RendererDirective, selector: "[yuvRenderer]", inputs: ["yuvRenderer"] }, { kind: "directive", type: ObjectMetadataElementLabelDirective, selector: "[yuvObjectMetadataElementLabel]", inputs: ["yuvObjectMetadataElementLabel"] }, { kind: "directive", type: YmtIconButtonDirective, selector: "button[ymtIconButton],button[ymt-icon-button],a[ymtIconButton],a[ymt-icon-button]", inputs: ["disabled", "disableRipple", "aria-disabled", "disabledInteractive", "icon-button-size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
362
366
  }
363
367
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DataGridComponent, decorators: [{
364
368
  type: Component,
@@ -376,7 +380,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
376
380
  ], host: {
377
381
  class: 'yuv-data-grid',
378
382
  '(focusout)': 'onHostFocusOut($event)'
379
- }, template: "<fieldset [attr.aria-required]=\"isRequired\" [attr.aria-invalid]=\"isInvalid\">\n <legend class=\"ymt-hide-sr\">\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </legend>\n <header class=\"yuv-data-grid__header\">\n <span\n [yuvObjectMetadataElementLabel]=\"formFieldContext()\"\n class=\"yuv-data-grid__header-title label\"\n [ngClass]=\"{ 'yuv-data-grid__header-title--invalid': isInvalid }\"\n aria-hidden=\"true\"\n >\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </span>\n\n @if (!readonly()) {\n <button ymtIconButton (click)=\"addRow()\" class=\"yuv-data-grid__header-action\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </header>\n\n @let displayedCol = displayedColumns();\n @let displayedColActions = displayedColumnsWithActions();\n @let data = dataSource();\n\n <div class=\"yuv-data-grid__table\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"data\" class=\"mat-elevation-z8\">\n <caption class=\"ymt-hide-sr\">\n {{\n tableLabel()\n }}\n </caption>\n\n @for (column of displayedCol; track column) {\n @if (column.columnDef === 'actions') {\n <h1>Actions</h1>\n <ng-container [matColumnDef]=\"column.columnDef\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef aria-label=\"row actions\"></th>\n <td class=\"yuv-data-grid__cell--editable\" mat-cell *matCellDef=\"let element\">\n <div class=\"yuv-data-grid__table-actions\">\n <!-- Only show the button in the last (empty) row -->\n <button ymtIconButton icon-button-size=\"small\" class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTrigger(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n } @else {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td\n [ngClass]=\"{ 'number-cell': column.type === 'integer' || column.type === 'decimal', 'yuv-data-grid__cell--editable': !readonly() }\"\n mat-cell\n *matCellDef=\"let element\"\n >\n <ng-template *yuvRenderer=\"column.cell(element)\"></ng-template>\n </td>\n </ng-container>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell no-data-cell\" [attr.colspan]=\"column.length\"></td>\n </tr>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n </table>\n @if (data.length === 0) {\n <span class=\"no-data\">{{ 'yuv.form.element.data.grid.noData' | translate }}</span>\n }\n </div>\n</fieldset>\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;max-width:100%;width:100%;border:1px solid var(--ymt-outline-variant);border-radius:var(--ymt-corner-s);overflow:hidden}:host .yuv-data-grid__header{display:flex;justify-content:space-between;align-items:center;padding:var(--ymt-spacing-xs)}:host .yuv-data-grid__header-title{transform:scale(var(--mat-mdc-form-field-floating-label-scale, .75))}:host .yuv-data-grid__header-title--invalid{background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);align-self:baseline}:host .yuv-data-grid__cell--editable{-webkit-user-select:none;user-select:none}:host .yuv-data-grid__table{overflow:auto;white-space:nowrap}:host .yuv-data-grid__table.small{height:var(--table-size-small)}:host .yuv-data-grid__table.medium{height:var(--table-size-medium)}:host .yuv-data-grid__table.large{height:var(--table-size-large)}:host .yuv-data-grid__table.extra-large{height:var(--table-size-extra-large)}:host .yuv-data-grid__table .no-data{display:block;width:100%;background-color:var(--ymt-surface);text-align:center;padding:var(--ymt-spacing-s);font:var(--ymt-font-body);color:var(--ymt-text-color-subtle);font-style:italic}:host .yuv-data-grid__table-actions{display:flex;align-items:center;justify-content:flex-end}:host.yuv-data-grid{display:block}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}\n"] }]
383
+ }, template: "<fieldset [attr.aria-required]=\"isRequired\" [attr.aria-invalid]=\"isInvalid\">\n <legend class=\"ymt-hide-sr\">\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </legend>\n <header class=\"yuv-data-grid__header\">\n <span\n [yuvObjectMetadataElementLabel]=\"formFieldContext()\"\n class=\"yuv-data-grid__header-title label\"\n [ngClass]=\"{ 'yuv-data-grid__header-title--invalid': isInvalid }\"\n aria-hidden=\"true\"\n >\n {{ tableLabel() }}\n @if (isRequired) {\n *\n }\n </span>\n\n @if (!readonly()) {\n <button ymtIconButton (click)=\"addRow()\" class=\"yuv-data-grid__header-action\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </header>\n\n @let displayedCol = displayedColumns();\n @let displayedColActions = displayedColumnsWithActions();\n @let data = dataSource();\n\n <div class=\"yuv-data-grid__table\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"data\" class=\"mat-elevation-z8\">\n <caption class=\"ymt-hide-sr\">\n {{\n tableLabel()\n }}\n </caption>\n\n @for (column of displayedCol; track column) {\n @if (column.columnDef === 'actions') {\n <!-- <h1>Actions</h1> -->\n <ng-container [matColumnDef]=\"column.columnDef\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef aria-label=\"row actions\"></th>\n <td class=\"yuv-data-grid__cell--editable\" mat-cell *matCellDef=\"let element\">\n <div class=\"yuv-data-grid__table-actions\">\n <!-- Only show the button in the last (empty) row -->\n <button ymtIconButton icon-button-size=\"small\" class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTrigger(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n } @else {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td\n [ngClass]=\"{ 'number-cell': column.type === 'integer' || column.type === 'decimal', 'yuv-data-grid__cell--editable': !readonly() }\"\n mat-cell\n *matCellDef=\"let element\"\n >\n <ng-template *yuvRenderer=\"column.cell(element)\"></ng-template>\n </td>\n </ng-container>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell no-data-cell\" [attr.colspan]=\"column.length\"></td>\n </tr>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n </table>\n @if (data.length === 0) {\n <span class=\"no-data\">{{ 'yuv.form.element.data.grid.noData' | translate }}</span>\n }\n </div>\n</fieldset>\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;max-width:100%;width:100%;border:1px solid var(--ymt-outline-variant);border-radius:var(--ymt-corner-s);overflow:hidden;position:relative}:host .yuv-data-grid__header{display:flex;justify-content:space-between;align-items:center;padding:var(--ymt-spacing-xs)}:host .yuv-data-grid__header-title{transform:scale(var(--mat-mdc-form-field-floating-label-scale, .75))}:host .yuv-data-grid__header-title--invalid{background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);align-self:baseline}:host .yuv-data-grid__cell--editable{-webkit-user-select:none;user-select:none}:host .yuv-data-grid__table{overflow:auto;white-space:nowrap}:host .yuv-data-grid__table.small{height:var(--table-size-small)}:host .yuv-data-grid__table.medium{height:var(--table-size-medium)}:host .yuv-data-grid__table.large{height:var(--table-size-large)}:host .yuv-data-grid__table.extra-large{height:var(--table-size-extra-large)}:host .yuv-data-grid__table .no-data{display:block;width:100%;background-color:var(--ymt-surface);text-align:center;padding:var(--ymt-spacing-s);font:var(--ymt-font-body);color:var(--ymt-text-color-subtle);font-style:italic}:host .yuv-data-grid__table-actions{display:flex;align-items:center;justify-content:flex-end}:host.yuv-data-grid{display:block}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}\n"] }]
380
384
  }] });
381
385
 
382
386
  class DatetimeComponent extends AbstractMatFormField {
@@ -897,7 +901,7 @@ class NumberRangeComponent extends AbstractMatFormField {
897
901
  numberValueFrom: Number(value.firstValue) || undefined,
898
902
  operator: match ? match.value : this.availableSearchOptions[0].value,
899
903
  numberValue: Number(value.secondValue) || undefined
900
- });
904
+ }, { emitEvent: false });
901
905
  }
902
906
  }
903
907
  else {
@@ -1348,6 +1352,7 @@ class OrganizationSetComponent extends AbstractMatFormField {
1348
1352
  else {
1349
1353
  this.acFormControl.enable();
1350
1354
  }
1355
+ this.disabled = isDisabled;
1351
1356
  }
1352
1357
  propagate() {
1353
1358
  this.value = this.#getPropagateValue();
@@ -1592,15 +1597,15 @@ class RangeSelectDateComponent extends AbstractMatFormField {
1592
1597
  if (value?.rangeValue?.operator && value?.rangeValue?.firstValue) {
1593
1598
  const dr = SearchUtils.getMatchingDateRange(value.rangeValue);
1594
1599
  if (dr) {
1595
- this.fc.patchValue(dr);
1600
+ this.fc.patchValue(dr, { emitEvent: false });
1596
1601
  }
1597
1602
  else {
1598
1603
  this.#customDateRange = value.rangeValue;
1599
- this.fc.patchValue(this.#CUSTOM_OPTION);
1604
+ this.fc.patchValue(this.#CUSTOM_OPTION, { emitEvent: false });
1600
1605
  }
1601
1606
  }
1602
1607
  else {
1603
- this.fc.patchValue(this.#ANY_OPTION);
1608
+ this.fc.patchValue(this.#ANY_OPTION, { emitEvent: false });
1604
1609
  }
1605
1610
  }
1606
1611
  registerOnChange(fn) {
@@ -1684,7 +1689,7 @@ class RangeSelectFilesizeComponent extends AbstractMatFormField {
1684
1689
  if (range)
1685
1690
  patch = range;
1686
1691
  }
1687
- this.fc.patchValue(patch);
1692
+ this.fc.patchValue(patch, { emitEvent: false });
1688
1693
  }
1689
1694
  registerOnChange(fn) {
1690
1695
  this.propagateChange = fn;
@@ -1794,7 +1799,7 @@ class StringComponent extends AbstractMatFormField {
1794
1799
  else {
1795
1800
  this.formatedValue = Utils.formatMailTo(value, this.classify?.hrefPrefix === ClassificationPrefix.EMAIL);
1796
1801
  }
1797
- this.fc.patchValue(value);
1802
+ this.fc.patchValue(value, { emitEvent: false, onlySelf: true });
1798
1803
  this.value = value || undefined;
1799
1804
  }
1800
1805
  registerOnChange(fn) {
@@ -2060,6 +2065,7 @@ class CatalogComponent extends AbstractMatFormField {
2060
2065
  else {
2061
2066
  this.fc.enable();
2062
2067
  }
2068
+ this.disabled = isDisabled;
2063
2069
  }
2064
2070
  ngOnInit() {
2065
2071
  if (this.required)
@@ -2168,6 +2174,7 @@ class I18nCatalogComponent extends AbstractMatFormField {
2168
2174
  else {
2169
2175
  this.fc.enable();
2170
2176
  }
2177
+ this.disabled = isDisabled;
2171
2178
  }
2172
2179
  ngOnInit() {
2173
2180
  if (this.required)