ngx-material-entity 16.0.2 → 16.0.3

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.
Files changed (97) hide show
  1. package/components/edit-page/edit-page.component.d.ts +13 -2
  2. package/components/input/boolean/boolean-checkbox-input/boolean-checkbox-input.component.d.ts +1 -0
  3. package/components/input/boolean/boolean-toggle-input/boolean-toggle-input.component.d.ts +2 -1
  4. package/components/input/input.component.d.ts +1 -1
  5. package/components/input/input.module.d.ts +4 -2
  6. package/components/input/number/number-slider-input/number-slider-input.component.d.ts +2 -1
  7. package/components/table/create-dialog/create-entity-dialog.component.d.ts +3 -0
  8. package/components/table/edit-dialog/edit-entity-dialog.component.d.ts +4 -0
  9. package/components/tooltip/tooltip.component.d.ts +9 -0
  10. package/decorators/array/array-decorator-internal.data.d.ts +6 -6
  11. package/decorators/array/array-decorator.data.d.ts +7 -7
  12. package/decorators/base/property-decorator-internal.data.d.ts +11 -2
  13. package/decorators/base/property-decorator.data.d.ts +9 -1
  14. package/decorators/boolean/boolean-decorator-internal.data.d.ts +3 -3
  15. package/decorators/boolean/boolean-decorator.data.d.ts +1 -1
  16. package/decorators/custom/custom-decorator-internal.data.d.ts +2 -2
  17. package/decorators/custom/custom-decorator.data.d.ts +4 -4
  18. package/decorators/date/date-decorator-internal.data.d.ts +4 -4
  19. package/decorators/date/date-decorator.data.d.ts +5 -5
  20. package/decorators/file/file-decorator-internal.data.d.ts +3 -3
  21. package/decorators/file/file-decorator.data.d.ts +1 -1
  22. package/decorators/has-many/has-many-decorator-internal.data.d.ts +1 -1
  23. package/decorators/has-many/has-many-decorator.data.d.ts +1 -1
  24. package/decorators/number/number-decorator-internal.data.d.ts +3 -3
  25. package/decorators/number/number-decorator.data.d.ts +1 -1
  26. package/decorators/object/object-decorator-internal.data.d.ts +1 -1
  27. package/decorators/object/object-decorator.data.d.ts +1 -1
  28. package/decorators/references-many/references-many-decorator-internal.data.d.ts +1 -1
  29. package/decorators/references-many/references-many-decorator.data.d.ts +1 -1
  30. package/decorators/references-one/references-one-decorator-internal.data.d.ts +1 -1
  31. package/decorators/references-one/references-one-decorator.data.d.ts +1 -1
  32. package/decorators/string/string-decorator-internal.data.d.ts +5 -6
  33. package/decorators/string/string-decorator.data.d.ts +1 -7
  34. package/directives/number.directive.d.ts +17 -0
  35. package/directives/password-match.directive.d.ts +14 -0
  36. package/directives/tooltip.directive.d.ts +33 -0
  37. package/esm2022/components/edit-page/edit-page.component.mjs +57 -13
  38. package/esm2022/components/input/array/array-date-range-input/array-date-range-input.component.mjs +1 -1
  39. package/esm2022/components/input/base-input.component.mjs +2 -1
  40. package/esm2022/components/input/boolean/boolean-checkbox-input/boolean-checkbox-input.component.mjs +6 -3
  41. package/esm2022/components/input/boolean/boolean-toggle-input/boolean-toggle-input.component.mjs +6 -3
  42. package/esm2022/components/input/date/date-range-input/date-range-input.component.mjs +3 -1
  43. package/esm2022/components/input/file/file-image-input/file-image-input.component.mjs +3 -3
  44. package/esm2022/components/input/file/file-input/file-input.component.mjs +1 -1
  45. package/esm2022/components/input/input.component.mjs +7 -6
  46. package/esm2022/components/input/input.module.mjs +10 -4
  47. package/esm2022/components/input/number/number-input/number-input.component.mjs +4 -3
  48. package/esm2022/components/input/number/number-slider-input/number-slider-input.component.mjs +6 -3
  49. package/esm2022/components/input/string/string-password-input/string-password-input.component.mjs +4 -3
  50. package/esm2022/components/table/create-dialog/create-entity-dialog.component.mjs +18 -6
  51. package/esm2022/components/table/edit-dialog/edit-entity-dialog.component.mjs +26 -13
  52. package/esm2022/components/table/table.component.mjs +7 -4
  53. package/esm2022/components/tooltip/tooltip.component.mjs +20 -0
  54. package/esm2022/decorators/array/array-decorator-internal.data.mjs +1 -1
  55. package/esm2022/decorators/array/array-decorator.data.mjs +1 -1
  56. package/esm2022/decorators/base/property-decorator-internal.data.mjs +22 -1
  57. package/esm2022/decorators/base/property-decorator.data.mjs +10 -1
  58. package/esm2022/decorators/boolean/boolean-decorator-internal.data.mjs +1 -1
  59. package/esm2022/decorators/boolean/boolean-decorator.data.mjs +1 -1
  60. package/esm2022/decorators/custom/custom-decorator-internal.data.mjs +2 -2
  61. package/esm2022/decorators/custom/custom-decorator.data.mjs +1 -1
  62. package/esm2022/decorators/date/date-decorator-internal.data.mjs +2 -1
  63. package/esm2022/decorators/date/date-decorator.data.mjs +1 -1
  64. package/esm2022/decorators/file/file-decorator-internal.data.mjs +1 -1
  65. package/esm2022/decorators/file/file-decorator.data.mjs +1 -1
  66. package/esm2022/decorators/has-many/has-many-decorator-internal.data.mjs +1 -1
  67. package/esm2022/decorators/has-many/has-many-decorator.data.mjs +1 -1
  68. package/esm2022/decorators/number/number-decorator-internal.data.mjs +1 -1
  69. package/esm2022/decorators/number/number-decorator.data.mjs +1 -1
  70. package/esm2022/decorators/object/object-decorator-internal.data.mjs +1 -1
  71. package/esm2022/decorators/object/object-decorator.data.mjs +1 -1
  72. package/esm2022/decorators/references-many/references-many-decorator-internal.data.mjs +1 -1
  73. package/esm2022/decorators/references-many/references-many-decorator.data.mjs +1 -1
  74. package/esm2022/decorators/references-one/references-one-decorator-internal.data.mjs +1 -1
  75. package/esm2022/decorators/references-one/references-one-decorator.data.mjs +1 -1
  76. package/esm2022/decorators/string/string-decorator-internal.data.mjs +1 -4
  77. package/esm2022/decorators/string/string-decorator.data.mjs +1 -1
  78. package/esm2022/directives/drag-drop.directive.mjs +62 -0
  79. package/esm2022/directives/number.directive.mjs +38 -0
  80. package/esm2022/directives/password-match.directive.mjs +30 -0
  81. package/esm2022/directives/tooltip.directive.mjs +112 -0
  82. package/esm2022/functions/get-validation-error-message.function.mjs +49 -0
  83. package/esm2022/functions/get-validation-errors-tooltip-content.function.ts.mjs +25 -0
  84. package/esm2022/public-api.mjs +6 -2
  85. package/esm2022/utilities/entity.utilities.mjs +83 -386
  86. package/esm2022/utilities/validation.utilities.mjs +455 -0
  87. package/fesm2022/ngx-material-entity.mjs +1374 -905
  88. package/fesm2022/ngx-material-entity.mjs.map +1 -1
  89. package/functions/get-validation-errors-tooltip-content.function.ts.d.ts +10 -0
  90. package/package.json +1 -1
  91. package/public-api.d.ts +4 -1
  92. package/utilities/entity.utilities.d.ts +33 -30
  93. package/utilities/validation.utilities.d.ts +56 -0
  94. package/esm2022/components/get-validation-error-message.function.mjs +0 -42
  95. package/esm2022/components/input/file/file-input/dragDrop.directive.mjs +0 -62
  96. /package/{components/input/file/file-input/dragDrop.directive.d.ts → directives/drag-drop.directive.d.ts} +0 -0
  97. /package/{components → functions}/get-validation-error-message.function.d.ts +0 -0
@@ -4,11 +4,11 @@ import 'reflect-metadata';
4
4
  import { firstValueFrom, Observable, BehaviorSubject, first, map, Subject, takeUntil } from 'rxjs';
5
5
  import JSZip from 'jszip';
6
6
  import * as i0 from '@angular/core';
7
- import { Component, Inject, Input, EventEmitter, Output, Directive, HostListener, InjectionToken, inject, ViewChild, NgModule } from '@angular/core';
7
+ import { Component, Inject, InjectionToken, inject, EventEmitter, Directive, Output, HostListener, Input, ViewChild, NgModule, runInInjectionContext } from '@angular/core';
8
8
  import * as i1 from '@angular/material/dialog';
9
9
  import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
10
10
  import * as i3 from '@angular/forms';
11
- import { FormsModule } from '@angular/forms';
11
+ import { FormsModule, NG_VALIDATORS } from '@angular/forms';
12
12
  import * as i5 from '@angular/material/button';
13
13
  import { MatButtonModule } from '@angular/material/button';
14
14
  import * as i4 from '@angular/material/checkbox';
@@ -16,6 +16,8 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
16
16
  import * as i1$1 from '@angular/common';
17
17
  import { NgIf, NgFor, CommonModule } from '@angular/common';
18
18
  import * as i2 from '@angular/common/http';
19
+ import * as i10 from '@angular/material/badge';
20
+ import { MatBadgeModule } from '@angular/material/badge';
19
21
  import * as i14 from '@angular/material/menu';
20
22
  import { MatMenuModule } from '@angular/material/menu';
21
23
  import * as i15 from '@angular/material/progress-spinner';
@@ -661,7 +663,7 @@ class EntityUtilities {
661
663
  static getOmitForUpdate(entity) {
662
664
  const res = [];
663
665
  for (const key of ReflectUtilities.ownKeys(entity)) {
664
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
666
+ const metadata = this.getPropertyMetadata(entity, key);
665
667
  if (metadata.omitForUpdate) {
666
668
  res.push(key);
667
669
  }
@@ -677,7 +679,7 @@ class EntityUtilities {
677
679
  static getOmitForCreate(entity) {
678
680
  const res = [];
679
681
  for (const key of ReflectUtilities.ownKeys(entity)) {
680
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
682
+ const metadata = this.getPropertyMetadata(entity, key);
681
683
  if (metadata.omitForCreate) {
682
684
  res.push(key);
683
685
  }
@@ -691,7 +693,7 @@ class EntityUtilities {
691
693
  * @returns The reduced entity object.
692
694
  */
693
695
  static getWithoutOmitCreateValues(entity) {
694
- return LodashUtilities.omit(entity, EntityUtilities.getOmitForCreate(entity));
696
+ return LodashUtilities.omit(entity, this.getOmitForCreate(entity));
695
697
  }
696
698
  /**
697
699
  * Returns the given entity without the values that should be omitted for updating.
@@ -704,18 +706,18 @@ class EntityUtilities {
704
706
  */
705
707
  static async getWithoutOmitUpdateValues(entity, entityPriorChanges, http) {
706
708
  const res = {};
707
- for (const key of EntityUtilities.keysOf(entity, false, true)) {
708
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
709
- const type = EntityUtilities.getPropertyType(entity, key);
710
- if (!(await EntityUtilities.isEqual(entity[key], entityPriorChanges[key], metadata, type, http))) {
709
+ for (const key of this.keysOf(entity, false, true)) {
710
+ const metadata = this.getPropertyMetadata(entity, key);
711
+ const type = this.getPropertyType(entity, key);
712
+ if (!(await this.isEqual(entity[key], entityPriorChanges[key], metadata, type, http))) {
711
713
  switch (type) {
712
714
  case DecoratorTypes.OBJECT:
713
715
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
714
- res[key] = LodashUtilities.omit(entity[key], EntityUtilities.getOmitForCreate(entity[key]));
716
+ res[key] = LodashUtilities.omit(entity[key], this.getOmitForCreate(entity[key]));
715
717
  break;
716
718
  case DecoratorTypes.ARRAY:
717
719
  res[key] = entity[key]
718
- .map(value => LodashUtilities.omit(value, EntityUtilities.getOmitForCreate(value)));
720
+ .map(value => LodashUtilities.omit(value, this.getOmitForCreate(value)));
719
721
  break;
720
722
  default:
721
723
  res[key] = entity[key];
@@ -725,6 +727,20 @@ class EntityUtilities {
725
727
  }
726
728
  return res;
727
729
  }
730
+ /**
731
+ * Sets all default values on the given entity.
732
+ *
733
+ * @param entity - The entity to set the default values on.
734
+ */
735
+ static setDefaultValues(entity) {
736
+ for (const key in entity) {
737
+ const metadata = this.getPropertyMetadata(entity, key);
738
+ if (metadata.default) {
739
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
740
+ entity[key] = metadata.default();
741
+ }
742
+ }
743
+ }
728
744
  /**
729
745
  * Gets all properties on the given entity which are files.
730
746
  *
@@ -735,9 +751,9 @@ class EntityUtilities {
735
751
  static getFileProperties(entity, omit) {
736
752
  const res = [];
737
753
  for (const key of ReflectUtilities.ownKeys(entity)) {
738
- const type = EntityUtilities.getPropertyType(entity, key);
754
+ const type = this.getPropertyType(entity, key);
739
755
  if (type === DecoratorTypes.FILE_DEFAULT || type === DecoratorTypes.FILE_IMAGE) {
740
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
756
+ const metadata = this.getPropertyMetadata(entity, key);
741
757
  if (!(metadata.omitForCreate && omit === 'create') && !(metadata.omitForUpdate && omit === 'update')) {
742
758
  res.push(key);
743
759
  }
@@ -794,12 +810,12 @@ class EntityUtilities {
794
810
  */
795
811
  static new(target, entity) {
796
812
  for (const key in target) {
797
- const type = EntityUtilities.getPropertyType(target, key);
813
+ const type = this.getPropertyType(target, key);
798
814
  let value = entity ? ReflectUtilities.get(entity, key) : undefined;
799
815
  switch (type) {
800
816
  case DecoratorTypes.OBJECT:
801
817
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
802
- const objectMetadata = EntityUtilities.getPropertyMetadata(target, key, DecoratorTypes.OBJECT);
818
+ const objectMetadata = this.getPropertyMetadata(target, key, DecoratorTypes.OBJECT);
803
819
  value = new objectMetadata.EntityClass(value);
804
820
  break;
805
821
  case DecoratorTypes.ARRAY:
@@ -807,7 +823,7 @@ class EntityUtilities {
807
823
  const resArray = [];
808
824
  if (inputArray) {
809
825
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
810
- const arrayMetadata = EntityUtilities.getPropertyMetadata(target, key, DecoratorTypes.ARRAY);
826
+ const arrayMetadata = this.getPropertyMetadata(target, key, DecoratorTypes.ARRAY);
811
827
  for (const item of inputArray) {
812
828
  const itemWithMetadata = new arrayMetadata.EntityClass(item);
813
829
  resArray.push(itemWithMetadata);
@@ -822,800 +838,504 @@ class EntityUtilities {
822
838
  }
823
839
  }
824
840
  // eslint-disable-next-line @typescript-eslint/member-ordering, jsdoc/require-jsdoc, @typescript-eslint/typedef
825
- static construct = EntityUtilities.new;
841
+ static construct = this.new;
826
842
  // eslint-disable-next-line @typescript-eslint/member-ordering, jsdoc/require-jsdoc, @typescript-eslint/typedef
827
- static build = EntityUtilities.new;
843
+ static build = this.new;
828
844
  /**
829
- * Checks if the values on an entity are valid.
830
- * Also checks all the validators given by the metadata ("required", "maxLength" etc.).
845
+ * Checks if an entity is "dirty" (if its values have changed).
831
846
  *
832
- * @param entity - The entity to validate.
833
- * @param omit - Whether to check for creating or editing validity.
834
- * @returns Whether or not the entity is valid.
847
+ * @param entity - The entity after all changes.
848
+ * @param entityPriorChanges - The entity before the changes.
849
+ * @param http - The angular HttpClient. Used to fetch files.
850
+ * @returns Whether or not the entity is dirty.
835
851
  */
836
- static isEntityValid(entity, omit) {
837
- for (const key in entity) {
838
- if (!EntityUtilities.isPropertyValid(entity, key, omit)) {
839
- return false;
840
- }
852
+ static async isDirty(entity, entityPriorChanges, http) {
853
+ if (!entityPriorChanges) {
854
+ return false;
841
855
  }
842
- return true;
856
+ const differences = await this.getDifferencesBetweenEntities(entity, entityPriorChanges, http);
857
+ return differences.length ? true : false;
843
858
  }
844
859
  /**
845
- * Checks if a single property value is valid.
860
+ * Gets the differences between the two given entities.
846
861
  *
847
- * @param entity - The entity where the property is from.
848
- * @param key - The name of the property.
849
- * @param omit - Whether to check if the given entity is valid for creation or updating.
850
- * @returns Whether or not the property value is valid.
851
- * @throws Throws when it extracts an unknown metadata type.
862
+ * @param entity - The entity as is.
863
+ * @param entityPriorChanges - The entity before any changes have been made.
864
+ * @param http - The angular http client, is needed to check if files are equal.
865
+ * @returns The differences as an array consisting of key, before and after.
852
866
  */
853
- static isPropertyValid(entity, key, omit) {
854
- const type = EntityUtilities.getPropertyType(entity, key);
855
- const metadata = EntityUtilities.getPropertyMetadata(entity, key, type);
856
- if (metadata.omitForCreate && omit === 'create') {
857
- return true;
858
- }
859
- if (metadata.omitForUpdate && omit === 'update') {
860
- return true;
861
- }
862
- if (metadata.required(entity) && type !== DecoratorTypes.HAS_MANY) {
863
- if (entity[key] == null || entity[key] === '') {
864
- return false;
867
+ static async getDifferencesBetweenEntities(entity, entityPriorChanges, http) {
868
+ const res = [];
869
+ for (const key of ReflectUtilities.ownKeys(entity)) {
870
+ const metadata = this.getPropertyMetadata(entity, key);
871
+ const type = this.getPropertyType(entity, key);
872
+ if (!(await this.isEqual(entity[key], entityPriorChanges[key], metadata, type, http))) {
873
+ res.push({
874
+ key: key,
875
+ before: entityPriorChanges[key],
876
+ after: entity[key]
877
+ });
865
878
  }
866
- }
867
- if (!metadata.required(entity)) {
868
- if (entity[key] == null || entity[key] === '') {
869
- return true;
879
+ else {
880
+ // This is needed to set blob file data so that it is only requested once.
881
+ entityPriorChanges[key] = LodashUtilities.cloneDeep(entity[key]);
870
882
  }
871
883
  }
884
+ return res;
885
+ }
886
+ // TODO Remove
887
+ /**
888
+ * Compares two Entities and returns their difference in an object.
889
+ *
890
+ * @param entity - The first entity to compare.
891
+ * @param entityPriorChanges - The second entity to compare.
892
+ * @returns The difference between the two Entities in form of a Partial.
893
+ */
894
+ // static async difference<EntityType extends BaseEntityType<EntityType>>(
895
+ // entity: EntityType,
896
+ // entityPriorChanges: EntityType
897
+ // ): Promise<Partial<EntityType>> {
898
+ // const res: Partial<EntityType> = {};
899
+ // for (const key in entity) {
900
+ // const metadata: PropertyDecoratorConfigInternal = this.getPropertyMetadata(entity, key);
901
+ // const type: DecoratorTypes = this.getPropertyType(entity, key);
902
+ // if (!(await this.isEqual(entity[key], entityPriorChanges[key], metadata, type))) {
903
+ // res[key] = entity[key];
904
+ // }
905
+ // }
906
+ // return res;
907
+ // }
908
+ /**
909
+ * Checks if two given values are equal.
910
+ * It uses the isEqual method from LodashUtilities and extends it with functionality regarding Dates.
911
+ *
912
+ * @param value - The updated value.
913
+ * @param valuePriorChanges - The value before any changes.
914
+ * @param metadata - The metadata of the property.
915
+ * @param type - The type of the property.
916
+ * @param http - The angular HttpClient. Used to fetch files.
917
+ * @returns Whether or not the given values are equal.
918
+ */
919
+ static async isEqual(value, valuePriorChanges, metadata, type, http) {
872
920
  switch (type) {
873
- case DecoratorTypes.BOOLEAN_DROPDOWN:
874
- break;
875
- case DecoratorTypes.BOOLEAN_CHECKBOX:
876
- case DecoratorTypes.BOOLEAN_TOGGLE:
877
- const entityBoolean = entity[key];
878
- const booleanMetadata = metadata;
879
- if (!EntityUtilities.isBooleanValid(entity, entityBoolean, booleanMetadata)) {
880
- return false;
881
- }
882
- break;
883
- case DecoratorTypes.STRING_DROPDOWN:
884
- break;
885
- case DecoratorTypes.STRING:
886
- case DecoratorTypes.STRING_AUTOCOMPLETE:
887
- const entityString = entity[key];
888
- const stringMetadata = metadata;
889
- if (!EntityUtilities.isStringValid(entityString, stringMetadata)) {
890
- return false;
891
- }
892
- break;
893
- case DecoratorTypes.STRING_TEXTBOX:
894
- const entityTextbox = entity[key];
895
- const textboxMetadata = metadata;
896
- if (!EntityUtilities.isTextboxValid(entityTextbox, textboxMetadata)) {
897
- return false;
898
- }
899
- break;
900
- case DecoratorTypes.STRING_PASSWORD:
901
- const entityPassword = entity[key];
902
- const passwordMetadata = metadata;
903
- const confirmPassword = ReflectUtilities.getMetadata(this.CONFIRM_PASSWORD_KEY, entity, key);
904
- if (!EntityUtilities.isPasswordValid(entityPassword, passwordMetadata, confirmPassword)) {
905
- return false;
906
- }
907
- break;
908
- case DecoratorTypes.NUMBER_DROPDOWN:
909
- return true;
910
- case DecoratorTypes.NUMBER:
911
- case DecoratorTypes.NUMBER_SLIDER:
912
- const entityNumber = entity[key];
913
- const numberMetadata = metadata;
914
- if (!EntityUtilities.isNumberValid(entityNumber, numberMetadata)) {
915
- return false;
916
- }
917
- break;
918
- case DecoratorTypes.OBJECT:
919
- const entityObject = entity[key];
920
- for (const parameterKey in entityObject) {
921
- const value = entityObject[parameterKey];
922
- if (!metadata.omit.includes(parameterKey)
923
- && !(!metadata.required(entity) && (value == null || value == ''))) {
924
- if (!EntityUtilities.isPropertyValid(entityObject, parameterKey, omit)) {
925
- return false;
926
- }
927
- }
928
- }
929
- break;
930
- case DecoratorTypes.ARRAY_STRING_CHIPS:
931
- case DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS:
921
+ case DecoratorTypes.DATE_RANGE:
922
+ return this.isEqualDateRange(value, valuePriorChanges, metadata.filter);
923
+ case DecoratorTypes.DATE:
924
+ return this.isEqualDate(value, valuePriorChanges);
925
+ case DecoratorTypes.DATE_TIME:
926
+ return this.isEqualDateTime(value, valuePriorChanges);
932
927
  case DecoratorTypes.ARRAY_DATE:
933
928
  case DecoratorTypes.ARRAY_DATE_TIME:
929
+ return this.isEqualArrayDate(value, valuePriorChanges);
934
930
  case DecoratorTypes.ARRAY_DATE_RANGE:
935
- case DecoratorTypes.ARRAY:
936
- const entityArray = entity[key];
937
- // eslint-disable-next-line max-len
938
- const arrayMetadata = metadata;
939
- if (arrayMetadata.required(entity) && !entityArray.length) {
940
- return false;
941
- }
942
- break;
943
- case DecoratorTypes.DATE:
944
- const entityDate = new Date(entity[key]);
945
- const dateMetadata = metadata;
946
- if (!EntityUtilities.isDateValid(entityDate, dateMetadata)) {
947
- return false;
948
- }
949
- break;
950
- case DecoratorTypes.DATE_RANGE:
951
- const entityDateRange = LodashUtilities.cloneDeep(entity[key]);
952
- const dateRangeMetadata = metadata;
953
- if (!EntityUtilities.isDateRangeValid(entity, entityDateRange, dateRangeMetadata)) {
954
- return false;
955
- }
956
- break;
957
- case DecoratorTypes.DATE_TIME:
958
- const entityDateTime = new Date(entity[key]);
959
- const dateTimeMetadata = metadata;
960
- const hasTime = ReflectUtilities.hasMetadata(this.TIME_KEY, entity, key);
961
- if (!EntityUtilities.isDateTimeValid(entityDateTime, dateTimeMetadata, hasTime)) {
962
- return false;
963
- }
964
- break;
965
- case DecoratorTypes.FILE_DEFAULT:
931
+ return this.isEqualArrayDateRange(value, valuePriorChanges, metadata.filter);
932
+ case DecoratorTypes.ARRAY_STRING_CHIPS:
933
+ case DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS:
934
+ return this.isEqualArrayString(value, valuePriorChanges);
966
935
  case DecoratorTypes.FILE_IMAGE:
967
- const entityFile = entity[key];
968
- const entityFileMetadata = metadata;
969
- if (!EntityUtilities.isFileDataValid(entityFile, entityFileMetadata)) {
970
- return false;
971
- }
972
- break;
973
- case DecoratorTypes.REFERENCES_MANY:
974
- case DecoratorTypes.REFERENCES_ONE:
975
- case DecoratorTypes.HAS_MANY:
976
- break;
936
+ case DecoratorTypes.FILE_DEFAULT:
937
+ return this.isEqualFile(value, valuePriorChanges, metadata.multiple, http);
977
938
  case DecoratorTypes.CUSTOM:
978
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, max-len
979
- const customMetadata = metadata;
980
- if (!customMetadata.isValid(entity[key], omit)) {
981
- return false;
982
- }
983
- break;
939
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
940
+ return this.isEqualCustom(value, valuePriorChanges, metadata);
984
941
  default:
985
- throw new Error(`Could not validate the input because the DecoratorType ${type} is not known`);
942
+ return LodashUtilities.isEqual(value, valuePriorChanges);
986
943
  }
987
- return true;
988
944
  }
989
- static isBooleanValid(entity, value, metadata) {
990
- if (metadata.required(entity) && !value) {
945
+ static isEqualArrayString(value, valuePriorChanges) {
946
+ const stringArray = LodashUtilities.cloneDeep(value).sort();
947
+ const stringArrayPriorChanges = LodashUtilities.cloneDeep(valuePriorChanges).sort();
948
+ return LodashUtilities.isEqual(stringArray, stringArrayPriorChanges);
949
+ }
950
+ static isEqualArrayDate(value, valuePriorChanges) {
951
+ const newValue = value.map(v => new Date(v)).sort();
952
+ const newValuePriorChanges = valuePriorChanges.map(v => new Date(v)).sort();
953
+ return LodashUtilities.isEqual(newValue, newValuePriorChanges);
954
+ }
955
+ static isEqualArrayDateRange(value, valuePriorChanges, filter) {
956
+ const dateRanges = value.sort();
957
+ const dateRangesPriorChanges = valuePriorChanges.sort();
958
+ if (dateRanges.length !== dateRangesPriorChanges.length) {
991
959
  return false;
992
960
  }
961
+ for (let i = 0; i < dateRanges.length; i++) {
962
+ if (!this.isEqualDateRange(dateRanges[i], dateRangesPriorChanges[i], filter)) {
963
+ return false;
964
+ }
965
+ }
993
966
  return true;
994
967
  }
995
- static isStringValid(value, metadata) {
996
- if (metadata.maxLength && value.length > metadata.maxLength) {
997
- return false;
968
+ static isEqualDateTime(value, valuePriorChanges) {
969
+ const date = new Date(value);
970
+ const datePriorChanges = new Date(valuePriorChanges);
971
+ return LodashUtilities.isEqual(date, datePriorChanges);
972
+ }
973
+ static isEqualDate(value, valuePriorChanges) {
974
+ const date = new Date(value);
975
+ const datePriorChanges = new Date(valuePriorChanges);
976
+ date.setHours(0, 0, 0, 0);
977
+ datePriorChanges.setHours(0, 0, 0, 0);
978
+ return LodashUtilities.isEqual(date, datePriorChanges);
979
+ }
980
+ static isEqualDateRange(value, valuePriorChanges, filter) {
981
+ const dateRange = LodashUtilities.cloneDeep(value);
982
+ dateRange.start = new Date(value.start);
983
+ dateRange.end = new Date(value.end);
984
+ dateRange.values = DateUtilities.getDatesBetween(dateRange.start, dateRange.end, filter);
985
+ const dateRangePriorChanges = LodashUtilities.cloneDeep(valuePriorChanges);
986
+ dateRangePriorChanges.start = new Date(valuePriorChanges.start);
987
+ dateRangePriorChanges.end = new Date(valuePriorChanges.end);
988
+ dateRangePriorChanges.values = DateUtilities.getDatesBetween(dateRangePriorChanges.start, dateRangePriorChanges.end, filter);
989
+ return LodashUtilities.isEqual(dateRange, dateRangePriorChanges);
990
+ }
991
+ // TODO: Find a way to use blobs with jest
992
+ /* istanbul ignore next */
993
+ static async isEqualFile(value, valuePriorChanges, multiple, http) {
994
+ if (value == null) {
995
+ if (valuePriorChanges == null) {
996
+ return true;
997
+ }
998
+ else {
999
+ return false;
1000
+ }
998
1001
  }
999
- if (metadata.minLength && value.length < metadata.minLength) {
1002
+ const files = multiple ? value.sort() : [value].sort();
1003
+ const filesPriorChanges = multiple ? valuePriorChanges.sort() : [valuePriorChanges].sort();
1004
+ if (files.length !== filesPriorChanges.length) {
1000
1005
  return false;
1001
1006
  }
1002
- if (metadata.regex && !value.match(metadata.regex)) {
1003
- return false;
1007
+ for (let i = 0; i < files.length; i++) {
1008
+ // checks this before actually getting any files due to performance reasons.
1009
+ if (!LodashUtilities.isEqual(LodashUtilities.omit(files[i], 'file'), LodashUtilities.omit(filesPriorChanges[i], 'file'))) {
1010
+ return false;
1011
+ }
1012
+ if (filesPriorChanges[i].file && !files[i].file) {
1013
+ files[i] = await FileUtilities.getFileData(files[i], http);
1014
+ value = files[i];
1015
+ }
1016
+ if (files[i].file && !filesPriorChanges[i].file) {
1017
+ filesPriorChanges[i] = await FileUtilities.getFileData(filesPriorChanges[i], http);
1018
+ valuePriorChanges = filesPriorChanges[i];
1019
+ }
1020
+ if (!LodashUtilities.isEqual(await files[i].file?.text(), await filesPriorChanges[i].file?.text())) {
1021
+ return false;
1022
+ }
1004
1023
  }
1005
1024
  return true;
1006
1025
  }
1007
- static isTextboxValid(value, metadata) {
1008
- if (metadata.maxLength && value.length > metadata.maxLength) {
1009
- return false;
1010
- }
1011
- if (metadata.minLength && value.length < metadata.minLength) {
1012
- return false;
1013
- }
1014
- return true;
1015
- }
1016
- static isPasswordValid(value, metadata, confirmPassword) {
1017
- if (value !== confirmPassword) {
1018
- return false;
1019
- }
1020
- if (metadata.maxLength && value.length > metadata.maxLength) {
1021
- return false;
1022
- }
1023
- if (metadata.minLength && value.length < metadata.minLength) {
1024
- return false;
1025
- }
1026
- if (metadata.regex && !value.match(metadata.regex)) {
1026
+ static isEqualCustom(value, valuePriorChanges,
1027
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1028
+ metadata) {
1029
+ if (!metadata.isEqual(value, valuePriorChanges, metadata)) {
1027
1030
  return false;
1028
1031
  }
1029
1032
  return true;
1030
1033
  }
1031
- static isNumberValid(value, metadata) {
1032
- if (metadata.max && value > metadata.max) {
1033
- return false;
1034
+ /**
1035
+ * Compare function for sorting entity keys by their order value.
1036
+ *
1037
+ * @param a - First key of entity.
1038
+ * @param b - Second key of entity.
1039
+ * @param entity - Current entity (used to get metadata of entity keys).
1040
+ * @returns 0 if both values have the same order, a negative value if 'a' comes before 'b', a positive value if 'a' comes behind 'b'.
1041
+ */
1042
+ static compareOrder(a, b, entity) {
1043
+ const metadataA = this.getPropertyMetadata(entity, a);
1044
+ const metadataB = this.getPropertyMetadata(entity, b);
1045
+ if (metadataA.position.order === -1) {
1046
+ if (metadataB.position.order === -1) {
1047
+ return 0;
1048
+ }
1049
+ return 1;
1034
1050
  }
1035
- if (metadata.min && value < metadata.min) {
1036
- return false;
1051
+ else if (metadataB.position.order === -1) {
1052
+ return -1;
1037
1053
  }
1038
- return true;
1054
+ return metadataA.position.order - metadataB.position.order;
1039
1055
  }
1040
- static isDateValid(value, metadata) {
1041
- if (metadata.min && value.getTime() < metadata.min(value).getTime()) {
1042
- return false;
1043
- }
1044
- if (metadata.max && value.getTime() > metadata.max(value).getTime()) {
1045
- return false;
1046
- }
1047
- if (metadata.filter && !metadata.filter(value)) {
1048
- return false;
1056
+ /**
1057
+ * Gets the bootstrap column values for "lg", "md", "sm".
1058
+ *
1059
+ * @param entity - Entity to get the bootstrap column values of the key.
1060
+ * @param key - Key of the property to get bootstrap column values from.
1061
+ * @param type - Defines for which screen size the column values should be returned.
1062
+ * @returns Bootstrap column value.
1063
+ */
1064
+ static getWidth(entity, key, type) {
1065
+ const metadata = this.getPropertyMetadata(entity, key);
1066
+ switch (type) {
1067
+ case 'lg':
1068
+ return metadata.defaultWidths[0];
1069
+ case 'md':
1070
+ return metadata.defaultWidths[1];
1071
+ case 'sm':
1072
+ return metadata.defaultWidths[2];
1049
1073
  }
1050
- return true;
1051
1074
  }
1052
- static isDateRangeValid(entity, value, metadata) {
1053
- if (metadata.required(entity)) {
1054
- if (!value.start) {
1055
- return false;
1056
- }
1057
- if (!value.end) {
1058
- return false;
1059
- }
1060
- }
1061
- value.start = new Date(value.start);
1062
- value.end = new Date(value.end);
1063
- if (metadata.minStart && value.start.getTime() < metadata.minStart(value.start).getTime()) {
1064
- return false;
1065
- }
1066
- if (metadata.maxStart && value.start.getTime() > metadata.maxStart(value.start).getTime()) {
1067
- return false;
1068
- }
1069
- if (metadata.minEnd && value.end.getTime() < metadata.minEnd(value.end).getTime()) {
1070
- return false;
1071
- }
1072
- if (metadata.maxEnd && value.end.getTime() > metadata.maxEnd(value.end).getTime()) {
1073
- return false;
1074
- }
1075
- if (metadata.filter) {
1076
- if (!metadata.filter(value.start)) {
1077
- return false;
1078
- }
1079
- if (!metadata.filter(value.end)) {
1080
- return false;
1081
- }
1082
- if (value.values) {
1083
- for (const date of value.values) {
1084
- if (!metadata.filter(date)) {
1085
- return false;
1075
+ /**
1076
+ * Resets all changes on an entity.
1077
+ *
1078
+ * @param entity - The entity to reset.
1079
+ * @param entityPriorChanges - The entity before any changes.
1080
+ */
1081
+ static resetChangesOnEntity(entity, entityPriorChanges) {
1082
+ for (const key in entityPriorChanges) {
1083
+ ReflectUtilities.set(entity, key, ReflectUtilities.get(entityPriorChanges, key));
1084
+ if (ReflectUtilities.hasMetadata(this.METADATA_KEYS_TO_RESET_KEY, entity, key)) {
1085
+ for (const k of ReflectUtilities.getMetadata(this.METADATA_KEYS_TO_RESET_KEY, entity, key)) {
1086
+ if (ReflectUtilities.hasMetadata(k, entity, key)) {
1087
+ ReflectUtilities.defineMetadata(k, undefined, entity, key);
1086
1088
  }
1087
1089
  }
1088
1090
  }
1089
1091
  }
1090
- return true;
1091
1092
  }
1092
- static isDateTimeValid(value, metadata, hasTime) {
1093
- if (!hasTime) {
1094
- return false;
1095
- }
1096
- if (metadata.minDate && value.getTime() < metadata.minDate(value).getTime()) {
1097
- return false;
1098
- }
1099
- if (metadata.maxDate && value.getTime() > metadata.maxDate(value).getTime()) {
1100
- return false;
1101
- }
1102
- if (metadata.filterDate && !metadata.filterDate(value)) {
1103
- return false;
1093
+ static getEntityRows(entity, tab, hideOmitForCreate, hideOmitForEdit, additionalOmitValues) {
1094
+ const res = [];
1095
+ const keys = this.keysOf(entity, hideOmitForCreate, hideOmitForEdit)
1096
+ .filter(k => !additionalOmitValues.includes(k));
1097
+ const numberOfRows = this.getNumberOfRows(keys, entity, tab);
1098
+ for (let i = 1; i <= numberOfRows; i++) {
1099
+ const row = {
1100
+ row: i,
1101
+ keys: this.getKeysForRow(keys, entity, i, tab)
1102
+ };
1103
+ res.push(row);
1104
1104
  }
1105
- const time = {
1106
- hours: value.getHours(),
1107
- minutes: value.getMinutes()
1108
- };
1109
- if (metadata.minTime) {
1110
- const minTime = metadata.minTime(value);
1111
- if (!(time.hours > minTime.hours
1112
- || (time.hours === minTime.hours
1113
- && time.minutes >= minTime.minutes))) {
1114
- return false;
1115
- }
1105
+ if (this.getKeysForRow(keys, entity, -1, tab).length) {
1106
+ const lastRow = {
1107
+ row: numberOfRows + 1,
1108
+ keys: this.getKeysForRow(keys, entity, -1, tab)
1109
+ };
1110
+ res.push(lastRow);
1116
1111
  }
1117
- if (metadata.maxTime) {
1118
- const maxTime = metadata.maxTime(value);
1119
- if (!(time.hours < maxTime.hours
1120
- || (time.hours === maxTime.hours
1121
- && time.minutes <= maxTime.minutes))) {
1122
- return false;
1123
- }
1112
+ return res;
1113
+ }
1114
+ /**
1115
+ * Gets the tabs that are used to display the given entity.
1116
+ *
1117
+ * @param entity - The entity to get the rows from.
1118
+ * @param hideOmitForCreate - Whether or not keys with the metadata omitForCreate should be filtered out.
1119
+ * @param hideOmitForEdit - Whether or not keys with the metadata omitForUpdate should be filtered out.
1120
+ * @param additionalOmitValues - Additional omit values.
1121
+ * @returns The sorted Tabs containing the rows and the keys to display in that row.
1122
+ */
1123
+ static getEntityTabs(entity, hideOmitForCreate = false, hideOmitForEdit = false, additionalOmitValues = []) {
1124
+ const res = [];
1125
+ const keys = this.keysOf(entity, hideOmitForCreate, hideOmitForEdit)
1126
+ .filter(k => !additionalOmitValues.includes(k));
1127
+ const numberOfTabs = this.getNumberOfTabs(keys, entity);
1128
+ // eslint-disable-next-line max-len
1129
+ const firstTabRows = this.getEntityRows(entity, -1, hideOmitForCreate, hideOmitForEdit, additionalOmitValues);
1130
+ if (firstTabRows.length) {
1131
+ const firstTab = {
1132
+ tabName: this.getFirstTabName(entity),
1133
+ tab: -1,
1134
+ rows: firstTabRows
1135
+ };
1136
+ res.push(firstTab);
1124
1137
  }
1125
- if (metadata.filterTime) {
1126
- if (!metadata.filterTime(time)) {
1127
- return false;
1138
+ for (let i = 2; i <= numberOfTabs; i++) {
1139
+ const rows = this.getEntityRows(entity, i, hideOmitForCreate, hideOmitForEdit, additionalOmitValues);
1140
+ if (rows.length) {
1141
+ const tab = {
1142
+ tabName: this.getTabName(entity, i),
1143
+ tab: i,
1144
+ rows: rows
1145
+ };
1146
+ res.push(tab);
1128
1147
  }
1129
1148
  }
1130
- return true;
1149
+ return res;
1131
1150
  }
1132
- static isFileDataValid(value, metadata) {
1133
- const files = metadata.multiple ? value : [value];
1134
- let fileSizeTotal = 0;
1135
- for (const file of files) {
1136
- if (!file.name || !file.file && !file.url) {
1137
- return false;
1138
- }
1139
- if (!FileUtilities.isMimeTypeValid(file.type, metadata.allowedMimeTypes)) {
1140
- return false;
1141
- }
1142
- if (FileUtilities.transformToMegaBytes(file.size, 'B') > metadata.maxSize) {
1143
- return false;
1144
- }
1145
- fileSizeTotal += file.size;
1146
- if (FileUtilities.transformToMegaBytes(fileSizeTotal, 'B') > metadata.maxSizeTotal) {
1147
- return false;
1148
- }
1149
- }
1150
- return true;
1151
+ static getKeysForRow(keys, entity, row, tab) {
1152
+ return keys
1153
+ .filter(k => this.getPropertyMetadata(entity, k).position.row === row)
1154
+ .filter(k => this.getPropertyMetadata(entity, k).position.tab === tab)
1155
+ .sort((a, b) => this.compareOrder(a, b, entity));
1156
+ }
1157
+ static getNumberOfRows(keys, entity, tab) {
1158
+ return keys
1159
+ .filter(k => this.getPropertyMetadata(entity, k).position.tab === tab)
1160
+ .map(k => this.getPropertyMetadata(entity, k).position.row)
1161
+ .sort((a, b) => (a > b ? -1 : 1))[0];
1162
+ }
1163
+ static getNumberOfTabs(keys, entity) {
1164
+ return keys
1165
+ .map(k => this.getPropertyMetadata(entity, k).position.tab)
1166
+ .sort((a, b) => (a > b ? -1 : 1))[0];
1167
+ }
1168
+ static getTabName(entity, tab) {
1169
+ const providedTabName = ReflectUtilities.ownKeys(entity)
1170
+ .map(k => this.getPropertyMetadata(entity, k))
1171
+ .find(m => m.position.tab === tab && m.position.tabName)?.position.tabName;
1172
+ return providedTabName ?? `Tab ${tab}`;
1173
+ }
1174
+ static getFirstTabName(entity) {
1175
+ const providedTabName = ReflectUtilities.ownKeys(entity)
1176
+ .map(k => this.getPropertyMetadata(entity, k))
1177
+ .find(m => m.position.tabName && m.position.tab === -1)?.position.tabName;
1178
+ return providedTabName ?? 'Tab 1';
1151
1179
  }
1152
1180
  /**
1153
- * Checks if an entity is "dirty" (if its values have changed).
1181
+ * Gets the keys of the provided entity correctly typed.
1154
1182
  *
1155
- * @param entity - The entity after all changes.
1156
- * @param entityPriorChanges - The entity before the changes.
1157
- * @param http - The angular HttpClient. Used to fetch files.
1158
- * @returns Whether or not the entity is dirty.
1183
+ * @param entity - The entity to get the keys of.
1184
+ * @param hideOmitForCreate - Whether or not keys with the metadata omitForCreate should be filtered out.
1185
+ * @param hideOmitForEdit - Whether or not keys with the metadata omitForUpdate should be filtered out.
1186
+ * @returns An array of keys of the entity.
1159
1187
  */
1160
- static async isDirty(entity, entityPriorChanges, http) {
1161
- if (!entityPriorChanges) {
1162
- return false;
1188
+ static keysOf(entity, hideOmitForCreate = false, hideOmitForEdit = false) {
1189
+ let keys = ReflectUtilities.ownKeys(entity);
1190
+ const dontDisplayKeys = this.getDontDisplayKeys(entity);
1191
+ keys = keys.filter(k => !dontDisplayKeys.includes(k));
1192
+ if (hideOmitForCreate) {
1193
+ const omitForCreateKeys = this.getOmitForCreate(entity);
1194
+ keys = keys.filter(k => !omitForCreateKeys.includes(k));
1163
1195
  }
1164
- const differences = await EntityUtilities.differencesForDirty(entity, entityPriorChanges, http);
1165
- return differences.length ? true : false;
1196
+ if (hideOmitForEdit) {
1197
+ const omitForUpdateKeys = this.getOmitForUpdate(entity);
1198
+ keys = keys.filter(k => !omitForUpdateKeys.includes(k));
1199
+ }
1200
+ return keys;
1166
1201
  }
1167
- static async differencesForDirty(entity, entityPriorChanges, http) {
1202
+ static getDontDisplayKeys(entity) {
1168
1203
  const res = [];
1169
1204
  for (const key of ReflectUtilities.ownKeys(entity)) {
1170
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
1171
- const type = EntityUtilities.getPropertyType(entity, key);
1172
- if (!(await EntityUtilities.isEqual(entity[key], entityPriorChanges[key], metadata, type, http))) {
1173
- res.push({
1174
- key: key,
1175
- before: entityPriorChanges[key],
1176
- after: entity[key]
1177
- });
1178
- }
1179
- else {
1180
- // This is needed to set blob file data so that it is only requested once.
1181
- entityPriorChanges[key] = LodashUtilities.cloneDeep(entity[key]);
1205
+ const metadata = this.getPropertyMetadata(entity, key);
1206
+ if (!metadata.display(entity)) {
1207
+ res.push(key);
1182
1208
  }
1183
1209
  }
1184
1210
  return res;
1185
1211
  }
1186
- // TODO Remove
1187
- /**
1188
- * Compares two Entities and returns their difference in an object.
1189
- *
1190
- * @param entity - The first entity to compare.
1191
- * @param entityPriorChanges - The second entity to compare.
1192
- * @returns The difference between the two Entities in form of a Partial.
1193
- */
1194
- // static async difference<EntityType extends BaseEntityType<EntityType>>(
1195
- // entity: EntityType,
1196
- // entityPriorChanges: EntityType
1197
- // ): Promise<Partial<EntityType>> {
1198
- // const res: Partial<EntityType> = {};
1199
- // for (const key in entity) {
1200
- // const metadata: PropertyDecoratorConfigInternal = EntityUtilities.getPropertyMetadata(entity, key);
1201
- // const type: DecoratorTypes = EntityUtilities.getPropertyType(entity, key);
1202
- // if (!(await EntityUtilities.isEqual(entity[key], entityPriorChanges[key], metadata, type))) {
1203
- // res[key] = entity[key];
1204
- // }
1205
- // }
1206
- // return res;
1207
- // }
1208
- /**
1209
- * Checks if two given values are equal.
1210
- * It uses the isEqual method from LodashUtilities and extends it with functionality regarding Dates.
1211
- *
1212
- * @param value - The updated value.
1213
- * @param valuePriorChanges - The value before any changes.
1214
- * @param metadata - The metadata of the property.
1215
- * @param type - The type of the property.
1216
- * @param http - The angular HttpClient. Used to fetch files.
1217
- * @returns Whether or not the given values are equal.
1218
- */
1219
- static async isEqual(value, valuePriorChanges, metadata, type, http) {
1220
- switch (type) {
1221
- case DecoratorTypes.DATE_RANGE:
1222
- return EntityUtilities.isEqualDateRange(value, valuePriorChanges, metadata.filter);
1223
- case DecoratorTypes.DATE:
1224
- return EntityUtilities.isEqualDate(value, valuePriorChanges);
1225
- case DecoratorTypes.DATE_TIME:
1226
- return EntityUtilities.isEqualDateTime(value, valuePriorChanges);
1227
- case DecoratorTypes.ARRAY_DATE:
1228
- case DecoratorTypes.ARRAY_DATE_TIME:
1229
- return EntityUtilities.isEqualArrayDate(value, valuePriorChanges);
1230
- case DecoratorTypes.ARRAY_DATE_RANGE:
1231
- return EntityUtilities.isEqualArrayDateRange(value, valuePriorChanges, metadata.filter);
1232
- case DecoratorTypes.ARRAY_STRING_CHIPS:
1233
- case DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS:
1234
- return EntityUtilities.isEqualArrayString(value, valuePriorChanges);
1235
- case DecoratorTypes.FILE_IMAGE:
1236
- case DecoratorTypes.FILE_DEFAULT:
1237
- // eslint-disable-next-line max-len
1238
- return EntityUtilities.isEqualFile(value, valuePriorChanges, metadata.multiple, http);
1239
- case DecoratorTypes.CUSTOM:
1240
- // eslint-disable-next-line max-len, @typescript-eslint/no-explicit-any
1241
- return EntityUtilities.isEqualCustom(value, valuePriorChanges, metadata);
1242
- default:
1243
- return LodashUtilities.isEqual(value, valuePriorChanges);
1244
- }
1245
- }
1246
- static isEqualArrayString(value, valuePriorChanges) {
1247
- const stringArray = LodashUtilities.cloneDeep(value).sort();
1248
- const stringArrayPriorChanges = LodashUtilities.cloneDeep(valuePriorChanges).sort();
1249
- return LodashUtilities.isEqual(stringArray, stringArrayPriorChanges);
1250
- }
1251
- static isEqualArrayDate(value, valuePriorChanges) {
1252
- const newValue = value.map(v => new Date(v)).sort();
1253
- const newValuePriorChanges = valuePriorChanges.map(v => new Date(v)).sort();
1254
- return LodashUtilities.isEqual(newValue, newValuePriorChanges);
1255
- }
1256
- static isEqualArrayDateRange(value, valuePriorChanges, filter) {
1257
- const dateRanges = value.sort();
1258
- const dateRangesPriorChanges = valuePriorChanges.sort();
1259
- if (dateRanges.length !== dateRangesPriorChanges.length) {
1260
- return false;
1261
- }
1262
- for (let i = 0; i < dateRanges.length; i++) {
1263
- if (!EntityUtilities.isEqualDateRange(dateRanges[i], dateRangesPriorChanges[i], filter)) {
1264
- return false;
1265
- }
1266
- }
1267
- return true;
1268
- }
1269
- static isEqualDateTime(value, valuePriorChanges) {
1270
- const date = new Date(value);
1271
- const datePriorChanges = new Date(valuePriorChanges);
1272
- return LodashUtilities.isEqual(date, datePriorChanges);
1273
- }
1274
- static isEqualDate(value, valuePriorChanges) {
1275
- const date = new Date(value);
1276
- const datePriorChanges = new Date(valuePriorChanges);
1277
- date.setHours(0, 0, 0, 0);
1278
- datePriorChanges.setHours(0, 0, 0, 0);
1279
- return LodashUtilities.isEqual(date, datePriorChanges);
1280
- }
1281
- static isEqualDateRange(value, valuePriorChanges, filter) {
1282
- const dateRange = LodashUtilities.cloneDeep(value);
1283
- dateRange.start = new Date(value.start);
1284
- dateRange.end = new Date(value.end);
1285
- dateRange.values = DateUtilities.getDatesBetween(dateRange.start, dateRange.end, filter);
1286
- const dateRangePriorChanges = LodashUtilities.cloneDeep(valuePriorChanges);
1287
- dateRangePriorChanges.start = new Date(valuePriorChanges.start);
1288
- dateRangePriorChanges.end = new Date(valuePriorChanges.end);
1289
- dateRangePriorChanges.values = DateUtilities.getDatesBetween(dateRangePriorChanges.start, dateRangePriorChanges.end, filter);
1290
- return LodashUtilities.isEqual(dateRange, dateRangePriorChanges);
1212
+ }
1213
+
1214
+ /**
1215
+ * The base decorator for setting metadata on properties.
1216
+ *
1217
+ * @param metadata - The metadata to define.
1218
+ * @param type - The type of metadata.
1219
+ * @param metadataKeysToReset - Any metadata keys which values should be set to undefined on reset.
1220
+ * @returns The method that sets the metadata.
1221
+ */
1222
+ function baseProperty(metadata, type, metadataKeysToReset) {
1223
+ return function (target, propertyKey) {
1224
+ ReflectUtilities.defineMetadata('metadata', metadata, target, propertyKey);
1225
+ ReflectUtilities.defineMetadata('type', type, target, propertyKey);
1226
+ // eslint-disable-next-line max-len
1227
+ ReflectUtilities.defineMetadata(EntityUtilities.METADATA_KEYS_TO_RESET_KEY, metadataKeysToReset, target, propertyKey);
1228
+ };
1229
+ }
1230
+
1231
+ /**
1232
+ * The default false function.
1233
+ * A boolean false is resolved to this.
1234
+ *
1235
+ * @returns False.
1236
+ */
1237
+ function defaultFalse() {
1238
+ return false;
1239
+ }
1240
+
1241
+ /**
1242
+ * The internal Position. Sets default values and validates user input.
1243
+ */
1244
+ class PositionInternal {
1245
+ // eslint-disable-next-line jsdoc/require-jsdoc
1246
+ row;
1247
+ // eslint-disable-next-line jsdoc/require-jsdoc
1248
+ order;
1249
+ // eslint-disable-next-line jsdoc/require-jsdoc
1250
+ tab;
1251
+ // eslint-disable-next-line jsdoc/require-jsdoc
1252
+ tabName;
1253
+ constructor(data) {
1254
+ this.validateInput(data);
1255
+ this.row = data?.row ?? -1;
1256
+ this.order = data?.order ?? -1;
1257
+ this.tab = data?.tab ?? -1;
1258
+ this.tabName = data?.tabName;
1291
1259
  }
1292
- // TODO: Find a way to use blobs with jest
1293
- /* istanbul ignore next */
1294
- static async isEqualFile(value, valuePriorChanges, multiple, http) {
1295
- if (value == null) {
1296
- if (valuePriorChanges == null) {
1297
- return true;
1260
+ validateInput(data) {
1261
+ if (data?.order != null) {
1262
+ if (data.order < 1) {
1263
+ throw new Error('order must be at least 1');
1298
1264
  }
1299
- else {
1300
- return false;
1265
+ if (data.order > 12) {
1266
+ throw new Error('order cannot be bigger than 12 (the minimum value for a bootstrap column)');
1301
1267
  }
1302
1268
  }
1303
- const files = multiple ? value.sort() : [value].sort();
1304
- const filesPriorChanges = multiple ? valuePriorChanges.sort() : [valuePriorChanges].sort();
1305
- if (files.length !== filesPriorChanges.length) {
1306
- return false;
1269
+ if (data?.row != null && data.row < 1) {
1270
+ throw new Error('row must be at least 1');
1307
1271
  }
1308
- for (let i = 0; i < files.length; i++) {
1309
- // checks this before actually getting any files due to performance reasons.
1310
- if (!LodashUtilities.isEqual(LodashUtilities.omit(files[i], 'file'), LodashUtilities.omit(filesPriorChanges[i], 'file'))) {
1311
- return false;
1312
- }
1313
- if (filesPriorChanges[i].file && !files[i].file) {
1314
- files[i] = await FileUtilities.getFileData(files[i], http);
1315
- value = files[i];
1316
- }
1317
- if (files[i].file && !filesPriorChanges[i].file) {
1318
- filesPriorChanges[i] = await FileUtilities.getFileData(filesPriorChanges[i], http);
1319
- valuePriorChanges = filesPriorChanges[i];
1320
- }
1321
- if (!LodashUtilities.isEqual(await files[i].file?.text(), await filesPriorChanges[i].file?.text())) {
1322
- return false;
1323
- }
1272
+ if (data?.tab != null && data.tab != -1 && data.tab < 2) {
1273
+ throw new Error('tab must be either -1 for the first tab or at least 2');
1324
1274
  }
1325
- return true;
1326
1275
  }
1327
- static isEqualCustom(value, valuePriorChanges,
1328
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1329
- metadata) {
1330
- if (!metadata.isEqual(value, valuePriorChanges, metadata)) {
1331
- return false;
1332
- }
1333
- return true;
1276
+ }
1277
+ /**
1278
+ * The internal PropertyDecoratorConfig. Sets default values.
1279
+ */
1280
+ class PropertyDecoratorConfigInternal {
1281
+ // eslint-disable-next-line jsdoc/require-jsdoc
1282
+ display;
1283
+ // eslint-disable-next-line jsdoc/require-jsdoc
1284
+ displayName;
1285
+ // eslint-disable-next-line jsdoc/require-jsdoc
1286
+ required;
1287
+ // eslint-disable-next-line jsdoc/require-jsdoc
1288
+ omitForCreate;
1289
+ // eslint-disable-next-line jsdoc/require-jsdoc
1290
+ omitForUpdate;
1291
+ // eslint-disable-next-line jsdoc/require-jsdoc
1292
+ defaultWidths;
1293
+ // eslint-disable-next-line jsdoc/require-jsdoc
1294
+ position;
1295
+ // eslint-disable-next-line jsdoc/require-jsdoc
1296
+ isReadOnly;
1297
+ // eslint-disable-next-line jsdoc/require-jsdoc
1298
+ default;
1299
+ // eslint-disable-next-line jsdoc/require-jsdoc
1300
+ change;
1301
+ constructor(data) {
1302
+ this.display = this.booleanToFunction(data.display ?? true);
1303
+ this.displayName = data.displayName;
1304
+ this.required = this.booleanToFunction(data.required ?? true);
1305
+ this.omitForCreate = data.omitForCreate ?? false;
1306
+ this.omitForUpdate = data.omitForUpdate ?? false;
1307
+ this.defaultWidths = data.defaultWidths ?? [6, 6, 12];
1308
+ this.position = new PositionInternal(data.position);
1309
+ this.isReadOnly = this.booleanToFunction(data.isReadOnly ?? false);
1310
+ this.default = this.defaultToFunction(data.default);
1311
+ this.change = data.change;
1334
1312
  }
1335
1313
  /**
1336
- * Compare function for sorting entity keys by their order value.
1314
+ * Converts the default value to a function or undefined.
1337
1315
  *
1338
- * @param a - First key of entity.
1339
- * @param b - Second key of entity.
1340
- * @param entity - Current entity (used to get metadata of entity keys).
1341
- * @returns 0 if both values have the same order, a negative value if 'a' comes before 'b', a positive value if 'a' comes behind 'b'.
1316
+ * @param value - The default value provided by the metadata.
1317
+ * @returns A function that returns a default value or undefined.
1342
1318
  */
1343
- static compareOrder(a, b, entity) {
1344
- const metadataA = EntityUtilities.getPropertyMetadata(entity, a);
1345
- const metadataB = EntityUtilities.getPropertyMetadata(entity, b);
1346
- if (metadataA.position.order === -1) {
1347
- if (metadataB.position.order === -1) {
1348
- return 0;
1349
- }
1350
- return 1;
1319
+ defaultToFunction(value) {
1320
+ if (value == null) {
1321
+ return undefined;
1351
1322
  }
1352
- else if (metadataB.position.order === -1) {
1353
- return -1;
1323
+ if (typeof value == 'function') {
1324
+ return value;
1354
1325
  }
1355
- return metadataA.position.order - metadataB.position.order;
1326
+ return (() => value);
1356
1327
  }
1357
1328
  /**
1358
- * Gets the bootstrap column values for "lg", "md", "sm".
1329
+ * Converts the given boolean or boolean function to a boolean function.
1359
1330
  *
1360
- * @param entity - Entity to get the bootstrap column values of the key.
1361
- * @param key - Key of the property to get bootstrap column values from.
1362
- * @param type - Defines for which screen size the column values should be returned.
1363
- * @returns Bootstrap column value.
1331
+ * @param value - The value to convert.
1332
+ * @returns A function that resolves to a boolean.
1364
1333
  */
1365
- static getWidth(entity, key, type) {
1366
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
1367
- switch (type) {
1368
- case 'lg':
1369
- return metadata.defaultWidths[0];
1370
- case 'md':
1371
- return metadata.defaultWidths[1];
1372
- case 'sm':
1373
- return metadata.defaultWidths[2];
1334
+ booleanToFunction(value) {
1335
+ if (typeof value !== 'boolean') {
1336
+ return value;
1374
1337
  }
1375
- }
1376
- /**
1377
- * Resets all changes on an entity.
1378
- *
1379
- * @param entity - The entity to reset.
1380
- * @param entityPriorChanges - The entity before any changes.
1381
- */
1382
- static resetChangesOnEntity(entity, entityPriorChanges) {
1383
- for (const key in entityPriorChanges) {
1384
- ReflectUtilities.set(entity, key, ReflectUtilities.get(entityPriorChanges, key));
1385
- if (ReflectUtilities.hasMetadata(this.METADATA_KEYS_TO_RESET_KEY, entity, key)) {
1386
- for (const k of ReflectUtilities.getMetadata(this.METADATA_KEYS_TO_RESET_KEY, entity, key)) {
1387
- if (ReflectUtilities.hasMetadata(k, entity, key)) {
1388
- ReflectUtilities.defineMetadata(k, undefined, entity, key);
1389
- }
1390
- }
1391
- }
1392
- }
1393
- }
1394
- static getEntityRows(entity, tab, hideOmitForCreate, hideOmitForEdit, additionalOmitValues) {
1395
- const res = [];
1396
- const keys = EntityUtilities.keysOf(entity, hideOmitForCreate, hideOmitForEdit)
1397
- .filter(k => !additionalOmitValues.includes(k));
1398
- const numberOfRows = EntityUtilities.getNumberOfRows(keys, entity, tab);
1399
- for (let i = 1; i <= numberOfRows; i++) {
1400
- const row = {
1401
- row: i,
1402
- keys: EntityUtilities.getKeysForRow(keys, entity, i, tab)
1403
- };
1404
- res.push(row);
1405
- }
1406
- if (EntityUtilities.getKeysForRow(keys, entity, -1, tab).length) {
1407
- const lastRow = {
1408
- row: numberOfRows + 1,
1409
- keys: EntityUtilities.getKeysForRow(keys, entity, -1, tab)
1410
- };
1411
- res.push(lastRow);
1412
- }
1413
- return res;
1414
- }
1415
- /**
1416
- * Gets the tabs that are used to display the given entity.
1417
- *
1418
- * @param entity - The entity to get the rows from.
1419
- * @param hideOmitForCreate - Whether or not keys with the metadata omitForCreate should be filtered out.
1420
- * @param hideOmitForEdit - Whether or not keys with the metadata omitForUpdate should be filtered out.
1421
- * @param additionalOmitValues - Additional omit values.
1422
- * @returns The sorted Tabs containing the rows and the keys to display in that row.
1423
- */
1424
- static getEntityTabs(entity, hideOmitForCreate = false, hideOmitForEdit = false, additionalOmitValues = []) {
1425
- const res = [];
1426
- const keys = EntityUtilities.keysOf(entity, hideOmitForCreate, hideOmitForEdit)
1427
- .filter(k => !additionalOmitValues.includes(k));
1428
- const numberOfTabs = EntityUtilities.getNumberOfTabs(keys, entity);
1429
- // eslint-disable-next-line max-len
1430
- const firstTabRows = EntityUtilities.getEntityRows(entity, -1, hideOmitForCreate, hideOmitForEdit, additionalOmitValues);
1431
- if (firstTabRows.length) {
1432
- const firstTab = {
1433
- tabName: EntityUtilities.getFirstTabName(entity),
1434
- tab: -1,
1435
- rows: firstTabRows
1436
- };
1437
- res.push(firstTab);
1438
- }
1439
- for (let i = 2; i <= numberOfTabs; i++) {
1440
- const rows = EntityUtilities.getEntityRows(entity, i, hideOmitForCreate, hideOmitForEdit, additionalOmitValues);
1441
- if (rows.length) {
1442
- const tab = {
1443
- tabName: EntityUtilities.getTabName(entity, i),
1444
- tab: i,
1445
- rows: rows
1446
- };
1447
- res.push(tab);
1448
- }
1449
- }
1450
- return res;
1451
- }
1452
- static getKeysForRow(keys, entity, row, tab) {
1453
- return keys
1454
- .filter(k => EntityUtilities.getPropertyMetadata(entity, k).position.row === row)
1455
- .filter(k => EntityUtilities.getPropertyMetadata(entity, k).position.tab === tab)
1456
- .sort((a, b) => EntityUtilities.compareOrder(a, b, entity));
1457
- }
1458
- static getNumberOfRows(keys, entity, tab) {
1459
- return keys
1460
- .filter(k => EntityUtilities.getPropertyMetadata(entity, k).position.tab === tab)
1461
- .map(k => EntityUtilities.getPropertyMetadata(entity, k).position.row)
1462
- .sort((a, b) => (a > b ? -1 : 1))[0];
1463
- }
1464
- static getNumberOfTabs(keys, entity) {
1465
- return keys
1466
- .map(k => EntityUtilities.getPropertyMetadata(entity, k).position.tab)
1467
- .sort((a, b) => (a > b ? -1 : 1))[0];
1468
- }
1469
- static getTabName(entity, tab) {
1470
- const providedTabName = ReflectUtilities.ownKeys(entity)
1471
- .map(k => EntityUtilities.getPropertyMetadata(entity, k))
1472
- .find(m => m.position.tab === tab && m.position.tabName)?.position.tabName;
1473
- return providedTabName ?? `Tab ${tab}`;
1474
- }
1475
- static getFirstTabName(entity) {
1476
- const providedTabName = ReflectUtilities.ownKeys(entity)
1477
- .map(k => EntityUtilities.getPropertyMetadata(entity, k))
1478
- .find(m => m.position.tabName && m.position.tab === -1)?.position.tabName;
1479
- return providedTabName ?? 'Tab 1';
1480
- }
1481
- /**
1482
- * Gets the keys of the provided entity correctly typed.
1483
- *
1484
- * @param entity - The entity to get the keys of.
1485
- * @param hideOmitForCreate - Whether or not keys with the metadata omitForCreate should be filtered out.
1486
- * @param hideOmitForEdit - Whether or not keys with the metadata omitForUpdate should be filtered out.
1487
- * @returns An array of keys of the entity.
1488
- */
1489
- static keysOf(entity, hideOmitForCreate = false, hideOmitForEdit = false) {
1490
- let keys = ReflectUtilities.ownKeys(entity);
1491
- const dontDisplayKeys = EntityUtilities.getDontDisplayKeys(entity);
1492
- keys = keys.filter(k => !dontDisplayKeys.includes(k));
1493
- if (hideOmitForCreate) {
1494
- const omitForCreateKeys = EntityUtilities.getOmitForCreate(entity);
1495
- keys = keys.filter(k => !omitForCreateKeys.includes(k));
1496
- }
1497
- if (hideOmitForEdit) {
1498
- const omitForUpdateKeys = EntityUtilities.getOmitForUpdate(entity);
1499
- keys = keys.filter(k => !omitForUpdateKeys.includes(k));
1500
- }
1501
- return keys;
1502
- }
1503
- static getDontDisplayKeys(entity) {
1504
- const res = [];
1505
- for (const key of ReflectUtilities.ownKeys(entity)) {
1506
- const metadata = EntityUtilities.getPropertyMetadata(entity, key);
1507
- if (!metadata.display(entity)) {
1508
- res.push(key);
1509
- }
1510
- }
1511
- return res;
1512
- }
1513
- }
1514
-
1515
- /**
1516
- * The base decorator for setting metadata on properties.
1517
- *
1518
- * @param metadata - The metadata to define.
1519
- * @param type - The type of metadata.
1520
- * @param metadataKeysToReset - Any metadata keys which values should be set to undefined on reset.
1521
- * @returns The method that sets the metadata.
1522
- */
1523
- function baseProperty(metadata, type, metadataKeysToReset) {
1524
- return function (target, propertyKey) {
1525
- ReflectUtilities.defineMetadata('metadata', metadata, target, propertyKey);
1526
- ReflectUtilities.defineMetadata('type', type, target, propertyKey);
1527
- // eslint-disable-next-line max-len
1528
- ReflectUtilities.defineMetadata(EntityUtilities.METADATA_KEYS_TO_RESET_KEY, metadataKeysToReset, target, propertyKey);
1529
- };
1530
- }
1531
-
1532
- /**
1533
- * The default false function.
1534
- * A boolean false is resolved to this.
1535
- *
1536
- * @returns False.
1537
- */
1538
- function defaultFalse() {
1539
- return false;
1540
- }
1541
-
1542
- /**
1543
- * The internal Position. Sets default values and validates user input.
1544
- */
1545
- class PositionInternal {
1546
- // eslint-disable-next-line jsdoc/require-jsdoc
1547
- row;
1548
- // eslint-disable-next-line jsdoc/require-jsdoc
1549
- order;
1550
- // eslint-disable-next-line jsdoc/require-jsdoc
1551
- tab;
1552
- // eslint-disable-next-line jsdoc/require-jsdoc
1553
- tabName;
1554
- constructor(data) {
1555
- this.validateInput(data);
1556
- this.row = data?.row ?? -1;
1557
- this.order = data?.order ?? -1;
1558
- this.tab = data?.tab ?? -1;
1559
- this.tabName = data?.tabName;
1560
- }
1561
- validateInput(data) {
1562
- if (data?.order != null) {
1563
- if (data.order < 1) {
1564
- throw new Error('order must be at least 1');
1565
- }
1566
- if (data.order > 12) {
1567
- throw new Error('order cannot be bigger than 12 (the minimum value for a bootstrap column)');
1568
- }
1569
- }
1570
- if (data?.row != null && data.row < 1) {
1571
- throw new Error('row must be at least 1');
1572
- }
1573
- if (data?.tab != null && data.tab != -1 && data.tab < 2) {
1574
- throw new Error('tab must be either -1 for the first tab or at least 2');
1575
- }
1576
- }
1577
- }
1578
- /**
1579
- * The internal PropertyDecoratorConfig. Sets default values.
1580
- */
1581
- class PropertyDecoratorConfigInternal {
1582
- // eslint-disable-next-line jsdoc/require-jsdoc
1583
- display;
1584
- // eslint-disable-next-line jsdoc/require-jsdoc
1585
- displayName;
1586
- // eslint-disable-next-line jsdoc/require-jsdoc
1587
- required;
1588
- // eslint-disable-next-line jsdoc/require-jsdoc
1589
- omitForCreate;
1590
- // eslint-disable-next-line jsdoc/require-jsdoc
1591
- omitForUpdate;
1592
- // eslint-disable-next-line jsdoc/require-jsdoc
1593
- defaultWidths;
1594
- // eslint-disable-next-line jsdoc/require-jsdoc
1595
- position;
1596
- // eslint-disable-next-line jsdoc/require-jsdoc
1597
- isReadOnly;
1598
- constructor(data) {
1599
- this.display = this.booleanToFunction(data.display ?? true);
1600
- this.displayName = data.displayName;
1601
- this.required = this.booleanToFunction(data.required ?? true);
1602
- this.omitForCreate = data.omitForCreate ?? false;
1603
- this.omitForUpdate = data.omitForUpdate ?? false;
1604
- this.defaultWidths = data.defaultWidths ?? [6, 6, 12];
1605
- this.position = new PositionInternal(data.position);
1606
- this.isReadOnly = this.booleanToFunction(data.isReadOnly ?? false);
1607
- }
1608
- /**
1609
- * Converts the given boolean or boolean function to a boolean function.
1610
- *
1611
- * @param value - The value to convert.
1612
- * @returns A function that resolves to a boolean.
1613
- */
1614
- booleanToFunction(value) {
1615
- if (typeof value !== 'boolean') {
1616
- return value;
1617
- }
1618
- return value ? defaultTrue : defaultFalse;
1338
+ return value ? defaultTrue : defaultFalse;
1619
1339
  }
1620
1340
  }
1621
1341
 
@@ -1717,8 +1437,6 @@ class PasswordStringDecoratorConfigInternal extends PropertyDecoratorConfigInter
1717
1437
  needsConfirmation;
1718
1438
  // eslint-disable-next-line jsdoc/require-jsdoc
1719
1439
  confirmationDisplayName;
1720
- // eslint-disable-next-line jsdoc/require-jsdoc
1721
- passwordsDontMatchErrorMessage;
1722
1440
  constructor(data) {
1723
1441
  super(data);
1724
1442
  this.displayStyle = data.displayStyle;
@@ -1727,7 +1445,6 @@ class PasswordStringDecoratorConfigInternal extends PropertyDecoratorConfigInter
1727
1445
  this.regex = data.regex;
1728
1446
  this.needsConfirmation = data.needsConfirmation ?? true;
1729
1447
  this.confirmationDisplayName = data.confirmationDisplayName ?? 'Confirm Password';
1730
- this.passwordsDontMatchErrorMessage = data.passwordsDontMatchErrorMessage ?? 'Passwords need to match!';
1731
1448
  this.defaultWidths = data.defaultWidths ?? [12, 12, 12];
1732
1449
  }
1733
1450
  }
@@ -1946,6 +1663,30 @@ const defaultEditDataRoute = {
1946
1663
  canDeactivate: [UnsavedChangesGuard]
1947
1664
  };
1948
1665
 
1666
+ const NGX_VALIDATION_ERRORS_TOOLTIP_TITLE = new InjectionToken('Provider for the validation errors tooltip title.', {
1667
+ providedIn: 'root',
1668
+ factory: () => 'Validation Errors:'
1669
+ });
1670
+ /**
1671
+ * The default function that gets the validation errors tooltip content.
1672
+ *
1673
+ * @param validationErrors - All validation errors for which the tooltip content should be generated.
1674
+ * @returns A html string, containing a list of the name of each invalid property.
1675
+ */
1676
+ function getValidationErrorsTooltipContent(validationErrors) {
1677
+ const title = inject(NGX_VALIDATION_ERRORS_TOOLTIP_TITLE);
1678
+ let res = `
1679
+ ${title}
1680
+ <br>
1681
+ <ul style="margin-bottom: 0px; padding-left: 16px;">
1682
+ `;
1683
+ for (const error of validationErrors) {
1684
+ res = res.concat(`<li>${error.property}</li>`);
1685
+ }
1686
+ res = res.concat('</ul>');
1687
+ return res;
1688
+ }
1689
+
1949
1690
  /**
1950
1691
  * A generic EntityService class.
1951
1692
  * Offers basic CRUD-functionality.
@@ -2131,91 +1872,663 @@ class EntityService {
2131
1872
  }
2132
1873
  }
2133
1874
  /**
2134
- * Builds the update request body from the given entity before and after its changes.
1875
+ * Builds the update request body from the given entity before and after its changes.
1876
+ *
1877
+ * @param entity - The entity with changed values.
1878
+ * @param entityPriorChanges - The entity before any changes.
1879
+ * @returns A partial of only the changed values.
1880
+ */
1881
+ async entityToUpdateRequestBody(entity, entityPriorChanges) {
1882
+ const body = await EntityUtilities.getWithoutOmitUpdateValues(entity, entityPriorChanges, this.http);
1883
+ return LodashUtilities.omitBy(body, LodashUtilities.isNil);
1884
+ }
1885
+ // TODO: Find a way to use blobs with jest
1886
+ /* istanbul ignore next */
1887
+ /**
1888
+ * Updates the entity with form data when the entity contains files in contrast to creating it with a normal json body.
1889
+ * All file values are stored inside their respective property key and their name.
1890
+ * Form data is able to handle setting multiple files to the same key.
1891
+ *
1892
+ * @param body - The request body. Already contains only properties that have changed.
1893
+ * @param filePropertyKeys - The keys of all properties which are files and need to separately be appended to the form data.
1894
+ * @param entity - The original entity. Is needed to get the metadata of all the files.
1895
+ * @param id - The id of the entity to update.
1896
+ */
1897
+ async updateWithFormData(body, filePropertyKeys, entity, id) {
1898
+ const formData = new FormData();
1899
+ formData.append('body', JSON.stringify(body));
1900
+ for (const key of filePropertyKeys) {
1901
+ if (EntityUtilities.getPropertyMetadata(entity, key, DecoratorTypes.FILE_DEFAULT).multiple) {
1902
+ const fileDataValues = body[key];
1903
+ for (const value of fileDataValues) {
1904
+ formData.append(key, (await FileUtilities.getFileData(value, this.http)).file, value.name);
1905
+ }
1906
+ }
1907
+ else {
1908
+ const fileData = body[key];
1909
+ formData.append(key, (await FileUtilities.getFileData(fileData, this.http)).file, fileData.name);
1910
+ }
1911
+ }
1912
+ const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${id}`, formData));
1913
+ if (!updatedEntity) {
1914
+ // eslint-disable-next-line no-console
1915
+ console.warn('The updated entity was not returned in the response. Applying the changes from the request body.');
1916
+ for (const key in body) {
1917
+ this.entities[this.entities.findIndex(e => e[this.idKey] === id)][key]
1918
+ = body[key];
1919
+ }
1920
+ this.entitiesSubject.next(this.entities);
1921
+ return;
1922
+ }
1923
+ this.entities[this.entities.findIndex(e => e[this.idKey] === id)] = updatedEntity;
1924
+ this.entitiesSubject.next(this.entities);
1925
+ }
1926
+ /**
1927
+ * Updates the entity with a normal json body in contrast to updating it with form data when the entity contains files.
1928
+ *
1929
+ * @param body - The body of the Request. Has already removed all unnecessary values.
1930
+ * @param id - The id of the entity to update.
1931
+ */
1932
+ async updateWithJson(body, id) {
1933
+ const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${id}`, LodashUtilities.omitBy(body, LodashUtilities.isNil)));
1934
+ if (!updatedEntity) {
1935
+ // eslint-disable-next-line no-console
1936
+ console.warn('The updated entity was not returned in the response. Applying the changes from the request body.');
1937
+ const foundEntity = this.entities[this.entities.findIndex(e => e[this.idKey] === id)];
1938
+ for (const key in body) {
1939
+ foundEntity[key]
1940
+ = body[key];
1941
+ }
1942
+ this.entitiesSubject.next(this.entities);
1943
+ return;
1944
+ }
1945
+ this.entities[this.entities.findIndex(e => e[this.idKey] === id)] = updatedEntity;
1946
+ this.entitiesSubject.next(this.entities);
1947
+ }
1948
+ /**
1949
+ * Deletes a specific Entity.
1950
+ *
1951
+ * @param entity - The entity to delete.
1952
+ */
1953
+ async delete(entity) {
1954
+ await firstValueFrom(this.http.delete(`${this.baseUrl}/${entity[this.idKey]}`));
1955
+ // the == comparison instead of === is to catch ids that are numbers.
1956
+ this.entities.splice(this.entities.findIndex(e => e[this.idKey] === entity[this.idKey]), 1);
1957
+ this.entitiesSubject.next(this.entities);
1958
+ }
1959
+ }
1960
+
1961
+ /**
1962
+ * Contains HelperMethods around handling Validation of entities and properties.
1963
+ */
1964
+ class ValidationUtilities {
1965
+ /**
1966
+ * Checks if the values on an entity are valid.
1967
+ * Also checks all the validators given by the metadata ("required", "maxLength" etc.).
1968
+ *
1969
+ * @param entity - The entity to validate.
1970
+ * @param omit - Whether to check for creating or editing validity.
1971
+ * @returns Whether or not the entity is valid.
1972
+ */
1973
+ static isEntityValid(entity, omit) {
1974
+ return this.getEntityValidationErrors(entity, omit).length === 0;
1975
+ }
1976
+ /**
1977
+ * Gets all validation errors on the given entity.
1978
+ *
1979
+ * @param entity - The entity to validate.
1980
+ * @param omit - What keys not to check. An empty value means no keys are omitted.
1981
+ * @returns An array of validation errors on the provided entity.
1982
+ */
1983
+ static getEntityValidationErrors(entity, omit) {
1984
+ const res = [];
1985
+ for (const key in entity) {
1986
+ const err = this.getPropertyValidationError(entity, key, omit);
1987
+ if (err) {
1988
+ res.push(err);
1989
+ }
1990
+ }
1991
+ return res;
1992
+ }
1993
+ // /**
1994
+ // * Checks if a single property value is valid.
1995
+ // *
1996
+ // * @param entity - The entity where the property is from.
1997
+ // * @param key - The name of the property.
1998
+ // * @param omit - Whether to check if the given entity is valid for creation or updating.
1999
+ // * @returns Whether or not the property value is valid.
2000
+ // * @throws Throws when it extracts an unknown metadata type.
2001
+ // */
2002
+ // static isPropertyValid<EntityType extends BaseEntityType<EntityType>>(
2003
+ // entity: EntityType,
2004
+ // key: keyof EntityType,
2005
+ // omit?: 'create' | 'update'
2006
+ // ): boolean {
2007
+ // return this.getPropertyValidationError(entity, key, omit) == null;
2008
+ // }
2009
+ /**
2010
+ * Validates the property on the given entity with the given key.
2011
+ *
2012
+ * @param entity - The entity on which the property to check is.
2013
+ * @param key - The key of the property to validate.
2014
+ * @param omit - What keys not to check. An empty value means no keys are omitted.
2015
+ * @returns A validation error when the property is not valid, undefined otherwise.
2016
+ * @throws When the type of the property is not known.
2017
+ */
2018
+ static getPropertyValidationError(entity, key, omit) {
2019
+ const type = EntityUtilities.getPropertyType(entity, key);
2020
+ const metadata = EntityUtilities.getPropertyMetadata(entity, key, type);
2021
+ if (metadata.omitForCreate && omit === 'create') {
2022
+ return undefined;
2023
+ }
2024
+ if (metadata.omitForUpdate && omit === 'update') {
2025
+ return undefined;
2026
+ }
2027
+ if (metadata.required(entity) && type !== DecoratorTypes.HAS_MANY) {
2028
+ if (entity[key] == null || entity[key] === '') {
2029
+ return {
2030
+ property: metadata.displayName,
2031
+ message: 'required'
2032
+ };
2033
+ }
2034
+ }
2035
+ if (!metadata.required(entity)) {
2036
+ if (entity[key] == null || entity[key] === '') {
2037
+ return undefined;
2038
+ }
2039
+ }
2040
+ switch (type) {
2041
+ case DecoratorTypes.BOOLEAN_DROPDOWN:
2042
+ break;
2043
+ case DecoratorTypes.BOOLEAN_CHECKBOX:
2044
+ case DecoratorTypes.BOOLEAN_TOGGLE:
2045
+ const entityBoolean = entity[key];
2046
+ const booleanMetadata = metadata;
2047
+ return this.getBooleanValidationError(entity, entityBoolean, booleanMetadata);
2048
+ case DecoratorTypes.STRING_DROPDOWN:
2049
+ break;
2050
+ case DecoratorTypes.STRING:
2051
+ case DecoratorTypes.STRING_AUTOCOMPLETE:
2052
+ const entityString = entity[key];
2053
+ const stringMetadata = metadata;
2054
+ return this.getStringValidationError(entityString, stringMetadata);
2055
+ case DecoratorTypes.STRING_TEXTBOX:
2056
+ const entityTextbox = entity[key];
2057
+ const textboxMetadata = metadata;
2058
+ return this.getTextboxValidationError(entityTextbox, textboxMetadata);
2059
+ case DecoratorTypes.STRING_PASSWORD:
2060
+ const entityPassword = entity[key];
2061
+ const passwordMetadata = metadata;
2062
+ const confirmPassword = ReflectUtilities.getMetadata(EntityUtilities.CONFIRM_PASSWORD_KEY, entity, key);
2063
+ return this.getPasswordValidationError(entityPassword, passwordMetadata, confirmPassword);
2064
+ case DecoratorTypes.NUMBER_DROPDOWN:
2065
+ // Because only valid values can be selected, this is always true when it has a value
2066
+ return undefined;
2067
+ case DecoratorTypes.NUMBER:
2068
+ case DecoratorTypes.NUMBER_SLIDER:
2069
+ const entityNumber = entity[key];
2070
+ const numberMetadata = metadata;
2071
+ return this.getNumberValidationError(entityNumber, numberMetadata);
2072
+ case DecoratorTypes.OBJECT:
2073
+ const entityObject = entity[key];
2074
+ for (const parameterKey in entityObject) {
2075
+ const value = entityObject[parameterKey];
2076
+ if (!metadata.omit.includes(parameterKey)
2077
+ && !(!metadata.required(entity) && (value == null || value == ''))) {
2078
+ const err = this.getPropertyValidationError(entityObject, parameterKey, omit);
2079
+ if (err) {
2080
+ return {
2081
+ property: metadata.displayName,
2082
+ message: `${err.property} is invalid: ${err.message}`
2083
+ };
2084
+ }
2085
+ }
2086
+ }
2087
+ break;
2088
+ case DecoratorTypes.ARRAY_STRING_CHIPS:
2089
+ case DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS:
2090
+ case DecoratorTypes.ARRAY_DATE:
2091
+ case DecoratorTypes.ARRAY_DATE_TIME:
2092
+ case DecoratorTypes.ARRAY_DATE_RANGE:
2093
+ case DecoratorTypes.ARRAY:
2094
+ const entityArray = entity[key];
2095
+ // eslint-disable-next-line max-len
2096
+ const arrayMetadata = metadata;
2097
+ if (arrayMetadata.required(entity) && !entityArray.length) {
2098
+ return {
2099
+ property: metadata.displayName,
2100
+ message: 'no items in array'
2101
+ };
2102
+ }
2103
+ break;
2104
+ case DecoratorTypes.DATE:
2105
+ const entityDate = new Date(entity[key]);
2106
+ const dateMetadata = metadata;
2107
+ return this.getDateValidationError(entityDate, dateMetadata);
2108
+ case DecoratorTypes.DATE_RANGE:
2109
+ const entityDateRange = LodashUtilities.cloneDeep(entity[key]);
2110
+ const dateRangeMetadata = metadata;
2111
+ return this.getDateRangeValidationError(entity, entityDateRange, dateRangeMetadata);
2112
+ case DecoratorTypes.DATE_TIME:
2113
+ const entityDateTime = new Date(entity[key]);
2114
+ const dateTimeMetadata = metadata;
2115
+ const hasTime = ReflectUtilities.hasMetadata(EntityUtilities.TIME_KEY, entity, key);
2116
+ return this.getDateTimeValidationError(entityDateTime, dateTimeMetadata, hasTime);
2117
+ case DecoratorTypes.FILE_DEFAULT:
2118
+ case DecoratorTypes.FILE_IMAGE:
2119
+ const entityFile = entity[key];
2120
+ const entityFileMetadata = metadata;
2121
+ return this.getFileDataValidationError(entityFile, entityFileMetadata);
2122
+ case DecoratorTypes.REFERENCES_MANY:
2123
+ case DecoratorTypes.REFERENCES_ONE:
2124
+ case DecoratorTypes.HAS_MANY:
2125
+ break;
2126
+ case DecoratorTypes.CUSTOM:
2127
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, max-len
2128
+ const customMetadata = metadata;
2129
+ if (!customMetadata.isValid(entity[key], omit)) {
2130
+ return {
2131
+ property: metadata.displayName,
2132
+ message: 'invalid'
2133
+ };
2134
+ }
2135
+ break;
2136
+ default:
2137
+ throw new Error(`Could not validate the input because the DecoratorType ${type} is not known`);
2138
+ }
2139
+ return undefined;
2140
+ }
2141
+ static getBooleanValidationError(entity, value, metadata) {
2142
+ if (metadata.required(entity) && !value) {
2143
+ return {
2144
+ property: metadata.displayName,
2145
+ message: 'not selected'
2146
+ };
2147
+ }
2148
+ return undefined;
2149
+ }
2150
+ static getStringValidationError(value, metadata) {
2151
+ if (metadata.maxLength && value.length > metadata.maxLength) {
2152
+ return {
2153
+ property: metadata.displayName,
2154
+ message: `needs to be smaller than ${metadata.maxLength} characters`
2155
+ };
2156
+ }
2157
+ if (metadata.minLength && value.length < metadata.minLength) {
2158
+ return {
2159
+ property: metadata.displayName,
2160
+ message: `needs to be bigger than ${metadata.minLength} characters`
2161
+ };
2162
+ }
2163
+ if (metadata.regex && !value.match(metadata.regex)) {
2164
+ return {
2165
+ property: metadata.displayName,
2166
+ message: 'invalid'
2167
+ };
2168
+ }
2169
+ return undefined;
2170
+ }
2171
+ static getTextboxValidationError(value, metadata) {
2172
+ if (metadata.maxLength && value.length > metadata.maxLength) {
2173
+ return {
2174
+ property: metadata.displayName,
2175
+ message: `needs to be smaller than ${metadata.maxLength} characters`
2176
+ };
2177
+ }
2178
+ if (metadata.minLength && value.length < metadata.minLength) {
2179
+ return {
2180
+ property: metadata.displayName,
2181
+ message: `needs to be bigger than ${metadata.minLength} characters`
2182
+ };
2183
+ }
2184
+ return undefined;
2185
+ }
2186
+ static getPasswordValidationError(value, metadata, confirmPassword) {
2187
+ if (value !== confirmPassword) {
2188
+ return {
2189
+ property: metadata.displayName,
2190
+ message: 'passwords need to match'
2191
+ };
2192
+ }
2193
+ if (metadata.maxLength && value.length > metadata.maxLength) {
2194
+ return {
2195
+ property: metadata.displayName,
2196
+ message: `needs to be smaller than ${metadata.maxLength} characters`
2197
+ };
2198
+ }
2199
+ if (metadata.minLength && value.length < metadata.minLength) {
2200
+ return {
2201
+ property: metadata.displayName,
2202
+ message: `needs to be bigger than ${metadata.minLength} characters`
2203
+ };
2204
+ }
2205
+ if (metadata.regex && !value.match(metadata.regex)) {
2206
+ return {
2207
+ property: metadata.displayName,
2208
+ message: 'invalid'
2209
+ };
2210
+ }
2211
+ return undefined;
2212
+ }
2213
+ static getNumberValidationError(value, metadata) {
2214
+ if (metadata.max && value > metadata.max) {
2215
+ return {
2216
+ property: metadata.displayName,
2217
+ message: `needs to be smaller than ${metadata.max}`
2218
+ };
2219
+ }
2220
+ if (metadata.min && value < metadata.min) {
2221
+ return {
2222
+ property: metadata.displayName,
2223
+ message: `needs to be bigger than ${metadata.min}`
2224
+ };
2225
+ }
2226
+ return undefined;
2227
+ }
2228
+ static getDateValidationError(value, metadata) {
2229
+ if (metadata.min && value.getTime() < metadata.min(value).getTime()) {
2230
+ return {
2231
+ property: metadata.displayName,
2232
+ message: `needs to be after ${formatDate(metadata.min(value))}`
2233
+ };
2234
+ }
2235
+ if (metadata.max && value.getTime() > metadata.max(value).getTime()) {
2236
+ return {
2237
+ property: metadata.displayName,
2238
+ message: `needs to be before ${formatDate(metadata.max(value))}`
2239
+ };
2240
+ }
2241
+ if (metadata.filter && !metadata.filter(value)) {
2242
+ return {
2243
+ property: metadata.displayName,
2244
+ message: 'invalid'
2245
+ };
2246
+ }
2247
+ return undefined;
2248
+ }
2249
+ static getDateRangeValidationError(entity, value, metadata) {
2250
+ if (metadata.required(entity)) {
2251
+ if (value.start == null || value.end == null || value.values == null) {
2252
+ return {
2253
+ property: metadata.displayName,
2254
+ message: 'required'
2255
+ };
2256
+ }
2257
+ }
2258
+ value.start = new Date(value.start);
2259
+ value.end = new Date(value.end);
2260
+ if (metadata.minStart && value.start.getTime() < metadata.minStart(value.start).getTime()) {
2261
+ return {
2262
+ property: metadata.displayName,
2263
+ message: `start date needs to be after ${formatDate(metadata.minStart(value.start))}`
2264
+ };
2265
+ }
2266
+ if (metadata.maxStart && value.start.getTime() > metadata.maxStart(value.start).getTime()) {
2267
+ return {
2268
+ property: metadata.displayName,
2269
+ message: `start date needs to be before ${formatDate(metadata.maxStart(value.start))}`
2270
+ };
2271
+ }
2272
+ if (metadata.minEnd && value.end.getTime() < metadata.minEnd(value.end).getTime()) {
2273
+ return {
2274
+ property: metadata.displayName,
2275
+ message: `end date needs to be after ${formatDate(metadata.minEnd(value.end))}`
2276
+ };
2277
+ }
2278
+ if (metadata.maxEnd && value.end.getTime() > metadata.maxEnd(value.end).getTime()) {
2279
+ return {
2280
+ property: metadata.displayName,
2281
+ message: `end date needs to be before ${formatDate(metadata.maxEnd(value.end))}`
2282
+ };
2283
+ }
2284
+ if (metadata.filter) {
2285
+ if (!metadata.filter(value.start)) {
2286
+ return {
2287
+ property: metadata.displayName,
2288
+ message: 'start date invalid'
2289
+ };
2290
+ }
2291
+ if (!metadata.filter(value.end)) {
2292
+ return {
2293
+ property: metadata.displayName,
2294
+ message: 'end date invalid'
2295
+ };
2296
+ }
2297
+ for (const date of value.values) {
2298
+ if (!metadata.filter(date)) {
2299
+ return {
2300
+ property: metadata.displayName,
2301
+ message: `value ${formatDate(date)} invalid`
2302
+ };
2303
+ }
2304
+ }
2305
+ }
2306
+ return undefined;
2307
+ }
2308
+ static getDateTimeValidationError(value, metadata, hasTime) {
2309
+ if (!hasTime) {
2310
+ return {
2311
+ property: metadata.displayName,
2312
+ message: 'no time'
2313
+ };
2314
+ }
2315
+ if (metadata.minDate && value.getTime() < metadata.minDate(value).getTime()) {
2316
+ return {
2317
+ property: metadata.displayName,
2318
+ message: `date needs to be after ${formatDate(metadata.minDate(value))}`
2319
+ };
2320
+ }
2321
+ if (metadata.maxDate && value.getTime() > metadata.maxDate(value).getTime()) {
2322
+ return {
2323
+ property: metadata.displayName,
2324
+ message: `date needs to be before ${formatDate(metadata.maxDate(value))}`
2325
+ };
2326
+ }
2327
+ if (metadata.filterDate && !metadata.filterDate(value)) {
2328
+ return {
2329
+ property: metadata.displayName,
2330
+ message: 'invalid date'
2331
+ };
2332
+ }
2333
+ const time = DateUtilities.getTimeFromDate(value);
2334
+ if (metadata.minTime) {
2335
+ const minTime = metadata.minTime(value);
2336
+ if (!(time.hours > minTime.hours
2337
+ || (time.hours === minTime.hours
2338
+ && time.minutes >= minTime.minutes))) {
2339
+ return {
2340
+ property: metadata.displayName,
2341
+ message: `time needs to be after ${minTime.hours}:${minTime.minutes}`
2342
+ };
2343
+ }
2344
+ }
2345
+ if (metadata.maxTime) {
2346
+ const maxTime = metadata.maxTime(value);
2347
+ if (!(time.hours < maxTime.hours
2348
+ || (time.hours === maxTime.hours
2349
+ && time.minutes <= maxTime.minutes))) {
2350
+ return {
2351
+ property: metadata.displayName,
2352
+ message: `time needs to be before ${maxTime.hours}:${maxTime.minutes}`
2353
+ };
2354
+ }
2355
+ }
2356
+ if (metadata.filterTime && !metadata.filterTime(time)) {
2357
+ return {
2358
+ property: metadata.displayName,
2359
+ message: 'invalid time'
2360
+ };
2361
+ }
2362
+ return undefined;
2363
+ }
2364
+ static getFileDataValidationError(value, metadata) {
2365
+ const files = metadata.multiple ? value : [value];
2366
+ let fileSizeTotal = 0;
2367
+ for (const file of files) {
2368
+ if (!file.name || !file.file && !file.url) {
2369
+ return {
2370
+ property: metadata.displayName,
2371
+ message: 'invalid'
2372
+ };
2373
+ }
2374
+ if (!FileUtilities.isMimeTypeValid(file.type, metadata.allowedMimeTypes)) {
2375
+ return {
2376
+ property: metadata.displayName,
2377
+ message: `mimetype needs to be one of ${metadata.allowedMimeTypes}`
2378
+ };
2379
+ }
2380
+ if (FileUtilities.transformToMegaBytes(file.size, 'B') > metadata.maxSize) {
2381
+ return {
2382
+ property: metadata.displayName,
2383
+ message: `file needs to be smaller than ${metadata.maxSize} MB`
2384
+ };
2385
+ }
2386
+ fileSizeTotal += file.size;
2387
+ if (FileUtilities.transformToMegaBytes(fileSizeTotal, 'B') > metadata.maxSizeTotal) {
2388
+ return {
2389
+ property: metadata.displayName,
2390
+ message: `The size of all files combined needs to be smaller than ${metadata.maxSizeTotal}`
2391
+ };
2392
+ }
2393
+ }
2394
+ return undefined;
2395
+ }
2396
+ }
2397
+ // eslint-disable-next-line jsdoc/require-jsdoc
2398
+ function padTo2Digits(num) {
2399
+ return num.toString().padStart(2, '0');
2400
+ }
2401
+ // eslint-disable-next-line jsdoc/require-jsdoc
2402
+ function formatDate(date) {
2403
+ return [
2404
+ padTo2Digits(date.getDate()),
2405
+ padTo2Digits(date.getMonth() + 1),
2406
+ date.getFullYear()
2407
+ ].join('/');
2408
+ }
2409
+
2410
+ /**
2411
+ * Adds drag and drop functionality to an element.
2412
+ */
2413
+ class DragDropDirective {
2414
+ /**
2415
+ * Emits the dropped files to the parent.
2416
+ */
2417
+ files = new EventEmitter();
2418
+ constructor() { }
2419
+ /**
2420
+ * Prevents the event default.
2421
+ *
2422
+ * @param evt - The Event when dragged files hover over the parent.
2423
+ */
2424
+ onDragOver(evt) {
2425
+ evt.preventDefault();
2426
+ evt.stopPropagation();
2427
+ }
2428
+ /**
2429
+ * Prevents the event default.
2135
2430
  *
2136
- * @param entity - The entity with changed values.
2137
- * @param entityPriorChanges - The entity before any changes.
2138
- * @returns A partial of only the changed values.
2431
+ * @param evt - The Event when dragged files leave the parent.
2139
2432
  */
2140
- async entityToUpdateRequestBody(entity, entityPriorChanges) {
2141
- const body = await EntityUtilities.getWithoutOmitUpdateValues(entity, entityPriorChanges, this.http);
2142
- return LodashUtilities.omitBy(body, LodashUtilities.isNil);
2433
+ onDragLeave(evt) {
2434
+ evt.preventDefault();
2435
+ evt.stopPropagation();
2143
2436
  }
2144
- // TODO: Find a way to use blobs with jest
2145
- /* istanbul ignore next */
2146
2437
  /**
2147
- * Updates the entity with form data when the entity contains files in contrast to creating it with a normal json body.
2148
- * All file values are stored inside their respective property key and their name.
2149
- * Form data is able to handle setting multiple files to the same key.
2438
+ * Prevents the event default and emits the dropped files with the output.
2150
2439
  *
2151
- * @param body - The request body. Already contains only properties that have changed.
2152
- * @param filePropertyKeys - The keys of all properties which are files and need to separately be appended to the form data.
2153
- * @param entity - The original entity. Is needed to get the metadata of all the files.
2154
- * @param id - The id of the entity to update.
2440
+ * @param evt - The Event when files are dropped.
2155
2441
  */
2156
- async updateWithFormData(body, filePropertyKeys, entity, id) {
2157
- const formData = new FormData();
2158
- formData.append('body', JSON.stringify(body));
2159
- for (const key of filePropertyKeys) {
2160
- if (EntityUtilities.getPropertyMetadata(entity, key, DecoratorTypes.FILE_DEFAULT).multiple) {
2161
- const fileDataValues = body[key];
2162
- for (const value of fileDataValues) {
2163
- formData.append(key, (await FileUtilities.getFileData(value, this.http)).file, value.name);
2164
- }
2165
- }
2166
- else {
2167
- const fileData = body[key];
2168
- formData.append(key, (await FileUtilities.getFileData(fileData, this.http)).file, fileData.name);
2169
- }
2170
- }
2171
- const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${id}`, formData));
2172
- if (!updatedEntity) {
2173
- // eslint-disable-next-line no-console
2174
- console.warn('The updated entity was not returned in the response. Applying the changes from the request body.');
2175
- for (const key in body) {
2176
- this.entities[this.entities.findIndex(e => e[this.idKey] === id)][key]
2177
- = body[key];
2178
- }
2179
- this.entitiesSubject.next(this.entities);
2180
- return;
2442
+ onDrop(evt) {
2443
+ evt.preventDefault();
2444
+ evt.stopPropagation();
2445
+ if (evt.dataTransfer && evt.dataTransfer.files.length > 0) {
2446
+ this.files.emit(Array.from(evt.dataTransfer.files));
2181
2447
  }
2182
- this.entities[this.entities.findIndex(e => e[this.idKey] === id)] = updatedEntity;
2183
- this.entitiesSubject.next(this.entities);
2448
+ }
2449
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: DragDropDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2450
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.0", type: DragDropDirective, selector: "[dragDrop]", outputs: { files: "files" }, host: { listeners: { "dragover": "onDragOver($event)", "dragleave": "onDragLeave($event)", "drop": "onDrop($event)" } }, ngImport: i0 });
2451
+ }
2452
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: DragDropDirective, decorators: [{
2453
+ type: Directive,
2454
+ args: [{
2455
+ selector: '[dragDrop]'
2456
+ }]
2457
+ }], ctorParameters: function () { return []; }, propDecorators: { files: [{
2458
+ type: Output
2459
+ }], onDragOver: [{
2460
+ type: HostListener,
2461
+ args: ['dragover', ['$event']]
2462
+ }], onDragLeave: [{
2463
+ type: HostListener,
2464
+ args: ['dragleave', ['$event']]
2465
+ }], onDrop: [{
2466
+ type: HostListener,
2467
+ args: ['drop', ['$event']]
2468
+ }] } });
2469
+
2470
+ /**
2471
+ * A directive that only allows number inputs.
2472
+ */
2473
+ class NumberDirective {
2474
+ el;
2475
+ constructor(el) {
2476
+ this.el = el;
2184
2477
  }
2185
2478
  /**
2186
- * Updates the entity with a normal json body in contrast to updating it with form data when the entity contains files.
2479
+ * Prevents the default event when a key is pressed that is not a valid number, eg. 'A', 'B', 'C', 'D' etc.
2187
2480
  *
2188
- * @param body - The body of the Request. Has already removed all unnecessary values.
2189
- * @param id - The id of the entity to update.
2481
+ * @param e - The keydown event from the user.
2190
2482
  */
2191
- async updateWithJson(body, id) {
2192
- const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${id}`, LodashUtilities.omitBy(body, LodashUtilities.isNil)));
2193
- if (!updatedEntity) {
2194
- // eslint-disable-next-line no-console
2195
- console.warn('The updated entity was not returned in the response. Applying the changes from the request body.');
2196
- const foundEntity = this.entities[this.entities.findIndex(e => e[this.idKey] === id)];
2197
- for (const key in body) {
2198
- foundEntity[key]
2199
- = body[key];
2200
- }
2201
- this.entitiesSubject.next(this.entities);
2483
+ onKeyDown(e) {
2484
+ if (!isNaN(parseInt(e.key))
2485
+ || ['.', ',', 'Escape', 'Enter', 'Delete', 'Backspace', 'Home', 'End', 'Left', 'Right', 'Tab'].includes(e.key)
2486
+ || (e.ctrlKey || e.metaKey) // && ['a', 'c', 'v', 'x', 'z'].includes(e.key)
2487
+ ) {
2202
2488
  return;
2203
2489
  }
2204
- this.entities[this.entities.findIndex(e => e[this.idKey] === id)] = updatedEntity;
2205
- this.entitiesSubject.next(this.entities);
2490
+ e.preventDefault();
2206
2491
  }
2492
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NumberDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
2493
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.0", type: NumberDirective, isStandalone: true, selector: "[number]", host: { listeners: { "keydown": "onKeyDown($event)" } }, ngImport: i0 });
2494
+ }
2495
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NumberDirective, decorators: [{
2496
+ type: Directive,
2497
+ args: [{
2498
+ selector: '[number]',
2499
+ standalone: true
2500
+ }]
2501
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { onKeyDown: [{
2502
+ type: HostListener,
2503
+ args: ['keydown', ['$event']]
2504
+ }] } });
2505
+
2506
+ /**
2507
+ * A directive that validates if a given password matches the control value.
2508
+ */
2509
+ class PasswordMatchValidatorDirective {
2207
2510
  /**
2208
- * Deletes a specific Entity.
2209
- *
2210
- * @param entity - The entity to delete.
2511
+ * The password that the control value should be matched against.
2211
2512
  */
2212
- async delete(entity) {
2213
- await firstValueFrom(this.http.delete(`${this.baseUrl}/${entity[this.idKey]}`));
2214
- // the == comparison instead of === is to catch ids that are numbers.
2215
- this.entities.splice(this.entities.findIndex(e => e[this.idKey] === entity[this.idKey]), 1);
2216
- this.entitiesSubject.next(this.entities);
2513
+ passwordMatch;
2514
+ // eslint-disable-next-line jsdoc/require-jsdoc
2515
+ validate(control) {
2516
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
2517
+ return this.passwordMatch == control.value ? null : { passwordMatch: { value: control.value } };
2217
2518
  }
2519
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: PasswordMatchValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2520
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.0", type: PasswordMatchValidatorDirective, isStandalone: true, selector: "[passwordMatch]", inputs: { passwordMatch: "passwordMatch" }, providers: [{ provide: NG_VALIDATORS, useExisting: PasswordMatchValidatorDirective, multi: true }], ngImport: i0 });
2218
2521
  }
2522
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: PasswordMatchValidatorDirective, decorators: [{
2523
+ type: Directive,
2524
+ args: [{
2525
+ selector: '[passwordMatch]',
2526
+ providers: [{ provide: NG_VALIDATORS, useExisting: PasswordMatchValidatorDirective, multi: true }],
2527
+ standalone: true
2528
+ }]
2529
+ }], propDecorators: { passwordMatch: [{
2530
+ type: Input
2531
+ }] } });
2219
2532
 
2220
2533
  /* eslint-disable @angular-eslint/component-selector */
2221
2534
  /**
@@ -2361,6 +2674,7 @@ class NgxMatEntityBaseInputComponent {
2361
2674
  // eslint-disable-next-line jsdoc/require-jsdoc
2362
2675
  set propertyValue(value) {
2363
2676
  this.entity[this.key] = value;
2677
+ this.metadata.change?.(this.entity);
2364
2678
  }
2365
2679
  /**
2366
2680
  * The metadata of the property.
@@ -2676,12 +2990,15 @@ class BooleanCheckboxInputComponent extends NgxMatEntityBaseInputComponent {
2676
2990
  super.ngOnInit();
2677
2991
  this.propertyValue = this.propertyValue ?? false;
2678
2992
  }
2993
+ updatePropertyValue() {
2994
+ this.propertyValue = this.propertyValue != null ? !this.propertyValue : true;
2995
+ }
2679
2996
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: BooleanCheckboxInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2680
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: BooleanCheckboxInputComponent, selector: "boolean-checkbox-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox\n color=\"primary\"\n (ngModelChange)=\"emitChange()\"\n (click)=\"model.control.markAsTouched()\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n [disabled]=\"isReadOnly\"\n [class.disabled]=\"isReadOnly\"\n [class.mat-checkbox-disabled]=\"false\"\n >\n </mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + 'Helper' + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n [disabled]=\"isReadOnly\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-checkbox{margin-top:-10px;margin-bottom:-10px}mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }] });
2997
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: BooleanCheckboxInputComponent, selector: "boolean-checkbox-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox\n color=\"primary\"\n (click)=\"model.control.markAsTouched(); updatePropertyValue(); emitChange();\"\n [disabled]=\"isReadOnly\"\n [class.disabled]=\"isReadOnly\"\n [class.mat-checkbox-disabled]=\"false\"\n [checked]=\"propertyValue\"\n >\n </mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n [disabled]=\"isReadOnly\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-checkbox{margin-top:-10px;margin-bottom:-10px}mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }] });
2681
2998
  }
2682
2999
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: BooleanCheckboxInputComponent, decorators: [{
2683
3000
  type: Component,
2684
- args: [{ selector: 'boolean-checkbox-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox\n color=\"primary\"\n (ngModelChange)=\"emitChange()\"\n (click)=\"model.control.markAsTouched()\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n [disabled]=\"isReadOnly\"\n [class.disabled]=\"isReadOnly\"\n [class.mat-checkbox-disabled]=\"false\"\n >\n </mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + 'Helper' + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n [disabled]=\"isReadOnly\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-checkbox{margin-top:-10px;margin-bottom:-10px}mat-form-field{width:100%}\n"] }]
3001
+ args: [{ selector: 'boolean-checkbox-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox\n color=\"primary\"\n (click)=\"model.control.markAsTouched(); updatePropertyValue(); emitChange();\"\n [disabled]=\"isReadOnly\"\n [class.disabled]=\"isReadOnly\"\n [class.mat-checkbox-disabled]=\"false\"\n [checked]=\"propertyValue\"\n >\n </mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n [disabled]=\"isReadOnly\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-checkbox{margin-top:-10px;margin-bottom:-10px}mat-form-field{width:100%}\n"] }]
2685
3002
  }] });
2686
3003
 
2687
3004
  /* eslint-disable jsdoc/require-jsdoc */
@@ -2700,12 +3017,15 @@ class BooleanToggleInputComponent extends NgxMatEntityBaseInputComponent {
2700
3017
  super.ngOnInit();
2701
3018
  this.propertyValue = this.propertyValue ?? false;
2702
3019
  }
3020
+ updatePropertyValue() {
3021
+ this.propertyValue = this.propertyValue != null ? !this.propertyValue : true;
3022
+ }
2703
3023
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: BooleanToggleInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2704
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: BooleanToggleInputComponent, selector: "boolean-toggle-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle\n color=\"primary\"\n (click)=\"model.control.markAsTouched()\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n [disabled]=\"isReadOnly\"\n >\n </mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + 'Helper' + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n (ngModelChange)=\"emitChange()\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4$3.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }] });
3024
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: BooleanToggleInputComponent, selector: "boolean-toggle-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle\n color=\"primary\"\n (click)=\"model.control.markAsTouched(); updatePropertyValue(); emitChange();\"\n [disabled]=\"isReadOnly\"\n [checked]=\"propertyValue\"\n >\n </mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n [disabled]=\"isReadOnly\"\n (ngModelChange)=\"emitChange()\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4$3.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }] });
2705
3025
  }
2706
3026
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: BooleanToggleInputComponent, decorators: [{
2707
3027
  type: Component,
2708
- args: [{ selector: 'boolean-toggle-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle\n color=\"primary\"\n (click)=\"model.control.markAsTouched()\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n [disabled]=\"isReadOnly\"\n >\n </mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + 'Helper' + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n (ngModelChange)=\"emitChange()\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
3028
+ args: [{ selector: 'boolean-toggle-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle\n color=\"primary\"\n (click)=\"model.control.markAsTouched(); updatePropertyValue(); emitChange();\"\n [disabled]=\"isReadOnly\"\n [checked]=\"propertyValue\"\n >\n </mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required(entity) ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required(entity)\"\n [disabled]=\"isReadOnly\"\n (ngModelChange)=\"emitChange()\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
2709
3029
  }] });
2710
3030
 
2711
3031
  /* eslint-disable jsdoc/require-jsdoc */
@@ -2788,6 +3108,8 @@ class DateRangeInputComponent extends NgxMatEntityBaseInputComponent {
2788
3108
  this.dateRange.values = values.length ? values : undefined;
2789
3109
  }
2790
3110
  else {
3111
+ this.dateRange.start = undefined;
3112
+ this.dateRange.end = undefined;
2791
3113
  this.dateRange.values = undefined;
2792
3114
  }
2793
3115
  this.propertyValue = this.dateRange;
@@ -2857,66 +3179,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
2857
3179
  args: [{ selector: 'date-time-input', template: "<div class=\"date-time\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.minDate ? metadata.minDate(propertyValue) : undefined\"\n [max]=\"metadata.maxDate ? metadata.maxDate(propertyValue) : undefined\"\n [matDatepickerFilter]=\"metadata.filterDate ?? defaultDateFilter\"\n (dateChange)=\"setTime()\"\n [disabled]=\"isReadOnly\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field class=\"timepicker\">\n <mat-label>{{metadata.timeDisplayName}}</mat-label>\n <mat-select\n [(ngModel)]=\"time\"\n [name]=\"key.toString() + 'time' + uuid\"\n #timeModel=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [compareWith]=\"compareTimes\"\n [disabled]=\"isReadOnly\"\n (selectionChange)=\"setTime()\"\n >\n <mat-option *ngFor=\"let validTime of DateUtilities.getValidTimesForDropdown(\n metadata.times,\n propertyValue,\n metadata.minTime,\n metadata.maxTime,\n metadata.filterTime\n )\"\n [value]=\"validTime.value\"\n >\n {{validTime.displayName}}\n </mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(timeModel)}}</mat-error>\n </mat-form-field>\n</div>", styles: ["mat-form-field{width:100%}.date-time{display:flex;align-items:baseline}.date-time .timepicker{margin-left:10px}\n"] }]
2858
3180
  }] });
2859
3181
 
2860
- /**
2861
- * Adds drag and drop functionality to an element.
2862
- */
2863
- class DragDropDirective {
2864
- /**
2865
- * Emits the dropped files to the parent.
2866
- */
2867
- files = new EventEmitter();
2868
- constructor() { }
2869
- /**
2870
- * Prevents the event default.
2871
- *
2872
- * @param evt - The Event when dragged files hover over the parent.
2873
- */
2874
- onDragOver(evt) {
2875
- evt.preventDefault();
2876
- evt.stopPropagation();
2877
- }
2878
- /**
2879
- * Prevents the event default.
2880
- *
2881
- * @param evt - The Event when dragged files leave the parent.
2882
- */
2883
- onDragLeave(evt) {
2884
- evt.preventDefault();
2885
- evt.stopPropagation();
2886
- }
2887
- /**
2888
- * Prevents the event default and emits the dropped files with the output.
2889
- *
2890
- * @param evt - The Event when files are dropped.
2891
- */
2892
- onDrop(evt) {
2893
- evt.preventDefault();
2894
- evt.stopPropagation();
2895
- if (evt.dataTransfer && evt.dataTransfer.files.length > 0) {
2896
- this.files.emit(Array.from(evt.dataTransfer.files));
2897
- }
2898
- }
2899
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: DragDropDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2900
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.0", type: DragDropDirective, selector: "[dragDrop]", outputs: { files: "files" }, host: { listeners: { "dragover": "onDragOver($event)", "dragleave": "onDragLeave($event)", "drop": "onDrop($event)" } }, ngImport: i0 });
2901
- }
2902
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: DragDropDirective, decorators: [{
2903
- type: Directive,
2904
- args: [{
2905
- selector: '[dragDrop]'
2906
- }]
2907
- }], ctorParameters: function () { return []; }, propDecorators: { files: [{
2908
- type: Output
2909
- }], onDragOver: [{
2910
- type: HostListener,
2911
- args: ['dragover', ['$event']]
2912
- }], onDragLeave: [{
2913
- type: HostListener,
2914
- args: ['dragleave', ['$event']]
2915
- }], onDrop: [{
2916
- type: HostListener,
2917
- args: ['drop', ['$event']]
2918
- }] } });
2919
-
2920
3182
  /* eslint-disable jsdoc/require-jsdoc */
2921
3183
  class FileInputComponent {
2922
3184
  dialog;
@@ -3205,11 +3467,11 @@ class FileImageInputComponent extends NgxMatEntityBaseInputComponent {
3205
3467
  this.imageIndex = index;
3206
3468
  }
3207
3469
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: FileImageInputComponent, deps: [{ token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
3208
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: FileImageInputComponent, selector: "file-image-input", usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"!metadata.dragAndDrop && !metadata.preview\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n</div>\n\n<div *ngIf=\"metadata.dragAndDrop || metadata.preview\" class=\"file-input mat-elevation-z8\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && metadata.multiple\">\n <i (click)=\"prev()\" [class.disabled]=\"imageIndex === 0\" class=\"prev-button fa-solid fa-angle-left\"></i>\n <img *ngIf=\"multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"multiPreviewImages?.[imageIndex]\">\n <img *ngIf=\"!multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"metadata.previewPlaceholderUrl ?? placeHolder\">\n <i (click)=\"next()\"\n [class.disabled]=\"!multiPreviewImages || !multiPreviewImages.length || imageIndex === (multiPreviewImages.length - 1)\"\n class=\"next-button fa-solid fa-angle-right\"\n >\n </i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && metadata.multiple\">\n <button type=\"button\" (click)=\"setIndex(imageIndex-4)\" mat-icon-button *ngIf=\"\n this.multiPreviewImages\n && multiPreviewImages[imageIndex-4]\n && imageIndex === (this.multiPreviewImages.length - 1)\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 3}}</span>\n </button>\n <!-- eslint-disable-next-line @angular-eslint/template/conditional-complexity -->\n <button type=\"button\" (click)=\"setIndex(imageIndex-3)\" mat-icon-button *ngIf=\"this.multiPreviewImages\n && multiPreviewImages[imageIndex-3]\n && (\n imageIndex === (this.multiPreviewImages.length - 2)\n || imageIndex === (this.multiPreviewImages.length - 1)\n )\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 2}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 1}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-1]\">\n <i class=\"dot\"></i>\n <span class=\"image-index\">{{imageIndex}}</span>\n </button>\n <button type=\"button\" mat-icon-button disabled>\n <i class=\"dot selected\"></i>\n <span class=\"image-index\">{{imageIndex + 1}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+1]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 2}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 3}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+3)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+3] && imageIndex <= 1\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 4}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+4)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+4] && imageIndex === 0\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 5}}</span>\n </button>\n </div>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <i class=\"prev-button disabled fa-solid fa-angle-left\"></i>\n <img class=\"mat-elevation-z2\" [src]=\"singlePreviewImage ?? metadata.previewPlaceholderUrl ?? placeHolder\">\n <i class=\"next-button disabled fa-solid fa-angle-right\"></i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <button type=\"button\" disabled mat-icon-button>\n <span class=\"dot selected\"></span>\n <span class=\"image-index\">1</span>\n </button>\n </div>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}.image-preview{height:250px;display:flex;align-items:center;padding-top:15px;padding-bottom:15px}.image-preview .prev-button{font-size:100px;margin-left:5px;color:#0000008a}.image-preview .next-button{font-size:100px;margin-right:5px;color:#0000008a}.image-preview .prev-button:hover,.image-preview .next-button:hover{cursor:pointer;color:#000000b3;transition:all .5s ease}.image-preview .prev-button.disabled,.image-preview .next-button.disabled{color:#00000042}.image-preview .prev-button.disabled:hover,.image-preview .next-button.disabled:hover{color:#00000042;transition:none;cursor:default}.image-preview img{max-width:calc(100% - 100px);max-height:100%;margin-left:auto;margin-right:auto;border-radius:3px}.preview-nav{text-align:center}.preview-nav button{display:inline-block;width:18px;height:18px;margin-left:5px;margin-right:5px}.preview-nav button .dot{height:100%;width:100%;background-color:#00000061;border-radius:50%;display:block}.preview-nav button .dot.selected{background-color:#0000008a}.preview-nav button .image-index{position:absolute;height:100%;width:100%;display:block;top:-11.5px;color:#fff}.preview-nav button:hover .dot{background-color:#0000008a;transition:all .3s ease}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: FileInputComponent, selector: "file-input", inputs: ["propertyValue", "entity", "key", "metadata", "getValidationErrorMessage", "isReadOnly"], outputs: ["fileDataChangeEvent"] }] });
3470
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: FileImageInputComponent, selector: "file-image-input", usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"!metadata.dragAndDrop && !metadata.preview\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n</div>\n\n<div *ngIf=\"metadata.dragAndDrop || metadata.preview\" class=\"file-input mat-elevation-z8\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && metadata.multiple\">\n <i (click)=\"prev()\" [class.disabled]=\"imageIndex === 0\" class=\"prev-button fa-solid fa-angle-left\"></i>\n <img *ngIf=\"multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"multiPreviewImages?.[imageIndex]\">\n <img *ngIf=\"!multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"metadata.previewPlaceholderUrl ?? placeHolder\">\n <i (click)=\"next()\"\n [class.disabled]=\"!multiPreviewImages || !multiPreviewImages.length || imageIndex === (multiPreviewImages.length - 1)\"\n class=\"next-button fa-solid fa-angle-right\"\n >\n </i>\n </div>\n\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && metadata.multiple\">\n <button type=\"button\" (click)=\"setIndex(imageIndex-4)\" mat-icon-button *ngIf=\"\n this.multiPreviewImages\n && multiPreviewImages[imageIndex-4]\n && imageIndex === (this.multiPreviewImages.length - 1)\"\n >\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex - 3}}</div>\n </div>\n </button>\n <!-- eslint-disable-next-line @angular-eslint/template/conditional-complexity -->\n <button type=\"button\" (click)=\"setIndex(imageIndex-3)\" mat-icon-button *ngIf=\"this.multiPreviewImages\n && multiPreviewImages[imageIndex-3]\n && (\n imageIndex === (this.multiPreviewImages.length - 2)\n || imageIndex === (this.multiPreviewImages.length - 1)\n )\"\n >\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex - 2}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-2]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex - 1}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-1]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex}}</div>\n </div>\n </button>\n <button type=\"button\" mat-icon-button disabled>\n <div class=\"dot selected\">\n <div class=\"image-index\">{{imageIndex + 1}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+1]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 2}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+2]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 3}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+3)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+3] && imageIndex <= 1\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 4}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+4)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+4] && imageIndex === 0\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 5}}</div>\n </div>\n </button>\n </div>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <i class=\"prev-button disabled fa-solid fa-angle-left\"></i>\n <img class=\"mat-elevation-z2\" [src]=\"singlePreviewImage ?? metadata.previewPlaceholderUrl ?? placeHolder\">\n <i class=\"next-button disabled fa-solid fa-angle-right\"></i>\n </div>\n\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <button type=\"button\" disabled mat-icon-button>\n <div class=\"dot selected\">\n <div class=\"image-index\">1</div>\n </div>\n </button>\n </div>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}.image-preview{height:250px;display:flex;align-items:center;padding-top:15px;padding-bottom:15px}.image-preview .prev-button{font-size:100px;margin-left:5px;color:#0000008a}.image-preview .next-button{font-size:100px;margin-right:5px;color:#0000008a}.image-preview .prev-button:hover,.image-preview .next-button:hover{cursor:pointer;color:#000000b3;transition:all .5s ease}.image-preview .prev-button.disabled,.image-preview .next-button.disabled{color:#00000042}.image-preview .prev-button.disabled:hover,.image-preview .next-button.disabled:hover{color:#00000042;transition:none;cursor:default}.image-preview img{max-width:calc(100% - 100px);max-height:100%;margin-left:auto;margin-right:auto;border-radius:3px}.preview-nav{display:flex;align-items:center;justify-content:center;column-gap:5px}.preview-nav button{display:flex;align-items:center;justify-content:center;padding:0;height:auto;width:auto}.preview-nav button .dot{display:flex;align-items:center;justify-content:center;height:25px;width:25px;min-width:25px;background-color:#00000061;border-radius:50%}.preview-nav button .dot .image-index{color:#fff;font-size:20px;font-weight:600}.preview-nav button .dot.selected{background-color:#0000008a}.preview-nav button:hover .dot{background-color:#0000008a;transition:all .3s ease}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: FileInputComponent, selector: "file-input", inputs: ["propertyValue", "entity", "key", "metadata", "getValidationErrorMessage", "isReadOnly"], outputs: ["fileDataChangeEvent"] }] });
3209
3471
  }
3210
3472
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: FileImageInputComponent, decorators: [{
3211
3473
  type: Component,
3212
- args: [{ selector: 'file-image-input', template: "<div *ngIf=\"!metadata.dragAndDrop && !metadata.preview\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n</div>\n\n<div *ngIf=\"metadata.dragAndDrop || metadata.preview\" class=\"file-input mat-elevation-z8\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && metadata.multiple\">\n <i (click)=\"prev()\" [class.disabled]=\"imageIndex === 0\" class=\"prev-button fa-solid fa-angle-left\"></i>\n <img *ngIf=\"multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"multiPreviewImages?.[imageIndex]\">\n <img *ngIf=\"!multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"metadata.previewPlaceholderUrl ?? placeHolder\">\n <i (click)=\"next()\"\n [class.disabled]=\"!multiPreviewImages || !multiPreviewImages.length || imageIndex === (multiPreviewImages.length - 1)\"\n class=\"next-button fa-solid fa-angle-right\"\n >\n </i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && metadata.multiple\">\n <button type=\"button\" (click)=\"setIndex(imageIndex-4)\" mat-icon-button *ngIf=\"\n this.multiPreviewImages\n && multiPreviewImages[imageIndex-4]\n && imageIndex === (this.multiPreviewImages.length - 1)\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 3}}</span>\n </button>\n <!-- eslint-disable-next-line @angular-eslint/template/conditional-complexity -->\n <button type=\"button\" (click)=\"setIndex(imageIndex-3)\" mat-icon-button *ngIf=\"this.multiPreviewImages\n && multiPreviewImages[imageIndex-3]\n && (\n imageIndex === (this.multiPreviewImages.length - 2)\n || imageIndex === (this.multiPreviewImages.length - 1)\n )\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 2}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 1}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-1]\">\n <i class=\"dot\"></i>\n <span class=\"image-index\">{{imageIndex}}</span>\n </button>\n <button type=\"button\" mat-icon-button disabled>\n <i class=\"dot selected\"></i>\n <span class=\"image-index\">{{imageIndex + 1}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+1]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 2}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 3}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+3)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+3] && imageIndex <= 1\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 4}}</span>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+4)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+4] && imageIndex === 0\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 5}}</span>\n </button>\n </div>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <i class=\"prev-button disabled fa-solid fa-angle-left\"></i>\n <img class=\"mat-elevation-z2\" [src]=\"singlePreviewImage ?? metadata.previewPlaceholderUrl ?? placeHolder\">\n <i class=\"next-button disabled fa-solid fa-angle-right\"></i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <button type=\"button\" disabled mat-icon-button>\n <span class=\"dot selected\"></span>\n <span class=\"image-index\">1</span>\n </button>\n </div>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}.image-preview{height:250px;display:flex;align-items:center;padding-top:15px;padding-bottom:15px}.image-preview .prev-button{font-size:100px;margin-left:5px;color:#0000008a}.image-preview .next-button{font-size:100px;margin-right:5px;color:#0000008a}.image-preview .prev-button:hover,.image-preview .next-button:hover{cursor:pointer;color:#000000b3;transition:all .5s ease}.image-preview .prev-button.disabled,.image-preview .next-button.disabled{color:#00000042}.image-preview .prev-button.disabled:hover,.image-preview .next-button.disabled:hover{color:#00000042;transition:none;cursor:default}.image-preview img{max-width:calc(100% - 100px);max-height:100%;margin-left:auto;margin-right:auto;border-radius:3px}.preview-nav{text-align:center}.preview-nav button{display:inline-block;width:18px;height:18px;margin-left:5px;margin-right:5px}.preview-nav button .dot{height:100%;width:100%;background-color:#00000061;border-radius:50%;display:block}.preview-nav button .dot.selected{background-color:#0000008a}.preview-nav button .image-index{position:absolute;height:100%;width:100%;display:block;top:-11.5px;color:#fff}.preview-nav button:hover .dot{background-color:#0000008a;transition:all .3s ease}\n"] }]
3474
+ args: [{ selector: 'file-image-input', template: "<div *ngIf=\"!metadata.dragAndDrop && !metadata.preview\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n</div>\n\n<div *ngIf=\"metadata.dragAndDrop || metadata.preview\" class=\"file-input mat-elevation-z8\">\n <file-input\n (fileDataChangeEvent)=\"refreshFileData($event)\"\n [propertyValue]=\"propertyValue\"\n [metadata]=\"metadata\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [isReadOnly]=\"isReadOnly\"\n [entity]=\"entity\"\n [key]=\"key\"\n >\n </file-input>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && metadata.multiple\">\n <i (click)=\"prev()\" [class.disabled]=\"imageIndex === 0\" class=\"prev-button fa-solid fa-angle-left\"></i>\n <img *ngIf=\"multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"multiPreviewImages?.[imageIndex]\">\n <img *ngIf=\"!multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"metadata.previewPlaceholderUrl ?? placeHolder\">\n <i (click)=\"next()\"\n [class.disabled]=\"!multiPreviewImages || !multiPreviewImages.length || imageIndex === (multiPreviewImages.length - 1)\"\n class=\"next-button fa-solid fa-angle-right\"\n >\n </i>\n </div>\n\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && metadata.multiple\">\n <button type=\"button\" (click)=\"setIndex(imageIndex-4)\" mat-icon-button *ngIf=\"\n this.multiPreviewImages\n && multiPreviewImages[imageIndex-4]\n && imageIndex === (this.multiPreviewImages.length - 1)\"\n >\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex - 3}}</div>\n </div>\n </button>\n <!-- eslint-disable-next-line @angular-eslint/template/conditional-complexity -->\n <button type=\"button\" (click)=\"setIndex(imageIndex-3)\" mat-icon-button *ngIf=\"this.multiPreviewImages\n && multiPreviewImages[imageIndex-3]\n && (\n imageIndex === (this.multiPreviewImages.length - 2)\n || imageIndex === (this.multiPreviewImages.length - 1)\n )\"\n >\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex - 2}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-2]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex - 1}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex-1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-1]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex}}</div>\n </div>\n </button>\n <button type=\"button\" mat-icon-button disabled>\n <div class=\"dot selected\">\n <div class=\"image-index\">{{imageIndex + 1}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+1]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 2}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+2]\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 3}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+3)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+3] && imageIndex <= 1\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 4}}</div>\n </div>\n </button>\n <button type=\"button\" (click)=\"setIndex(imageIndex+4)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+4] && imageIndex === 0\">\n <div class=\"dot\">\n <div class=\"image-index\">{{imageIndex + 5}}</div>\n </div>\n </button>\n </div>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <i class=\"prev-button disabled fa-solid fa-angle-left\"></i>\n <img class=\"mat-elevation-z2\" [src]=\"singlePreviewImage ?? metadata.previewPlaceholderUrl ?? placeHolder\">\n <i class=\"next-button disabled fa-solid fa-angle-right\"></i>\n </div>\n\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <button type=\"button\" disabled mat-icon-button>\n <div class=\"dot selected\">\n <div class=\"image-index\">1</div>\n </div>\n </button>\n </div>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}.image-preview{height:250px;display:flex;align-items:center;padding-top:15px;padding-bottom:15px}.image-preview .prev-button{font-size:100px;margin-left:5px;color:#0000008a}.image-preview .next-button{font-size:100px;margin-right:5px;color:#0000008a}.image-preview .prev-button:hover,.image-preview .next-button:hover{cursor:pointer;color:#000000b3;transition:all .5s ease}.image-preview .prev-button.disabled,.image-preview .next-button.disabled{color:#00000042}.image-preview .prev-button.disabled:hover,.image-preview .next-button.disabled:hover{color:#00000042;transition:none;cursor:default}.image-preview img{max-width:calc(100% - 100px);max-height:100%;margin-left:auto;margin-right:auto;border-radius:3px}.preview-nav{display:flex;align-items:center;justify-content:center;column-gap:5px}.preview-nav button{display:flex;align-items:center;justify-content:center;padding:0;height:auto;width:auto}.preview-nav button .dot{display:flex;align-items:center;justify-content:center;height:25px;width:25px;min-width:25px;background-color:#00000061;border-radius:50%}.preview-nav button .dot .image-index{color:#fff;font-size:20px;font-weight:600}.preview-nav button .dot.selected{background-color:#0000008a}.preview-nav button:hover .dot{background-color:#0000008a;transition:all .3s ease}\n"] }]
3213
3475
  }], ctorParameters: function () { return [{ type: i2.HttpClient }]; } });
3214
3476
 
3215
3477
  const NGX_GET_VALIDATION_ERROR_MESSAGE = new InjectionToken('Provider for the default getValidationErrorMessage.', {
@@ -3233,6 +3495,10 @@ function getValidationErrorMessage(model) {
3233
3495
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
3234
3496
  return `needs to be at least ${model.getError('minlength').requiredLength} characters long`;
3235
3497
  }
3498
+ else if (model.hasError('maxlength')) {
3499
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
3500
+ return `needs to be at most ${model.getError('maxlength').requiredLength} characters long`;
3501
+ }
3236
3502
  else if (model.hasError('min')) {
3237
3503
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
3238
3504
  return `needs to be equal or bigger than ${model.getError('min').min}`;
@@ -3241,6 +3507,9 @@ function getValidationErrorMessage(model) {
3241
3507
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
3242
3508
  return `needs to be equal or smaller than ${model.getError('max').max}`;
3243
3509
  }
3510
+ else if (model.hasError('passwordMatch')) {
3511
+ return 'Passwords need to match!';
3512
+ }
3244
3513
  else if (model.hasError('required')) {
3245
3514
  return 'required';
3246
3515
  }
@@ -3748,21 +4017,21 @@ class StringPasswordInputComponent extends NgxMatEntityBaseInputComponent {
3748
4017
  this.emitChange();
3749
4018
  }
3750
4019
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: StringPasswordInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3751
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: StringPasswordInputComponent, selector: "string-password-input", usesInheritance: true, ngImport: i0, template: "<div class=\"password-row\">\n <mat-form-field [class.w-50]=\"metadata.needsConfirmation\" [class.w-100]=\"!metadata.needsConfirmation\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n [type]=\"hide ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n >\n <button type=\"button\" (click)=\"hide = !hide\" mat-icon-button matSuffix>\n <i *ngIf=\"hide\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hide\" class=\"fas fa-eye\"></i>\n </button>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <div *ngIf=\"metadata.needsConfirmation\" class=\"password-spacer\"></div>\n <mat-form-field class=\"w-50\" *ngIf=\"metadata.needsConfirmation\">\n <mat-label>{{metadata.confirmationDisplayName}}</mat-label>\n <input\n [type]=\"hideConfirm ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"confirmPassword\"\n [name]=\"key.toString() + 'confirmPassword' + uuid\"\n #confirmModel=\"ngModel\"\n [required]=\"confirmRequired\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n >\n <button type=\"button\" (click)=\"hideConfirm = !hideConfirm\" mat-icon-button matSuffix>\n <i *ngIf=\"hideConfirm\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hideConfirm\" class=\"fas fa-eye\"></i>\n </button>\n <mat-error>{{getValidationErrorMessage(confirmModel)}}</mat-error>\n </mat-form-field>\n</div>\n\n<mat-error *ngIf=\"metadata.needsConfirmation && propertyValue && confirmPassword && (confirmPassword !== propertyValue)\">\n {{metadata.passwordsDontMatchErrorMessage}}\n</mat-error>", styles: [".password-row{display:flex;justify-content:space-between}.password-spacer{margin-left:12px;margin-right:12px}.w-50{width:50%}.w-100{width:100%}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2$2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i3.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }] });
4020
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: StringPasswordInputComponent, selector: "string-password-input", usesInheritance: true, ngImport: i0, template: "<div class=\"password-row\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n [type]=\"hide ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n >\n <button type=\"button\" (click)=\"hide = !hide\" mat-icon-button matSuffix>\n <div class=\"d-flex justify-content-center align-items-center\">\n <i *ngIf=\"hide\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hide\" class=\"fas fa-eye\"></i>\n </div>\n </button>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field *ngIf=\"metadata.needsConfirmation\">\n <mat-label>{{metadata.confirmationDisplayName}}</mat-label>\n <input\n [type]=\"hideConfirm ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"confirmPassword\"\n [name]=\"key.toString() + 'confirmPassword' + uuid\"\n #confirmModel=\"ngModel\"\n [required]=\"confirmRequired\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n [passwordMatch]=\"propertyValue\"\n >\n <button type=\"button\" (click)=\"hideConfirm = !hideConfirm\" mat-icon-button matSuffix>\n <div class=\"d-flex justify-content-center align-items-center\">\n <i *ngIf=\"hideConfirm\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hideConfirm\" class=\"fas fa-eye\"></i>\n </div>\n </button>\n <mat-error>{{getValidationErrorMessage(confirmModel)}}</mat-error>\n </mat-form-field>\n</div>", styles: [".password-row{display:flex;justify-content:space-evenly;column-gap:24px}.password-row mat-form-field{flex:1 1 0}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2$2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i3.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "directive", type: PasswordMatchValidatorDirective, selector: "[passwordMatch]", inputs: ["passwordMatch"] }] });
3752
4021
  }
3753
4022
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: StringPasswordInputComponent, decorators: [{
3754
4023
  type: Component,
3755
- args: [{ selector: 'string-password-input', template: "<div class=\"password-row\">\n <mat-form-field [class.w-50]=\"metadata.needsConfirmation\" [class.w-100]=\"!metadata.needsConfirmation\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n [type]=\"hide ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n >\n <button type=\"button\" (click)=\"hide = !hide\" mat-icon-button matSuffix>\n <i *ngIf=\"hide\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hide\" class=\"fas fa-eye\"></i>\n </button>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <div *ngIf=\"metadata.needsConfirmation\" class=\"password-spacer\"></div>\n <mat-form-field class=\"w-50\" *ngIf=\"metadata.needsConfirmation\">\n <mat-label>{{metadata.confirmationDisplayName}}</mat-label>\n <input\n [type]=\"hideConfirm ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"confirmPassword\"\n [name]=\"key.toString() + 'confirmPassword' + uuid\"\n #confirmModel=\"ngModel\"\n [required]=\"confirmRequired\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n >\n <button type=\"button\" (click)=\"hideConfirm = !hideConfirm\" mat-icon-button matSuffix>\n <i *ngIf=\"hideConfirm\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hideConfirm\" class=\"fas fa-eye\"></i>\n </button>\n <mat-error>{{getValidationErrorMessage(confirmModel)}}</mat-error>\n </mat-form-field>\n</div>\n\n<mat-error *ngIf=\"metadata.needsConfirmation && propertyValue && confirmPassword && (confirmPassword !== propertyValue)\">\n {{metadata.passwordsDontMatchErrorMessage}}\n</mat-error>", styles: [".password-row{display:flex;justify-content:space-between}.password-spacer{margin-left:12px;margin-right:12px}.w-50{width:50%}.w-100{width:100%}\n"] }]
4024
+ args: [{ selector: 'string-password-input', template: "<div class=\"password-row\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n [type]=\"hide ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n >\n <button type=\"button\" (click)=\"hide = !hide\" mat-icon-button matSuffix>\n <div class=\"d-flex justify-content-center align-items-center\">\n <i *ngIf=\"hide\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hide\" class=\"fas fa-eye\"></i>\n </div>\n </button>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field *ngIf=\"metadata.needsConfirmation\">\n <mat-label>{{metadata.confirmationDisplayName}}</mat-label>\n <input\n [type]=\"hideConfirm ? 'password' : 'text'\"\n matInput\n [(ngModel)]=\"confirmPassword\"\n [name]=\"key.toString() + 'confirmPassword' + uuid\"\n #confirmModel=\"ngModel\"\n [required]=\"confirmRequired\"\n (ngModelChange)=\"passwordInput()\"\n [disabled]=\"isReadOnly\"\n [passwordMatch]=\"propertyValue\"\n >\n <button type=\"button\" (click)=\"hideConfirm = !hideConfirm\" mat-icon-button matSuffix>\n <div class=\"d-flex justify-content-center align-items-center\">\n <i *ngIf=\"hideConfirm\" class=\"fas fa-eye-slash\"></i>\n <i *ngIf=\"!hideConfirm\" class=\"fas fa-eye\"></i>\n </div>\n </button>\n <mat-error>{{getValidationErrorMessage(confirmModel)}}</mat-error>\n </mat-form-field>\n</div>", styles: [".password-row{display:flex;justify-content:space-evenly;column-gap:24px}.password-row mat-form-field{flex:1 1 0}\n"] }]
3756
4025
  }] });
3757
4026
 
3758
4027
  /* eslint-disable jsdoc/require-jsdoc */
3759
4028
  class NumberInputComponent extends NgxMatEntityBaseInputComponent {
3760
4029
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NumberInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3761
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NumberInputComponent, selector: "number-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
4030
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NumberInputComponent, selector: "number-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n number\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NumberDirective, selector: "[number]" }] });
3762
4031
  }
3763
4032
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NumberInputComponent, decorators: [{
3764
4033
  type: Component,
3765
- args: [{ selector: 'number-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
4034
+ args: [{ selector: 'number-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n number\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
3766
4035
  }] });
3767
4036
 
3768
4037
  /* eslint-disable jsdoc/require-jsdoc */
@@ -3782,12 +4051,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
3782
4051
 
3783
4052
  /* eslint-disable jsdoc/require-jsdoc */
3784
4053
  class NumberSliderInputComponent extends NgxMatEntityBaseInputComponent {
4054
+ updatePropertyValue(value) {
4055
+ this.propertyValue = value;
4056
+ }
3785
4057
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NumberSliderInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3786
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NumberSliderInputComponent, selector: "number-slider-input", usesInheritance: true, ngImport: i0, template: "<mat-slider\n id=\"slider\"\n color=\"primary\"\n (click)=\"model.control.markAsTouched()\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n [step]=\"metadata.step\"\n [discrete]=\"true\"\n [displayWith]=\"metadata.formatThumbLabelValue\"\n [showTickMarks]=\"metadata.showTickMarks\"\n [disabled]=\"isReadOnly\"\n>\n <input matSliderThumb\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + 'Helper' + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n >\n</mat-slider>\n\n<mat-form-field floatLabel=\"always\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <!-- hidden input is needed so that the slider can be used inside a mat-form-field -->\n <input matInput style=\"opacity: 0%;\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%;margin-top:-40px}mat-slider{width:calc(100% - 40px);margin-left:20px;margin-right:20px;margin-bottom:-40px;z-index:999}::ng-deep #slider .mdc-slider__value-indicator-container{top:23px;left:57px;display:flex;transform:rotate(90deg) scale(1);border-radius:50%;pointer-events:auto}::ng-deep #slider .mdc-slider__value-indicator{padding-right:5px;padding-left:5px;transition:transform .1s 0ms cubic-bezier(0,0,.2,1);transform:scale(1)}::ng-deep #slider .mdc-slider__value-indicator-text{transform:rotate(270deg)}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4$4.MatSlider, selector: "mat-slider", inputs: ["color", "disableRipple", "disabled", "discrete", "showTickMarks", "min", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i4$4.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }] });
4058
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NumberSliderInputComponent, selector: "number-slider-input", usesInheritance: true, ngImport: i0, template: "<mat-slider\n id=\"slider\"\n color=\"primary\"\n (click)=\"model.control.markAsTouched()\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n [step]=\"metadata.step\"\n [discrete]=\"true\"\n [displayWith]=\"metadata.formatThumbLabelValue\"\n [showTickMarks]=\"metadata.showTickMarks\"\n [disabled]=\"isReadOnly\"\n>\n <input matSliderThumb\n (valueChange)=\"updatePropertyValue($event)\"\n [disabled]=\"isReadOnly\"\n >\n</mat-slider>\n\n<mat-form-field floatLabel=\"always\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <!-- hidden input is needed so that the slider can be used inside a mat-form-field -->\n <input matInput style=\"opacity: 0%;\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n >\n \n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%;margin-top:-40px}mat-slider{width:calc(100% - 40px);margin-left:20px;margin-right:20px;margin-bottom:-40px;z-index:999}::ng-deep #slider .mdc-slider__value-indicator-container{top:23px;left:57px;display:flex;transform:rotate(90deg) scale(1);border-radius:50%;pointer-events:auto}::ng-deep #slider .mdc-slider__value-indicator{padding-right:5px;padding-left:5px;transition:transform .1s 0ms cubic-bezier(0,0,.2,1);transform:scale(1)}::ng-deep #slider .mdc-slider__value-indicator-text{transform:rotate(270deg)}\n"], dependencies: [{ kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4$4.MatSlider, selector: "mat-slider", inputs: ["color", "disableRipple", "disabled", "discrete", "showTickMarks", "min", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: i4$4.MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }] });
3787
4059
  }
3788
4060
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NumberSliderInputComponent, decorators: [{
3789
4061
  type: Component,
3790
- args: [{ selector: 'number-slider-input', template: "<mat-slider\n id=\"slider\"\n color=\"primary\"\n (click)=\"model.control.markAsTouched()\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n [step]=\"metadata.step\"\n [discrete]=\"true\"\n [displayWith]=\"metadata.formatThumbLabelValue\"\n [showTickMarks]=\"metadata.showTickMarks\"\n [disabled]=\"isReadOnly\"\n>\n <input matSliderThumb\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + 'Helper' + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n >\n</mat-slider>\n\n<mat-form-field floatLabel=\"always\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <!-- hidden input is needed so that the slider can be used inside a mat-form-field -->\n <input matInput style=\"opacity: 0%;\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%;margin-top:-40px}mat-slider{width:calc(100% - 40px);margin-left:20px;margin-right:20px;margin-bottom:-40px;z-index:999}::ng-deep #slider .mdc-slider__value-indicator-container{top:23px;left:57px;display:flex;transform:rotate(90deg) scale(1);border-radius:50%;pointer-events:auto}::ng-deep #slider .mdc-slider__value-indicator{padding-right:5px;padding-left:5px;transition:transform .1s 0ms cubic-bezier(0,0,.2,1);transform:scale(1)}::ng-deep #slider .mdc-slider__value-indicator-text{transform:rotate(270deg)}\n"] }]
4062
+ args: [{ selector: 'number-slider-input', template: "<mat-slider\n id=\"slider\"\n color=\"primary\"\n (click)=\"model.control.markAsTouched()\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n [step]=\"metadata.step\"\n [discrete]=\"true\"\n [displayWith]=\"metadata.formatThumbLabelValue\"\n [showTickMarks]=\"metadata.showTickMarks\"\n [disabled]=\"isReadOnly\"\n>\n <input matSliderThumb\n (valueChange)=\"updatePropertyValue($event)\"\n [disabled]=\"isReadOnly\"\n >\n</mat-slider>\n\n<mat-form-field floatLabel=\"always\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <!-- hidden input is needed so that the slider can be used inside a mat-form-field -->\n <input matInput style=\"opacity: 0%;\"\n [(ngModel)]=\"propertyValue\"\n [name]=\"key.toString() + uuid\"\n #model=\"ngModel\"\n [required]=\"metadata.required(entity)\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n [disabled]=\"isReadOnly\"\n >\n \n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%;margin-top:-40px}mat-slider{width:calc(100% - 40px);margin-left:20px;margin-right:20px;margin-bottom:-40px;z-index:999}::ng-deep #slider .mdc-slider__value-indicator-container{top:23px;left:57px;display:flex;transform:rotate(90deg) scale(1);border-radius:50%;pointer-events:auto}::ng-deep #slider .mdc-slider__value-indicator{padding-right:5px;padding-left:5px;transition:transform .1s 0ms cubic-bezier(0,0,.2,1);transform:scale(1)}::ng-deep #slider .mdc-slider__value-indicator-text{transform:rotate(270deg)}\n"] }]
3791
4063
  }] });
3792
4064
 
3793
4065
  /* eslint-disable jsdoc/require-jsdoc */
@@ -4547,7 +4819,7 @@ class NgxMatEntityInputComponent {
4547
4819
  * @param omit - Whether values omitted for create or update should be left out.
4548
4820
  */
4549
4821
  checkIsHasManyEntityValid(omit) {
4550
- this.isHasManyEntityValid = EntityUtilities.isEntityValid(this.hasManyEntity, omit);
4822
+ this.isHasManyEntityValid = ValidationUtilities.isEntityValid(this.hasManyEntity, omit);
4551
4823
  }
4552
4824
  /**
4553
4825
  * Checks whether the array item is valid and if the array item is dirty.
@@ -4566,7 +4838,7 @@ class NgxMatEntityInputComponent {
4566
4838
  * Checks if the arrayItem is valid.
4567
4839
  */
4568
4840
  checkIsArrayItemValid() {
4569
- this.isArrayItemValid = EntityUtilities.isEntityValid(this.arrayItem, 'create');
4841
+ this.isArrayItemValid = ValidationUtilities.isEntityValid(this.arrayItem, 'create');
4570
4842
  }
4571
4843
  /**
4572
4844
  * Emits that a the value has been changed.
@@ -4673,11 +4945,11 @@ class NgxMatEntityInputComponent {
4673
4945
  this.emitChange();
4674
4946
  }
4675
4947
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityInputComponent, deps: [{ token: i1.MatDialog }, { token: i0.EnvironmentInjector }, { token: i2$3.Router }, { token: NGX_GET_VALIDATION_ERROR_MESSAGE }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
4676
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: { entity: "entity", propertyKey: "propertyKey", getValidationErrorMessage: "getValidationErrorMessage", hideOmitForCreate: "hideOmitForCreate", hideOmitForEdit: "hideOmitForEdit", validEmpty: "validEmpty", isReadOnly: "isReadOnly" }, outputs: { inputChangeEvent: "inputChangeEvent" }, viewQueries: [{ propertyName: "addArrayItemDialog", first: true, predicate: ["addArrayItemDialog"], descendants: true }, { propertyName: "editArrayItemDialog", first: true, predicate: ["editArrayItemDialog"], descendants: true }, { propertyName: "hasManyPaginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "hasManySort", first: true, predicate: MatSort, descendants: true }, { propertyName: "hasManyFilter", first: true, predicate: ["filter"], descendants: true, static: true }, { propertyName: "createHasManyDialog", first: true, predicate: ["createHasManyDialog"], descendants: true }, { propertyName: "editHasManyDialog", first: true, predicate: ["editHasManyDialog"], descendants: true }], ngImport: i0, template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <string-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <string-textbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-textbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <string-autocomplete-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-autocomplete-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <string-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_PASSWORD\">\n <string-password-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-password-input>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <boolean-checkbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-checkbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <boolean-toggle-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-toggle-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <boolean-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <number-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <number-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_SLIDER\">\n <number-slider-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-slider-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE\">\n <array-date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_TIME\">\n <array-date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-time-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_RANGE\">\n <array-date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <array-string-chips-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-chips-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <array-string-autocomplete-chips\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-autocomplete-chips>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Dates-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.DATE\">\n <date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_RANGE\">\n <date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_TIME\">\n <date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-time-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Files-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.FILE_DEFAULT\">\n <file-default-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-default-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.FILE_IMAGE\">\n <file-image-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-image-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references many ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_MANY\">\n <references-many-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </references-many-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Custom------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.CUSTOM\">\n <custom-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </custom-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n <mat-tab-group *ngIf=\"objectPropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of objectPropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"objectPropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of objectPropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references one ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_ONE\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"internalEntity[internalPropertyKey]\"\n [name]=\"internalPropertyKey.toString() + 'input' + referencesOneUUID\"\n #inputModel=\"ngModel\"\n [disabled]=\"internalIsReadOnly\"\n [required]=\"metadata.required(entity)\"\n (ngModelChange)=\"setReferencesOneObject()\"\n >\n <mat-option *ngIf=\"!metadata.required(entity)\">-</mat-option>\n <mat-option *ngFor=\"let value of referencesOneDropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{internalGetValidationErrorMessage(inputModel)}}</mat-error>\n </mat-form-field>\n <!-- iterates over the references one properties -->\n <mat-tab-group *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of referencesOnePropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of referencesOnePropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8 elevation-container\">\n <div class=\"array-headline\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline && !internalIsReadOnly\">\n <mat-tab-group *ngIf=\"arrayItemInlineTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemInlineTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"arrayItemInlineTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <div class=\"buttons\" *ngIf=\"!internalIsReadOnly\">\n <button type=\"button\" mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !isArrayItemValid\"\n (click)=\"addEntity()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button\n [disabled]=\"!entityArraySelection.selected.length\"\n (click)=\"removeFromEntityArray()\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"entityArrayDataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\" *ngIf=\"!internalIsReadOnly\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n [disabled]=\"!entityArrayDataSource.data.length\" (change)=\"$event ? SelectionUtilities.masterToggle(entityArraySelection, entityArrayDataSource) : null\"\n [checked]=\"entityArraySelection.hasValue() && SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\"\n [indeterminate]=\"entityArraySelection.hasValue() && !SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? entityArraySelection.toggle(entity) : null\" [checked]=\"entityArraySelection.isSelected(entity)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick\" (click)=\"editArrayItem(entity, dCol)\" *matCellDef=\"let entity\">\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"entityArrayDisplayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: entityArrayDisplayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required(entity) && !entityArrayDataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!------------------ has many ---------------->\n <!-------------------------------------------->\n <div class=\"hasMany\" *ngSwitchCase=\"DecoratorTypes.HAS_MANY\">\n <h2 class=\"title\">{{metadataHasMany.tableData.baseData.title}}</h2>\n\n <div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{metadataHasMany.tableData.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyHasManyFilter($event)\">\n </mat-form-field>\n <div\n *ngIf=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-2]=\"hasManyAllowCreate\"\n [class.col-lg-4]=\"!hasManyAllowCreate\"\n [class.col-md-3]=\"hasManyAllowCreate\"\n [class.col-md-6]=\"!hasManyAllowCreate\"\n [class.col-sm-6]=\"hasManyAllowCreate\"\n [class.col-sm-12]=\"!hasManyAllowCreate\"\n >\n <button type=\"button\" class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.tableActionsLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngIf=\"metadataHasMany.tableData.baseData.allowJsonImport\" type=\"button\" [disabled]=\"hasManyTableActionDisabled(hasManyImportAction)\" (click)=\"runHasManyTableAction(hasManyImportAction)\" mat-menu-item>\n {{hasManyImportAction.displayName}}\n </button>\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.baseData.tableActions\" [disabled]=\"hasManyTableActionDisabled(action)\" (click)=\"runHasManyTableAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"hasManyAllowCreate\"\n [class.col-lg-2]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-4]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-3]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-6]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-6]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-12]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n >\n <button type=\"button\" class=\"create-button\" (click)=\"createHasManyEntity()\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.createButtonLabel}}\n </button>\n </div>\n </div>\n\n <div class=\"mat-elevation-z8 elevation-container\">\n <mat-table [dataSource]=\"hasManyDataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? SelectionUtilities.masterToggle(hasManySelection, hasManyDataSource) : null\"\n [checked]=\"hasManySelection.hasValue() && SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\"\n [indeterminate]=\"hasManySelection.hasValue() && !SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\" class=\"enabled\">\n <mat-checkbox (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? hasManySelection.toggle(entity) : null\"\n [checked]=\"hasManySelection.isSelected(entity)\">\n </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of metadataHasMany.tableData.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick && (hasManyAllowUpdate(entity) || hasManyAllowRead(entity))\"\n (click)=\"editHasManyEntity(entity, dCol)\"\n *matCellDef=\"let entity\"\n >\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedHasManyColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedHasManyColumns\"></mat-row>\n </mat-table>\n\n <mat-spinner *ngIf=\"hasManyIsLoading && metadataHasMany.tableData.baseData.displayLoadingSpinner\">\n </mat-spinner>\n\n <mat-paginator [length]=\"hasManyDataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"></mat-paginator>\n </div>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{addArrayItemDialogData.title}}</div>\n </div>\n\n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!isArrayItemValid\">\n {{addArrayItemDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeAddArrayItemDialog()\" class=\"cancel-button\">\n {{addArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Edit Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #editArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{editArrayItemDialogData.title(arrayItemPriorChanges)}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"saveArrayItem()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isArrayItemValid || !isArrayItemDirty\">\n {{editArrayItemDialogData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeEditArrayItemDialog()\" class=\"cancel-button\">\n {{editArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Create Has Many Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #createHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.createDialogData.title}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyCreateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyCreateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyCreateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyCreateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogCreateHasMany()\" mat-raised-button [disabled]=\"!isHasManyEntityValid\">\n {{metadataHasMany.tableData.createDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelCreateHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n \n</ng-template>\n\n<ng-template #editHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.editData.title(hasManyEntityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"metadataHasMany.tableData.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.editData.actions\" [disabled]=\"hasManyEditActionDisabled(action)\" (click)=\"hasManyRunEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"hasManyAllowDelete(hasManyEntity)\" mat-raised-button (click)=\"deleteHasManyEntity()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{metadataHasMany.tableData.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyUpdateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyUpdateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyUpdateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyUpdateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogEditHasMany()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isHasManyEntityValid || !isHasManyEntityDirty\">\n {{metadataHasMany.tableData.editData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelEditHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form> \n</ng-template>", styles: [".mdc-data-table__row:last-child .mdc-data-table__cell{border-bottom:1px solid rgba(0,0,0,.12)}.mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}mat-spinner{margin:10px auto}::ng-deep .mat-mdc-tab-body-wrapper{margin-left:-12px;margin-right:-12px}::ng-deep mat-tab-body{padding-top:10px;padding-left:12px;padding-right:12px}::ng-deep mat-tab-body .mat-mdc-tab-body-content{overflow:initial}::ng-deep .mat-mdc-form-field.mat-form-field-disabled label{color:#0009}::ng-deep .mat-mdc-form-field.mat-form-field-disabled input,::ng-deep .mat-mdc-form-field.mat-form-field-disabled textarea,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-disabled,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-value{color:#000}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled{opacity:1}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled button{opacity:.2}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-date-range-input-inner:disabled{color:#000}::ng-deep .mat-mdc-form-field .mat-mdc-slide-toggle{opacity:1}.entityArray .elevation-container{border-radius:5px;padding:15px;margin-bottom:15px;margin-top:15px}.entityArray .array-headline{padding-bottom:10px}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .enabled:hover{cursor:pointer}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.hasMany button{width:100%;height:56px;line-height:24px;font-size:16px}.hasMany .title{text-align:center}.hasMany .elevation-container{border-radius:5px;padding:5px;margin-bottom:15px}.hasMany .mat-column-select{flex:0 0 75px}.hasMany .enabled:hover{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i5$1.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "component", type: i14.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i14.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i14.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i15.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i16.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: DisplayColumnValueComponent, selector: "display-column-value", inputs: ["entity", "ComponentClass"] }, { kind: "directive", type: i18.MatSort, selector: "[matSort]", inputs: ["matSortDisabled", "matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i18.MatSortHeader, selector: "[mat-sort-header]", inputs: ["disabled", "mat-sort-header", "arrowPosition", "start", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: StringInputComponent, selector: "string-input" }, { kind: "component", type: StringTextboxInputComponent, selector: "string-textbox-input" }, { kind: "component", type: StringAutocompleteInputComponent, selector: "string-autocomplete-input" }, { kind: "component", type: StringDropdownInputComponent, selector: "string-dropdown-input" }, { kind: "component", type: StringPasswordInputComponent, selector: "string-password-input" }, { kind: "component", type: BooleanCheckboxInputComponent, selector: "boolean-checkbox-input" }, { kind: "component", type: BooleanToggleInputComponent, selector: "boolean-toggle-input" }, { kind: "component", type: BooleanDropdownInputComponent, selector: "boolean-dropdown-input" }, { kind: "component", type: NumberInputComponent, selector: "number-input" }, { kind: "component", type: NumberDropdownInputComponent, selector: "number-dropdown-input" }, { kind: "component", type: NumberSliderInputComponent, selector: "number-slider-input" }, { kind: "component", type: ArrayStringChipsInputComponent, selector: "array-string-chips-input" }, { kind: "component", type: ArrayStringAutocompleteChipsComponent, selector: "array-string-autocomplete-chips" }, { kind: "component", type: DateInputComponent, selector: "date-input" }, { kind: "component", type: DateRangeInputComponent, selector: "date-range-input" }, { kind: "component", type: DateTimeInputComponent, selector: "date-time-input" }, { kind: "component", type: ArrayDateInputComponent, selector: "array-date-input" }, { kind: "component", type: ArrayDateTimeInputComponent, selector: "array-date-time-input" }, { kind: "component", type: ArrayDateRangeInputComponent, selector: "array-date-range-input" }, { kind: "component", type: FileImageInputComponent, selector: "file-image-input" }, { kind: "component", type: FileDefaultInputComponent, selector: "file-default-input" }, { kind: "component", type: ReferencesManyInputComponent, selector: "references-many-input" }, { kind: "component", type: CustomInputComponent, selector: "custom-input" }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }] });
4948
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: { entity: "entity", propertyKey: "propertyKey", getValidationErrorMessage: "getValidationErrorMessage", hideOmitForCreate: "hideOmitForCreate", hideOmitForEdit: "hideOmitForEdit", validEmpty: "validEmpty", isReadOnly: "isReadOnly" }, outputs: { inputChangeEvent: "inputChangeEvent" }, viewQueries: [{ propertyName: "addArrayItemDialog", first: true, predicate: ["addArrayItemDialog"], descendants: true }, { propertyName: "editArrayItemDialog", first: true, predicate: ["editArrayItemDialog"], descendants: true }, { propertyName: "hasManyPaginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "hasManySort", first: true, predicate: MatSort, descendants: true }, { propertyName: "hasManyFilter", first: true, predicate: ["filter"], descendants: true, static: true }, { propertyName: "createHasManyDialog", first: true, predicate: ["createHasManyDialog"], descendants: true }, { propertyName: "editHasManyDialog", first: true, predicate: ["editHasManyDialog"], descendants: true }], ngImport: i0, template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <string-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <string-textbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-textbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <string-autocomplete-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-autocomplete-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <string-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_PASSWORD\">\n <string-password-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-password-input>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <boolean-checkbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-checkbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <boolean-toggle-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-toggle-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <boolean-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <number-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <number-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_SLIDER\">\n <number-slider-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-slider-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE\">\n <array-date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_TIME\">\n <array-date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-time-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_RANGE\">\n <array-date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <array-string-chips-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-chips-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <array-string-autocomplete-chips\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-autocomplete-chips>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Dates-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.DATE\">\n <date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_RANGE\">\n <date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_TIME\">\n <date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-time-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Files-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.FILE_DEFAULT\">\n <file-default-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-default-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.FILE_IMAGE\">\n <file-image-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-image-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references many ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_MANY\">\n <references-many-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </references-many-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Custom------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.CUSTOM\">\n <custom-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </custom-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n <mat-tab-group *ngIf=\"objectPropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of objectPropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"objectPropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of objectPropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references one ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_ONE\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"internalEntity[internalPropertyKey]\"\n [name]=\"internalPropertyKey.toString() + 'input' + referencesOneUUID\"\n #inputModel=\"ngModel\"\n [disabled]=\"internalIsReadOnly\"\n [required]=\"metadata.required(entity)\"\n (ngModelChange)=\"setReferencesOneObject()\"\n >\n <mat-option *ngIf=\"!metadata.required(entity)\">-</mat-option>\n <mat-option *ngFor=\"let value of referencesOneDropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{internalGetValidationErrorMessage(inputModel)}}</mat-error>\n </mat-form-field>\n <!-- iterates over the references one properties -->\n <mat-tab-group *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of referencesOnePropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of referencesOnePropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8 elevation-container\">\n <div class=\"array-headline\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline && !internalIsReadOnly\">\n <mat-tab-group *ngIf=\"arrayItemInlineTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemInlineTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"arrayItemInlineTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <div class=\"buttons\" *ngIf=\"!internalIsReadOnly\">\n <button type=\"button\" mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !isArrayItemValid\"\n (click)=\"addEntity()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button\n [disabled]=\"!entityArraySelection.selected.length\"\n (click)=\"removeFromEntityArray()\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"entityArrayDataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\" *ngIf=\"!internalIsReadOnly\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n [disabled]=\"!entityArrayDataSource.data.length\" (change)=\"$event ? SelectionUtilities.masterToggle(entityArraySelection, entityArrayDataSource) : null\"\n [checked]=\"entityArraySelection.hasValue() && SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\"\n [indeterminate]=\"entityArraySelection.hasValue() && !SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? entityArraySelection.toggle(entity) : null\" [checked]=\"entityArraySelection.isSelected(entity)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick\" (click)=\"editArrayItem(entity, dCol)\" *matCellDef=\"let entity\">\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"entityArrayDisplayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: entityArrayDisplayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required(entity) && !entityArrayDataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!------------------ has many ---------------->\n <!-------------------------------------------->\n <div class=\"hasMany\" *ngSwitchCase=\"DecoratorTypes.HAS_MANY\">\n <h2 class=\"title\">{{metadataHasMany.tableData.baseData.title}}</h2>\n\n <div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{metadataHasMany.tableData.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyHasManyFilter($event)\">\n </mat-form-field>\n <div\n *ngIf=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-2]=\"hasManyAllowCreate\"\n [class.col-lg-4]=\"!hasManyAllowCreate\"\n [class.col-md-3]=\"hasManyAllowCreate\"\n [class.col-md-6]=\"!hasManyAllowCreate\"\n [class.col-sm-6]=\"hasManyAllowCreate\"\n [class.col-sm-12]=\"!hasManyAllowCreate\"\n >\n <button type=\"button\" class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.tableActionsLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngIf=\"metadataHasMany.tableData.baseData.allowJsonImport\" type=\"button\" [disabled]=\"hasManyTableActionDisabled(hasManyImportAction)\" (click)=\"runHasManyTableAction(hasManyImportAction)\" mat-menu-item>\n {{hasManyImportAction.displayName}}\n </button>\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.baseData.tableActions\" [disabled]=\"hasManyTableActionDisabled(action)\" (click)=\"runHasManyTableAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"hasManyAllowCreate\"\n [class.col-lg-2]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-4]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-3]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-6]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-6]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-12]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n >\n <button type=\"button\" class=\"create-button\" (click)=\"createHasManyEntity()\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.createButtonLabel}}\n </button>\n </div>\n </div>\n\n <div class=\"mat-elevation-z8 elevation-container\">\n <mat-table [dataSource]=\"hasManyDataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? SelectionUtilities.masterToggle(hasManySelection, hasManyDataSource) : null\"\n [checked]=\"hasManySelection.hasValue() && SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\"\n [indeterminate]=\"hasManySelection.hasValue() && !SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\" class=\"enabled\">\n <mat-checkbox (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? hasManySelection.toggle(entity) : null\"\n [checked]=\"hasManySelection.isSelected(entity)\">\n </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of metadataHasMany.tableData.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick && (hasManyAllowUpdate(entity) || hasManyAllowRead(entity))\"\n (click)=\"editHasManyEntity(entity, dCol)\"\n *matCellDef=\"let entity\"\n >\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedHasManyColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedHasManyColumns\"></mat-row>\n </mat-table>\n\n <mat-spinner *ngIf=\"hasManyIsLoading && metadataHasMany.tableData.baseData.displayLoadingSpinner\">\n </mat-spinner>\n\n <mat-paginator [length]=\"hasManyDataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"></mat-paginator>\n </div>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{addArrayItemDialogData.title}}</div>\n </div>\n\n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!isArrayItemValid\">\n {{addArrayItemDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeAddArrayItemDialog()\" class=\"cancel-button\">\n {{addArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Edit Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #editArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{editArrayItemDialogData.title(arrayItemPriorChanges)}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"saveArrayItem()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isArrayItemValid || !isArrayItemDirty\">\n {{editArrayItemDialogData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeEditArrayItemDialog()\" class=\"cancel-button\">\n {{editArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Create Has Many Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #createHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.createDialogData.title}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyCreateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyCreateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyCreateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyCreateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogCreateHasMany()\" mat-raised-button [disabled]=\"!isHasManyEntityValid\">\n {{metadataHasMany.tableData.createDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelCreateHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n \n</ng-template>\n\n<ng-template #editHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.editData.title(hasManyEntityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"metadataHasMany.tableData.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.editData.actions\" [disabled]=\"hasManyEditActionDisabled(action)\" (click)=\"hasManyRunEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"hasManyAllowDelete(hasManyEntity)\" mat-raised-button (click)=\"deleteHasManyEntity()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{metadataHasMany.tableData.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyUpdateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyUpdateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyUpdateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyUpdateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogEditHasMany()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isHasManyEntityValid || !isHasManyEntityDirty\">\n {{metadataHasMany.tableData.editData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelEditHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form> \n</ng-template>", styles: [".mdc-data-table__row:last-child .mdc-data-table__cell{border-bottom:1px solid rgba(0,0,0,.12)}.mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}mat-spinner{margin:10px auto}::ng-deep .mat-mdc-tab-body-wrapper{margin-left:-12px;margin-right:-12px}::ng-deep mat-tab-body{padding-top:10px;padding-left:12px;padding-right:12px}::ng-deep mat-tab-body .mat-mdc-tab-body-content{overflow:initial}::ng-deep .mat-mdc-form-field.mat-form-field-disabled label{color:#0009}::ng-deep .mat-mdc-form-field.mat-form-field-disabled input,::ng-deep .mat-mdc-form-field.mat-form-field-disabled textarea,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-disabled,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-value{color:#000!important}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:#707070}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[disabled]:checked~.mdc-checkbox__background,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[disabled]:indeterminate~.mdc-checkbox__background,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true][disabled]~.mdc-checkbox__background{background-color:#000}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled{opacity:1}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled button{opacity:.2}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--selected:disabled .mdc-switch__icons,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--unselected:disabled .mdc-switch__icons{opacity:1}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--selected:disabled .mdc-switch__handle:after,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--unselected:disabled .mdc-switch__handle:after{opacity:1;background:black}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--selected:disabled .mdc-switch__track,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--unselected:disabled .mdc-switch__track{opacity:.3}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-date-range-input-inner:disabled{color:#000}::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled{opacity:1}::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled .mdc-slider__input{cursor:default}::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled mat-slider-visual-thumb .mat-mdc-slider,::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled mat-slider-visual-thumb .mdc-slider__thumb:hover,::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled mat-slider-visual-thumb .mdc-slider__thumb-knob{background-color:#000;border-color:#000}::ng-deep .mat-mdc-form-field .mat-mdc-slide-toggle{opacity:1}.entityArray .elevation-container{border-radius:5px;padding:15px;margin-bottom:15px;margin-top:15px}.entityArray .array-headline{padding-bottom:10px}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .enabled:hover{cursor:pointer}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.hasMany button{width:100%;height:56px;line-height:24px;font-size:16px}.hasMany .title{text-align:center}.hasMany .elevation-container{border-radius:5px;padding:5px;margin-bottom:15px}.hasMany .mat-column-select{flex:0 0 75px}.hasMany .enabled:hover{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i5$1.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "component", type: i14.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i14.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i14.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i15.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i16.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }, { kind: "component", type: DisplayColumnValueComponent, selector: "display-column-value", inputs: ["entity", "ComponentClass"] }, { kind: "directive", type: i18.MatSort, selector: "[matSort]", inputs: ["matSortDisabled", "matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i18.MatSortHeader, selector: "[mat-sort-header]", inputs: ["disabled", "mat-sort-header", "arrowPosition", "start", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: StringInputComponent, selector: "string-input" }, { kind: "component", type: StringTextboxInputComponent, selector: "string-textbox-input" }, { kind: "component", type: StringAutocompleteInputComponent, selector: "string-autocomplete-input" }, { kind: "component", type: StringDropdownInputComponent, selector: "string-dropdown-input" }, { kind: "component", type: StringPasswordInputComponent, selector: "string-password-input" }, { kind: "component", type: BooleanCheckboxInputComponent, selector: "boolean-checkbox-input" }, { kind: "component", type: BooleanToggleInputComponent, selector: "boolean-toggle-input" }, { kind: "component", type: BooleanDropdownInputComponent, selector: "boolean-dropdown-input" }, { kind: "component", type: NumberInputComponent, selector: "number-input" }, { kind: "component", type: NumberDropdownInputComponent, selector: "number-dropdown-input" }, { kind: "component", type: NumberSliderInputComponent, selector: "number-slider-input" }, { kind: "component", type: ArrayStringChipsInputComponent, selector: "array-string-chips-input" }, { kind: "component", type: ArrayStringAutocompleteChipsComponent, selector: "array-string-autocomplete-chips" }, { kind: "component", type: DateInputComponent, selector: "date-input" }, { kind: "component", type: DateRangeInputComponent, selector: "date-range-input" }, { kind: "component", type: DateTimeInputComponent, selector: "date-time-input" }, { kind: "component", type: ArrayDateInputComponent, selector: "array-date-input" }, { kind: "component", type: ArrayDateTimeInputComponent, selector: "array-date-time-input" }, { kind: "component", type: ArrayDateRangeInputComponent, selector: "array-date-range-input" }, { kind: "component", type: FileImageInputComponent, selector: "file-image-input" }, { kind: "component", type: FileDefaultInputComponent, selector: "file-default-input" }, { kind: "component", type: ReferencesManyInputComponent, selector: "references-many-input" }, { kind: "component", type: CustomInputComponent, selector: "custom-input" }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }] });
4677
4949
  }
4678
4950
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityInputComponent, decorators: [{
4679
4951
  type: Component,
4680
- args: [{ selector: 'ngx-mat-entity-input', template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <string-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <string-textbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-textbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <string-autocomplete-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-autocomplete-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <string-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_PASSWORD\">\n <string-password-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-password-input>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <boolean-checkbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-checkbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <boolean-toggle-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-toggle-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <boolean-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <number-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <number-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_SLIDER\">\n <number-slider-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-slider-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE\">\n <array-date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_TIME\">\n <array-date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-time-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_RANGE\">\n <array-date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <array-string-chips-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-chips-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <array-string-autocomplete-chips\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-autocomplete-chips>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Dates-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.DATE\">\n <date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_RANGE\">\n <date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_TIME\">\n <date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-time-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Files-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.FILE_DEFAULT\">\n <file-default-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-default-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.FILE_IMAGE\">\n <file-image-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-image-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references many ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_MANY\">\n <references-many-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </references-many-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Custom------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.CUSTOM\">\n <custom-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </custom-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n <mat-tab-group *ngIf=\"objectPropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of objectPropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"objectPropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of objectPropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references one ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_ONE\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"internalEntity[internalPropertyKey]\"\n [name]=\"internalPropertyKey.toString() + 'input' + referencesOneUUID\"\n #inputModel=\"ngModel\"\n [disabled]=\"internalIsReadOnly\"\n [required]=\"metadata.required(entity)\"\n (ngModelChange)=\"setReferencesOneObject()\"\n >\n <mat-option *ngIf=\"!metadata.required(entity)\">-</mat-option>\n <mat-option *ngFor=\"let value of referencesOneDropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{internalGetValidationErrorMessage(inputModel)}}</mat-error>\n </mat-form-field>\n <!-- iterates over the references one properties -->\n <mat-tab-group *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of referencesOnePropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of referencesOnePropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8 elevation-container\">\n <div class=\"array-headline\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline && !internalIsReadOnly\">\n <mat-tab-group *ngIf=\"arrayItemInlineTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemInlineTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"arrayItemInlineTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <div class=\"buttons\" *ngIf=\"!internalIsReadOnly\">\n <button type=\"button\" mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !isArrayItemValid\"\n (click)=\"addEntity()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button\n [disabled]=\"!entityArraySelection.selected.length\"\n (click)=\"removeFromEntityArray()\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"entityArrayDataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\" *ngIf=\"!internalIsReadOnly\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n [disabled]=\"!entityArrayDataSource.data.length\" (change)=\"$event ? SelectionUtilities.masterToggle(entityArraySelection, entityArrayDataSource) : null\"\n [checked]=\"entityArraySelection.hasValue() && SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\"\n [indeterminate]=\"entityArraySelection.hasValue() && !SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? entityArraySelection.toggle(entity) : null\" [checked]=\"entityArraySelection.isSelected(entity)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick\" (click)=\"editArrayItem(entity, dCol)\" *matCellDef=\"let entity\">\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"entityArrayDisplayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: entityArrayDisplayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required(entity) && !entityArrayDataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!------------------ has many ---------------->\n <!-------------------------------------------->\n <div class=\"hasMany\" *ngSwitchCase=\"DecoratorTypes.HAS_MANY\">\n <h2 class=\"title\">{{metadataHasMany.tableData.baseData.title}}</h2>\n\n <div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{metadataHasMany.tableData.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyHasManyFilter($event)\">\n </mat-form-field>\n <div\n *ngIf=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-2]=\"hasManyAllowCreate\"\n [class.col-lg-4]=\"!hasManyAllowCreate\"\n [class.col-md-3]=\"hasManyAllowCreate\"\n [class.col-md-6]=\"!hasManyAllowCreate\"\n [class.col-sm-6]=\"hasManyAllowCreate\"\n [class.col-sm-12]=\"!hasManyAllowCreate\"\n >\n <button type=\"button\" class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.tableActionsLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngIf=\"metadataHasMany.tableData.baseData.allowJsonImport\" type=\"button\" [disabled]=\"hasManyTableActionDisabled(hasManyImportAction)\" (click)=\"runHasManyTableAction(hasManyImportAction)\" mat-menu-item>\n {{hasManyImportAction.displayName}}\n </button>\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.baseData.tableActions\" [disabled]=\"hasManyTableActionDisabled(action)\" (click)=\"runHasManyTableAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"hasManyAllowCreate\"\n [class.col-lg-2]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-4]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-3]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-6]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-6]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-12]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n >\n <button type=\"button\" class=\"create-button\" (click)=\"createHasManyEntity()\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.createButtonLabel}}\n </button>\n </div>\n </div>\n\n <div class=\"mat-elevation-z8 elevation-container\">\n <mat-table [dataSource]=\"hasManyDataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? SelectionUtilities.masterToggle(hasManySelection, hasManyDataSource) : null\"\n [checked]=\"hasManySelection.hasValue() && SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\"\n [indeterminate]=\"hasManySelection.hasValue() && !SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\" class=\"enabled\">\n <mat-checkbox (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? hasManySelection.toggle(entity) : null\"\n [checked]=\"hasManySelection.isSelected(entity)\">\n </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of metadataHasMany.tableData.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick && (hasManyAllowUpdate(entity) || hasManyAllowRead(entity))\"\n (click)=\"editHasManyEntity(entity, dCol)\"\n *matCellDef=\"let entity\"\n >\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedHasManyColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedHasManyColumns\"></mat-row>\n </mat-table>\n\n <mat-spinner *ngIf=\"hasManyIsLoading && metadataHasMany.tableData.baseData.displayLoadingSpinner\">\n </mat-spinner>\n\n <mat-paginator [length]=\"hasManyDataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"></mat-paginator>\n </div>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{addArrayItemDialogData.title}}</div>\n </div>\n\n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!isArrayItemValid\">\n {{addArrayItemDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeAddArrayItemDialog()\" class=\"cancel-button\">\n {{addArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Edit Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #editArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{editArrayItemDialogData.title(arrayItemPriorChanges)}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"saveArrayItem()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isArrayItemValid || !isArrayItemDirty\">\n {{editArrayItemDialogData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeEditArrayItemDialog()\" class=\"cancel-button\">\n {{editArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Create Has Many Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #createHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.createDialogData.title}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyCreateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyCreateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyCreateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyCreateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogCreateHasMany()\" mat-raised-button [disabled]=\"!isHasManyEntityValid\">\n {{metadataHasMany.tableData.createDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelCreateHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n \n</ng-template>\n\n<ng-template #editHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.editData.title(hasManyEntityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"metadataHasMany.tableData.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.editData.actions\" [disabled]=\"hasManyEditActionDisabled(action)\" (click)=\"hasManyRunEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"hasManyAllowDelete(hasManyEntity)\" mat-raised-button (click)=\"deleteHasManyEntity()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{metadataHasMany.tableData.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyUpdateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyUpdateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyUpdateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyUpdateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogEditHasMany()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isHasManyEntityValid || !isHasManyEntityDirty\">\n {{metadataHasMany.tableData.editData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelEditHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form> \n</ng-template>", styles: [".mdc-data-table__row:last-child .mdc-data-table__cell{border-bottom:1px solid rgba(0,0,0,.12)}.mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}mat-spinner{margin:10px auto}::ng-deep .mat-mdc-tab-body-wrapper{margin-left:-12px;margin-right:-12px}::ng-deep mat-tab-body{padding-top:10px;padding-left:12px;padding-right:12px}::ng-deep mat-tab-body .mat-mdc-tab-body-content{overflow:initial}::ng-deep .mat-mdc-form-field.mat-form-field-disabled label{color:#0009}::ng-deep .mat-mdc-form-field.mat-form-field-disabled input,::ng-deep .mat-mdc-form-field.mat-form-field-disabled textarea,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-disabled,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-value{color:#000}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled{opacity:1}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled button{opacity:.2}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-date-range-input-inner:disabled{color:#000}::ng-deep .mat-mdc-form-field .mat-mdc-slide-toggle{opacity:1}.entityArray .elevation-container{border-radius:5px;padding:15px;margin-bottom:15px;margin-top:15px}.entityArray .array-headline{padding-bottom:10px}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .enabled:hover{cursor:pointer}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.hasMany button{width:100%;height:56px;line-height:24px;font-size:16px}.hasMany .title{text-align:center}.hasMany .elevation-container{border-radius:5px;padding:5px;margin-bottom:15px}.hasMany .mat-column-select{flex:0 0 75px}.hasMany .enabled:hover{cursor:pointer}\n"] }]
4952
+ args: [{ selector: 'ngx-mat-entity-input', template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <string-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <string-textbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-textbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <string-autocomplete-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-autocomplete-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <string-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_PASSWORD\">\n <string-password-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </string-password-input>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <boolean-checkbox-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-checkbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <boolean-toggle-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-toggle-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <boolean-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </boolean-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <number-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <number-dropdown-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-dropdown-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_SLIDER\">\n <number-slider-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </number-slider-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE\">\n <array-date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_TIME\">\n <array-date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-time-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_RANGE\">\n <array-date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <array-string-chips-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-chips-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <array-string-autocomplete-chips\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </array-string-autocomplete-chips>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Dates-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.DATE\">\n <date-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_RANGE\">\n <date-range-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_TIME\">\n <date-time-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </date-time-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Files-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.FILE_DEFAULT\">\n <file-default-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-default-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.FILE_IMAGE\">\n <file-image-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </file-image-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references many ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_MANY\">\n <references-many-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </references-many-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Custom------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.CUSTOM\">\n <custom-input\n (inputChangeEvent)=\"emitChange()\"\n [entity]=\"internalEntity\"\n [key]=\"internalPropertyKey\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [isReadOnly]=\"internalIsReadOnly\"\n >\n </custom-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n <mat-tab-group *ngIf=\"objectPropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of objectPropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"objectPropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of objectPropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"isPropertyReadOnly(objectProperty, key)\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------- references one ------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.REFERENCES_ONE\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"internalEntity[internalPropertyKey]\"\n [name]=\"internalPropertyKey.toString() + 'input' + referencesOneUUID\"\n #inputModel=\"ngModel\"\n [disabled]=\"internalIsReadOnly\"\n [required]=\"metadata.required(entity)\"\n (ngModelChange)=\"setReferencesOneObject()\"\n >\n <mat-option *ngIf=\"!metadata.required(entity)\">-</mat-option>\n <mat-option *ngFor=\"let value of referencesOneDropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{internalGetValidationErrorMessage(inputModel)}}</mat-error>\n </mat-form-field>\n <!-- iterates over the references one properties -->\n <mat-tab-group *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of referencesOnePropertyTabs; let tI = index; trackBy: trackByFn\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows;\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let rI = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"referencesOnePropertyTabs && referencesOnePropertyTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of referencesOnePropertyTabs[0].rows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"referencesOneObject\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n [validEmpty]=\"!metadata.required(entity)\"\n [isReadOnly]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(referencesOneObject, key, 'lg')}} col-md-{{EntityUtilities.getWidth(referencesOneObject, key, 'md')}} col-sm-{{EntityUtilities.getWidth(referencesOneObject, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8 elevation-container\">\n <div class=\"array-headline\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline && !internalIsReadOnly\">\n <mat-tab-group *ngIf=\"arrayItemInlineTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemInlineTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n\n <div *ngIf=\"arrayItemInlineTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </div>\n\n <div class=\"buttons\" *ngIf=\"!internalIsReadOnly\">\n <button type=\"button\" mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !isArrayItemValid\"\n (click)=\"addEntity()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button\n [disabled]=\"!entityArraySelection.selected.length\"\n (click)=\"removeFromEntityArray()\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"entityArrayDataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\" *ngIf=\"!internalIsReadOnly\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n [disabled]=\"!entityArrayDataSource.data.length\" (change)=\"$event ? SelectionUtilities.masterToggle(entityArraySelection, entityArrayDataSource) : null\"\n [checked]=\"entityArraySelection.hasValue() && SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\"\n [indeterminate]=\"entityArraySelection.hasValue() && !SelectionUtilities.isAllSelected(entityArraySelection, entityArrayDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? entityArraySelection.toggle(entity) : null\" [checked]=\"entityArraySelection.isSelected(entity)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick\" (click)=\"editArrayItem(entity, dCol)\" *matCellDef=\"let entity\">\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"entityArrayDisplayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: entityArrayDisplayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required(entity) && !entityArrayDataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!------------------ has many ---------------->\n <!-------------------------------------------->\n <div class=\"hasMany\" *ngSwitchCase=\"DecoratorTypes.HAS_MANY\">\n <h2 class=\"title\">{{metadataHasMany.tableData.baseData.title}}</h2>\n\n <div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{metadataHasMany.tableData.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyHasManyFilter($event)\">\n </mat-form-field>\n <div\n *ngIf=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-2]=\"hasManyAllowCreate\"\n [class.col-lg-4]=\"!hasManyAllowCreate\"\n [class.col-md-3]=\"hasManyAllowCreate\"\n [class.col-md-6]=\"!hasManyAllowCreate\"\n [class.col-sm-6]=\"hasManyAllowCreate\"\n [class.col-sm-12]=\"!hasManyAllowCreate\"\n >\n <button type=\"button\" class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.tableActionsLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngIf=\"metadataHasMany.tableData.baseData.allowJsonImport\" type=\"button\" [disabled]=\"hasManyTableActionDisabled(hasManyImportAction)\" (click)=\"runHasManyTableAction(hasManyImportAction)\" mat-menu-item>\n {{hasManyImportAction.displayName}}\n </button>\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.baseData.tableActions\" [disabled]=\"hasManyTableActionDisabled(action)\" (click)=\"runHasManyTableAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"hasManyAllowCreate\"\n [class.col-lg-2]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-lg-4]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-3]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-md-6]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-6]=\"metadataHasMany.tableData.baseData.tableActions.length\"\n [class.col-sm-12]=\"!metadataHasMany.tableData.baseData.tableActions.length\"\n >\n <button type=\"button\" class=\"create-button\" (click)=\"createHasManyEntity()\" mat-raised-button>\n {{metadataHasMany.tableData.baseData.createButtonLabel}}\n </button>\n </div>\n </div>\n\n <div class=\"mat-elevation-z8 elevation-container\">\n <mat-table [dataSource]=\"hasManyDataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? SelectionUtilities.masterToggle(hasManySelection, hasManyDataSource) : null\"\n [checked]=\"hasManySelection.hasValue() && SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\"\n [indeterminate]=\"hasManySelection.hasValue() && !SelectionUtilities.isAllSelected(hasManySelection, hasManyDataSource)\">\n </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let entity\" class=\"enabled\">\n <mat-checkbox (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? hasManySelection.toggle(entity) : null\"\n [checked]=\"hasManySelection.isSelected(entity)\">\n </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of metadataHasMany.tableData.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell [class.enabled]=\"!dCol.disableClick && (hasManyAllowUpdate(entity) || hasManyAllowRead(entity))\"\n (click)=\"editHasManyEntity(entity, dCol)\"\n *matCellDef=\"let entity\"\n >\n <ng-container *ngIf=\"dCol.Component\">\n <display-column-value [entity]=\"entity\" [ComponentClass]=\"dCol.Component\"></display-column-value>\n </ng-container>\n <ng-container *ngIf=\"!dCol.Component\">\n {{getDisplayColumnValue(entity, dCol)}}\n </ng-container>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedHasManyColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedHasManyColumns\"></mat-row>\n </mat-table>\n\n <mat-spinner *ngIf=\"hasManyIsLoading && metadataHasMany.tableData.baseData.displayLoadingSpinner\">\n </mat-spinner>\n\n <mat-paginator [length]=\"hasManyDataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"></mat-paginator>\n </div>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{addArrayItemDialogData.title}}</div>\n </div>\n\n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!isArrayItemValid\">\n {{addArrayItemDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeAddArrayItemDialog()\" class=\"cancel-button\">\n {{addArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Edit Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #editArrayItemDialog>\n <div class=\"mat-dialog-title\">\n <div>{{editArrayItemDialogData.title(arrayItemPriorChanges)}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"arrayItemDialogTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of arrayItemDialogTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"arrayItemDialogTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkArrayItem()\"\n [isReadOnly]=\"isPropertyReadOnly(arrayItem, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"saveArrayItem()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isArrayItemValid || !isArrayItemDirty\">\n {{editArrayItemDialogData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"closeEditArrayItemDialog()\" class=\"cancel-button\">\n {{editArrayItemDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n</ng-template>\n\n<!--------------------------------------------------------->\n<!--------------------Create Has Many Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #createHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.createDialogData.title}}</div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyCreateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyCreateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyCreateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyCreateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsHasManyEntityValid('create')\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogCreateHasMany()\" mat-raised-button [disabled]=\"!isHasManyEntityValid\">\n {{metadataHasMany.tableData.createDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelCreateHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form>\n \n</ng-template>\n\n<ng-template #editHasManyDialog>\n <div class=\"mat-dialog-title\">\n <div>{{metadataHasMany.tableData.editData.title(hasManyEntityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"metadataHasMany.tableData.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{metadataHasMany.tableData.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of metadataHasMany.tableData.editData.actions\" [disabled]=\"hasManyEditActionDisabled(action)\" (click)=\"hasManyRunEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"hasManyAllowDelete(hasManyEntity)\" mat-raised-button (click)=\"deleteHasManyEntity()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{metadataHasMany.tableData.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n \n <form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"hasManyUpdateTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of hasManyUpdateTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"hasManyUpdateTabs.length <= 1\">\n <div class=\"row\" *ngFor=\"let row of hasManyUpdateTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"hasManyEntity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(hasManyEntity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(hasManyEntity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(hasManyEntity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkHasManyEntity()\"\n [isReadOnly]=\"isPropertyReadOnly(hasManyEntity, key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"dialogEditHasMany()\" mat-raised-button [disabled]=\"internalIsReadOnly || !isHasManyEntityValid || !isHasManyEntityDirty\">\n {{metadataHasMany.tableData.editData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"dialogCancelEditHasMany()\" class=\"cancel-button\">\n {{metadataHasMany.tableData.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n </form> \n</ng-template>", styles: [".mdc-data-table__row:last-child .mdc-data-table__cell{border-bottom:1px solid rgba(0,0,0,.12)}.mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}mat-spinner{margin:10px auto}::ng-deep .mat-mdc-tab-body-wrapper{margin-left:-12px;margin-right:-12px}::ng-deep mat-tab-body{padding-top:10px;padding-left:12px;padding-right:12px}::ng-deep mat-tab-body .mat-mdc-tab-body-content{overflow:initial}::ng-deep .mat-mdc-form-field.mat-form-field-disabled label{color:#0009}::ng-deep .mat-mdc-form-field.mat-form-field-disabled input,::ng-deep .mat-mdc-form-field.mat-form-field-disabled textarea,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-disabled,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-select-value{color:#000!important}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[disabled]:not(:checked):not(:indeterminate):not([data-indeterminate=true])~.mdc-checkbox__background{border-color:#707070}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[disabled]:checked~.mdc-checkbox__background,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[disabled]:indeterminate~.mdc-checkbox__background,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-checkbox .mdc-checkbox__native-control[data-indeterminate=true][disabled]~.mdc-checkbox__background{background-color:#000}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled{opacity:1}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-mdc-chip.mat-mdc-standard-chip.mat-mdc-chip-disabled button{opacity:.2}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--selected:disabled .mdc-switch__icons,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--unselected:disabled .mdc-switch__icons{opacity:1}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--selected:disabled .mdc-switch__handle:after,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--unselected:disabled .mdc-switch__handle:after{opacity:1;background:black}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--selected:disabled .mdc-switch__track,::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mdc-switch.mdc-switch--unselected:disabled .mdc-switch__track{opacity:.3}::ng-deep .mat-mdc-form-field.mat-form-field-disabled .mat-date-range-input-inner:disabled{color:#000}::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled{opacity:1}::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled .mdc-slider__input{cursor:default}::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled mat-slider-visual-thumb .mat-mdc-slider,::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled mat-slider-visual-thumb .mdc-slider__thumb:hover,::ng-deep #slider.mat-mdc-slider.mdc-slider--disabled mat-slider-visual-thumb .mdc-slider__thumb-knob{background-color:#000;border-color:#000}::ng-deep .mat-mdc-form-field .mat-mdc-slide-toggle{opacity:1}.entityArray .elevation-container{border-radius:5px;padding:15px;margin-bottom:15px;margin-top:15px}.entityArray .array-headline{padding-bottom:10px}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .enabled:hover{cursor:pointer}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.hasMany button{width:100%;height:56px;line-height:24px;font-size:16px}.hasMany .title{text-align:center}.hasMany .elevation-container{border-radius:5px;padding:5px;margin-bottom:15px}.hasMany .mat-column-select{flex:0 0 75px}.hasMany .enabled:hover{cursor:pointer}\n"] }]
4681
4953
  }], ctorParameters: function () { return [{ type: i1.MatDialog }, { type: i0.EnvironmentInjector }, { type: i2$3.Router }, { type: undefined, decorators: [{
4682
4954
  type: Inject,
4683
4955
  args: [NGX_GET_VALIDATION_ERROR_MESSAGE]
@@ -4767,7 +5039,9 @@ class NgxMatEntityInputModule {
4767
5039
  MatProgressSpinnerModule,
4768
5040
  MatPaginatorModule,
4769
5041
  DisplayColumnValueComponent,
4770
- MatSortModule], exports: [NgxMatEntityInputComponent] });
5042
+ MatSortModule,
5043
+ PasswordMatchValidatorDirective,
5044
+ NumberDirective], exports: [NgxMatEntityInputComponent] });
4771
5045
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityInputModule, imports: [CommonModule,
4772
5046
  MatInputModule,
4773
5047
  FormsModule,
@@ -4841,12 +5115,141 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
4841
5115
  MatProgressSpinnerModule,
4842
5116
  MatPaginatorModule,
4843
5117
  DisplayColumnValueComponent,
4844
- MatSortModule
5118
+ MatSortModule,
5119
+ PasswordMatchValidatorDirective,
5120
+ NumberDirective
4845
5121
  ],
4846
5122
  exports: [NgxMatEntityInputComponent]
4847
5123
  }]
4848
5124
  }] });
4849
5125
 
5126
+ /**
5127
+ * A directive that displays a tooltip on hover.
5128
+ */
5129
+ class TooltipDirective {
5130
+ el;
5131
+ renderer;
5132
+ /**
5133
+ * The content to display inside the tooltip.
5134
+ */
5135
+ tooltip;
5136
+ tooltipElement;
5137
+ isTooltipVisible = false;
5138
+ closeListeners = [];
5139
+ constructor(el, renderer) {
5140
+ this.el = el;
5141
+ this.renderer = renderer;
5142
+ }
5143
+ /**
5144
+ * Shows the tooltip.
5145
+ */
5146
+ onMouseEnter() {
5147
+ if (!this.isTooltipVisible) {
5148
+ this.showTooltip();
5149
+ this.registerCloseListeners();
5150
+ }
5151
+ else {
5152
+ this.hideTooltip();
5153
+ this.removeCloseListeners();
5154
+ }
5155
+ }
5156
+ /**
5157
+ * Hides the tooltip.
5158
+ */
5159
+ onMouseLeave() {
5160
+ this.hideTooltip();
5161
+ this.removeCloseListeners();
5162
+ }
5163
+ showTooltip() {
5164
+ if (!this.tooltipElement) {
5165
+ this.tooltipElement = this.renderer.createElement('div');
5166
+ this.tooltipElement.innerHTML = this.tooltip;
5167
+ const rect = this.el.nativeElement.getBoundingClientRect();
5168
+ this.renderer.setStyle(this.tooltipElement, 'z-index', '1000');
5169
+ this.renderer.setStyle(this.tooltipElement, 'position', 'absolute');
5170
+ this.renderer.setStyle(this.tooltipElement, 'padding', '4px 8px 4px 8px');
5171
+ this.renderer.setStyle(this.tooltipElement, 'border-radius', '5px');
5172
+ this.renderer.setStyle(this.tooltipElement, 'background-color', '#616161');
5173
+ this.renderer.setStyle(this.tooltipElement, 'color', 'white');
5174
+ this.renderer.setStyle(this.tooltipElement, 'max-height', '30vh');
5175
+ this.renderer.setStyle(this.tooltipElement, 'overflow', 'scroll');
5176
+ this.renderer.appendChild(document.body, this.tooltipElement);
5177
+ const left = window.scrollX + rect.left - (this.tooltipElement.clientWidth / 2) + 18;
5178
+ this.renderer.setStyle(this.tooltipElement, 'left', `${left}px`);
5179
+ const top = window.scrollY + rect.top - this.tooltipElement.clientHeight - 5;
5180
+ this.renderer.setStyle(this.tooltipElement, 'top', `${top}px`);
5181
+ this.isTooltipVisible = true;
5182
+ }
5183
+ }
5184
+ registerCloseListeners() {
5185
+ setTimeout(() => {
5186
+ this.closeListeners.push(this.getCloseListener('click'), this.getCloseListener('touchmove'), this.getCloseListener('resize'));
5187
+ }, 100);
5188
+ }
5189
+ getCloseListener(event) {
5190
+ return this.renderer.listen('document', event, () => {
5191
+ this.hideTooltip();
5192
+ this.removeCloseListeners();
5193
+ });
5194
+ }
5195
+ hideTooltip() {
5196
+ if (this.tooltipElement) {
5197
+ this.renderer.removeChild(this.el.nativeElement, this.tooltipElement);
5198
+ this.tooltipElement = undefined;
5199
+ this.isTooltipVisible = false;
5200
+ }
5201
+ }
5202
+ removeCloseListeners() {
5203
+ for (const listener of this.closeListeners) {
5204
+ listener();
5205
+ }
5206
+ this.closeListeners = [];
5207
+ }
5208
+ ngOnDestroy() {
5209
+ this.removeCloseListeners();
5210
+ }
5211
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: TooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
5212
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.0", type: TooltipDirective, isStandalone: true, selector: "[tooltip]", inputs: { tooltip: "tooltip" }, host: { listeners: { "mouseenter": "onMouseEnter()", "click": "onMouseEnter()", "mouseleave": "onMouseLeave()", "window:resize": "onMouseLeave()" } }, ngImport: i0 });
5213
+ }
5214
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: TooltipDirective, decorators: [{
5215
+ type: Directive,
5216
+ args: [{
5217
+ selector: '[tooltip]',
5218
+ standalone: true
5219
+ }]
5220
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { tooltip: [{
5221
+ type: Input
5222
+ }], onMouseEnter: [{
5223
+ type: HostListener,
5224
+ args: ['mouseenter']
5225
+ }, {
5226
+ type: HostListener,
5227
+ args: ['click']
5228
+ }], onMouseLeave: [{
5229
+ type: HostListener,
5230
+ args: ['mouseleave']
5231
+ }, {
5232
+ type: HostListener,
5233
+ args: ['window:resize']
5234
+ }] } });
5235
+
5236
+ /**
5237
+ * A component that displays an info-symbol and a tooltip when it is hovered/clicked.
5238
+ */
5239
+ class TooltipComponent {
5240
+ tooltipContent;
5241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: TooltipComponent, isStandalone: true, selector: "ngx-mat-entity-tooltip", inputs: { tooltipContent: "tooltipContent" }, ngImport: i0, template: "<div [tooltip]=\"tooltipContent\" class=\"info\">\n <i class=\"fas fa-info\"></i>\n</div>", styles: [".info{display:flex;align-items:center;justify-content:center;height:25px;min-height:25px;width:25px;min-width:25px;border:2px solid black;border-radius:50%}.info:hover{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: TooltipDirective, selector: "[tooltip]", inputs: ["tooltip"] }] });
5243
+ }
5244
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: TooltipComponent, decorators: [{
5245
+ type: Component,
5246
+ args: [{ selector: 'ngx-mat-entity-tooltip', standalone: true, imports: [
5247
+ TooltipDirective
5248
+ ], template: "<div [tooltip]=\"tooltipContent\" class=\"info\">\n <i class=\"fas fa-info\"></i>\n</div>", styles: [".info{display:flex;align-items:center;justify-content:center;height:25px;min-height:25px;width:25px;min-width:25px;border:2px solid black;border-radius:50%}.info:hover{cursor:pointer}\n"] }]
5249
+ }], propDecorators: { tooltipContent: [{
5250
+ type: Input
5251
+ }] } });
5252
+
4850
5253
  // eslint-disable-next-line jsdoc/require-jsdoc
4851
5254
  class PageEditDataBuilder extends BaseBuilder {
4852
5255
  constructor(data) {
@@ -4904,13 +5307,17 @@ class NgxMatEntityEditPageComponent {
4904
5307
  EntityClass;
4905
5308
  inputData;
4906
5309
  http;
5310
+ el;
5311
+ renderer;
4907
5312
  EntityUtilities = EntityUtilities;
4908
5313
  entityTabs;
4909
5314
  entity;
4910
5315
  entityPriorChanges;
4911
5316
  data;
5317
+ validationErrors = [];
4912
5318
  isEntityValid = true;
4913
5319
  isEntityDirty = false;
5320
+ tooltipContent = '';
4914
5321
  isEntityReadOnly;
4915
5322
  allowDelete;
4916
5323
  inConfirmNavigation = false;
@@ -4918,7 +5325,7 @@ class NgxMatEntityEditPageComponent {
4918
5325
  get hasUnsavedChanges() {
4919
5326
  return this.isEntityDirty && this.data.editData.unsavedChangesRequireConfirmDialog;
4920
5327
  }
4921
- constructor(dialog, location, route, injector, entityService, EntityClass, inputData, http) {
5328
+ constructor(dialog, location, route, injector, entityService, EntityClass, inputData, http, el, renderer) {
4922
5329
  this.dialog = dialog;
4923
5330
  this.location = location;
4924
5331
  this.route = route;
@@ -4927,6 +5334,8 @@ class NgxMatEntityEditPageComponent {
4927
5334
  this.EntityClass = EntityClass;
4928
5335
  this.inputData = inputData;
4929
5336
  this.http = http;
5337
+ this.el = el;
5338
+ this.renderer = renderer;
4930
5339
  }
4931
5340
  /**
4932
5341
  * Checks if the input with the given key is readonly.
@@ -4935,7 +5344,7 @@ class NgxMatEntityEditPageComponent {
4935
5344
  * @returns Whether or not the input for the key is read only.
4936
5345
  */
4937
5346
  isReadOnly(key) {
4938
- return this.injector.runInContext(() => {
5347
+ return runInInjectionContext(this.injector, () => {
4939
5348
  const metadata = EntityUtilities.getPropertyMetadata(this.entity, key);
4940
5349
  return this.isEntityReadOnly || metadata.isReadOnly(this.entity);
4941
5350
  });
@@ -4954,11 +5363,34 @@ class NgxMatEntityEditPageComponent {
4954
5363
  }
4955
5364
  this.entity = new this.EntityClass(foundEntity);
4956
5365
  this.entityPriorChanges = LodashUtilities.cloneDeep(this.entity);
4957
- this.injector.runInContext(() => {
5366
+ runInInjectionContext(this.injector, () => {
4958
5367
  this.isEntityReadOnly = !this.data.allowUpdate(this.entityPriorChanges);
4959
5368
  this.allowDelete = this.data.allowDelete(this.entityPriorChanges);
4960
5369
  });
4961
5370
  this.entityTabs = EntityUtilities.getEntityTabs(this.entity, false, true);
5371
+ setTimeout(() => this.checkOffset(), 1);
5372
+ setTimeout(() => this.checkIsEntityValid(), 1);
5373
+ }
5374
+ /**
5375
+ * Checks if the bottom row should be displayed as fixed.
5376
+ */
5377
+ onScroll() {
5378
+ this.checkOffset();
5379
+ }
5380
+ checkOffset() {
5381
+ const scrollY = window.scrollY;
5382
+ const bottomRow = this.el.nativeElement.querySelector('.bottom-row');
5383
+ const bottomRowContainer = this.el.nativeElement.querySelector('.bottom-row-container');
5384
+ if (bottomRow && bottomRowContainer) {
5385
+ const bottomRowContainerOffset = bottomRowContainer.offsetTop;
5386
+ const windowHeight = window.innerHeight;
5387
+ if (scrollY + windowHeight >= bottomRowContainerOffset) {
5388
+ this.renderer.removeClass(bottomRow, 'fixed');
5389
+ }
5390
+ else {
5391
+ this.renderer.addClass(bottomRow, 'fixed');
5392
+ }
5393
+ }
4962
5394
  }
4963
5395
  /**
4964
5396
  * Whether the page can be left without confirmation (of unsaved changes).
@@ -4972,9 +5404,14 @@ class NgxMatEntityEditPageComponent {
4972
5404
  * Checks if the entity has become invalid or dirty.
4973
5405
  */
4974
5406
  async checkEntity() {
4975
- this.isEntityValid = EntityUtilities.isEntityValid(this.entity, 'update');
5407
+ this.checkIsEntityValid();
4976
5408
  this.isEntityDirty = await EntityUtilities.isDirty(this.entity, this.entityPriorChanges, this.http);
4977
5409
  }
5410
+ checkIsEntityValid() {
5411
+ this.validationErrors = ValidationUtilities.getEntityValidationErrors(this.entity, 'update');
5412
+ this.tooltipContent = runInInjectionContext(this.injector, () => getValidationErrorsTooltipContent(this.validationErrors));
5413
+ this.isEntityValid = this.validationErrors.length === 0;
5414
+ }
4978
5415
  /**
4979
5416
  * Tries to save the changes and close the dialog afterwards.
4980
5417
  * Also handles the confirmation if required.
@@ -5111,8 +5548,8 @@ class NgxMatEntityEditPageComponent {
5111
5548
  return !action.enabled(this.entityPriorChanges);
5112
5549
  });
5113
5550
  }
5114
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityEditPageComponent, deps: [{ token: i1.MatDialog }, { token: i1$1.Location }, { token: i2$3.ActivatedRoute }, { token: i0.EnvironmentInjector }, { token: NGX_EDIT_DATA_ENTITY_SERVICE }, { token: NGX_EDIT_DATA_ENTITY }, { token: NGX_EDIT_DATA }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
5115
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityEditPageComponent, isStandalone: true, selector: "ngx-mat-entity-edit-page", host: { listeners: { "window:beforeunload": "canDeactivate()" } }, ngImport: i0, template: "<div *ngIf=\"!entityTabs && data.displayLoadingSpinner\" class=\"container\">\n <br>\n <mat-spinner></mat-spinner>\n <br>\n</div>\n\n<div *ngIf=\"entityTabs\" class=\"container\">\n <br>\n\n <!------------>\n <!-- Header -->\n <!------------>\n <div class=\"header\">\n <div class=\"save-cancel-container\">\n <button type=\"button\" [class.unsavedChanges]=\"hasUnsavedChanges\" mat-raised-button (click)=\"navigateBack()\" class=\"back-button\" tabindex=\"-1\">\n <i class=\"fas fa-chevron-left\"></i>\n {{data.editData.cancelButtonLabel}}\n <i class=\"fas fa-warning\" *ngIf=\"hasUnsavedChanges\"></i>\n </button>\n <button type=\"button\" class=\"save-button\" (click)=\"edit()\" mat-raised-button [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\">\n {{data.editData.confirmButtonLabel}}\n </button>\n </div>\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n\n <h1>{{data.editData.title(entityPriorChanges)}}</h1>\n\n <!----------->\n <!-- Input -->\n <!----------->\n <form>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\">\n {{data.editData.confirmButtonLabel}}\n </button>\n </form>\n\n <br>\n</div>", styles: ["h1{text-align:center}mat-spinner{margin:10px auto}.fa-warning{color:orange}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}.header{display:flex;margin-bottom:5px;gap:10px;flex-wrap:wrap}.header button{min-width:150px}.header .save-cancel-container{display:flex;justify-content:flex-start;column-gap:10px;width:calc(50% - 10px)}.header .actions-container{display:flex;justify-content:flex-end;gap:10px;width:calc(50% - 10px)}.unsavedChanges{background-color:#ffe48d}@media (max-width: 800px){.header{margin-bottom:10px;gap:15px}.header button{min-width:0px;width:50%}.header .save-cancel-container,.header .actions-container{width:100%;gap:15px}}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: NgxMatEntityInputModule }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i15.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i14.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i14.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i14.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }] });
5551
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityEditPageComponent, deps: [{ token: i1.MatDialog }, { token: i1$1.Location }, { token: i2$3.ActivatedRoute }, { token: i0.EnvironmentInjector }, { token: NGX_EDIT_DATA_ENTITY_SERVICE }, { token: NGX_EDIT_DATA_ENTITY }, { token: NGX_EDIT_DATA }, { token: i2.HttpClient }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
5552
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityEditPageComponent, isStandalone: true, selector: "ngx-mat-entity-edit-page", host: { listeners: { "window:scroll": "onScroll()", "window:beforeunload": "canDeactivate()" } }, ngImport: i0, template: "<div *ngIf=\"!entityTabs && data.displayLoadingSpinner\" class=\"container\">\n <br>\n <mat-spinner></mat-spinner>\n <br>\n</div>\n\n<div *ngIf=\"entityTabs\" class=\"container\">\n <br>\n\n <!------------>\n <!-- Header -->\n <!------------>\n <div class=\"header\">\n <div class=\"save-cancel-container\">\n <button type=\"button\" [class.unsavedChanges]=\"hasUnsavedChanges\" mat-raised-button (click)=\"navigateBack()\" class=\"back-button\" tabindex=\"-1\">\n <i class=\"fas fa-chevron-left\"></i>\n {{data.editData.cancelButtonLabel}}\n <i class=\"fas fa-warning\" *ngIf=\"hasUnsavedChanges\"></i>\n </button>\n </div>\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n\n <h1>{{data.editData.title(entityPriorChanges)}}</h1>\n\n <!----------->\n <!-- Input -->\n <!----------->\n <form>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <div class=\"bottom-row-container\">\n <div class=\"bottom-row container\" style=\"margin-top: 10px;\">\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button\n [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\"\n [matBadge]=\"validationErrors.length\"\n [matBadgeHidden]=\"!validationErrors.length\"\n matBadgeColor=\"warn\"\n >\n {{data.editData.confirmButtonLabel}}\n </button>\n <ngx-mat-entity-tooltip *ngIf=\"validationErrors.length\" [tooltipContent]=\"tooltipContent\"></ngx-mat-entity-tooltip>\n </div>\n </div>\n </form>\n\n <br>\n</div>", styles: ["h1{text-align:center}mat-spinner{margin:10px auto}.fa-warning{color:orange}.bottom-row{display:flex;align-items:center;column-gap:10px}.fixed{position:fixed;bottom:0;left:0;right:0;width:100%;z-index:1000;padding:8px 20px;background-color:#fff}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}.header{display:flex;margin-bottom:5px;gap:10px;flex-wrap:wrap}.header button{min-width:150px}.header .save-cancel-container{display:flex;justify-content:flex-start;align-items:center;column-gap:10px;width:calc(50% - 10px)}.header .actions-container{display:flex;justify-content:flex-end;gap:10px;width:calc(50% - 10px)}.unsavedChanges{background-color:#ffe48d}@media (max-width: 800px){.header{margin-bottom:10px;gap:15px}.header button{min-width:0px;width:50%}.header .save-cancel-container,.header .actions-container{width:100%;gap:15px}}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: NgxMatEntityInputModule }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i15.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i14.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i14.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i14.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i10.MatBadge, selector: "[matBadge]", inputs: ["matBadgeDisabled", "matBadgeColor", "matBadgeOverlap", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: TooltipComponent, selector: "ngx-mat-entity-tooltip", inputs: ["tooltipContent"] }] });
5116
5553
  }
5117
5554
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityEditPageComponent, decorators: [{
5118
5555
  type: Component,
@@ -5123,8 +5560,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
5123
5560
  MatTabsModule,
5124
5561
  NgxMatEntityInputModule,
5125
5562
  MatProgressSpinnerModule,
5126
- MatMenuModule
5127
- ], template: "<div *ngIf=\"!entityTabs && data.displayLoadingSpinner\" class=\"container\">\n <br>\n <mat-spinner></mat-spinner>\n <br>\n</div>\n\n<div *ngIf=\"entityTabs\" class=\"container\">\n <br>\n\n <!------------>\n <!-- Header -->\n <!------------>\n <div class=\"header\">\n <div class=\"save-cancel-container\">\n <button type=\"button\" [class.unsavedChanges]=\"hasUnsavedChanges\" mat-raised-button (click)=\"navigateBack()\" class=\"back-button\" tabindex=\"-1\">\n <i class=\"fas fa-chevron-left\"></i>\n {{data.editData.cancelButtonLabel}}\n <i class=\"fas fa-warning\" *ngIf=\"hasUnsavedChanges\"></i>\n </button>\n <button type=\"button\" class=\"save-button\" (click)=\"edit()\" mat-raised-button [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\">\n {{data.editData.confirmButtonLabel}}\n </button>\n </div>\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n\n <h1>{{data.editData.title(entityPriorChanges)}}</h1>\n\n <!----------->\n <!-- Input -->\n <!----------->\n <form>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\">\n {{data.editData.confirmButtonLabel}}\n </button>\n </form>\n\n <br>\n</div>", styles: ["h1{text-align:center}mat-spinner{margin:10px auto}.fa-warning{color:orange}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}.header{display:flex;margin-bottom:5px;gap:10px;flex-wrap:wrap}.header button{min-width:150px}.header .save-cancel-container{display:flex;justify-content:flex-start;column-gap:10px;width:calc(50% - 10px)}.header .actions-container{display:flex;justify-content:flex-end;gap:10px;width:calc(50% - 10px)}.unsavedChanges{background-color:#ffe48d}@media (max-width: 800px){.header{margin-bottom:10px;gap:15px}.header button{min-width:0px;width:50%}.header .save-cancel-container,.header .actions-container{width:100%;gap:15px}}\n"] }]
5563
+ MatMenuModule,
5564
+ MatBadgeModule,
5565
+ TooltipComponent
5566
+ ], template: "<div *ngIf=\"!entityTabs && data.displayLoadingSpinner\" class=\"container\">\n <br>\n <mat-spinner></mat-spinner>\n <br>\n</div>\n\n<div *ngIf=\"entityTabs\" class=\"container\">\n <br>\n\n <!------------>\n <!-- Header -->\n <!------------>\n <div class=\"header\">\n <div class=\"save-cancel-container\">\n <button type=\"button\" [class.unsavedChanges]=\"hasUnsavedChanges\" mat-raised-button (click)=\"navigateBack()\" class=\"back-button\" tabindex=\"-1\">\n <i class=\"fas fa-chevron-left\"></i>\n {{data.editData.cancelButtonLabel}}\n <i class=\"fas fa-warning\" *ngIf=\"hasUnsavedChanges\"></i>\n </button>\n </div>\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n </div>\n\n <h1>{{data.editData.title(entityPriorChanges)}}</h1>\n\n <!----------->\n <!-- Input -->\n <!----------->\n <form>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <div class=\"bottom-row-container\">\n <div class=\"bottom-row container\" style=\"margin-top: 10px;\">\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button\n [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\"\n [matBadge]=\"validationErrors.length\"\n [matBadgeHidden]=\"!validationErrors.length\"\n matBadgeColor=\"warn\"\n >\n {{data.editData.confirmButtonLabel}}\n </button>\n <ngx-mat-entity-tooltip *ngIf=\"validationErrors.length\" [tooltipContent]=\"tooltipContent\"></ngx-mat-entity-tooltip>\n </div>\n </div>\n </form>\n\n <br>\n</div>", styles: ["h1{text-align:center}mat-spinner{margin:10px auto}.fa-warning{color:orange}.bottom-row{display:flex;align-items:center;column-gap:10px}.fixed{position:fixed;bottom:0;left:0;right:0;width:100%;z-index:1000;padding:8px 20px;background-color:#fff}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}.header{display:flex;margin-bottom:5px;gap:10px;flex-wrap:wrap}.header button{min-width:150px}.header .save-cancel-container{display:flex;justify-content:flex-start;align-items:center;column-gap:10px;width:calc(50% - 10px)}.header .actions-container{display:flex;justify-content:flex-end;gap:10px;width:calc(50% - 10px)}.unsavedChanges{background-color:#ffe48d}@media (max-width: 800px){.header{margin-bottom:10px;gap:15px}.header button{min-width:0px;width:50%}.header .save-cancel-container,.header .actions-container{width:100%;gap:15px}}\n"] }]
5128
5567
  }], ctorParameters: function () { return [{ type: i1.MatDialog }, { type: i1$1.Location }, { type: i2$3.ActivatedRoute }, { type: i0.EnvironmentInjector }, { type: EntityService, decorators: [{
5129
5568
  type: Inject,
5130
5569
  args: [NGX_EDIT_DATA_ENTITY_SERVICE]
@@ -5134,7 +5573,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
5134
5573
  }] }, { type: undefined, decorators: [{
5135
5574
  type: Inject,
5136
5575
  args: [NGX_EDIT_DATA]
5137
- }] }, { type: i2.HttpClient }]; }, propDecorators: { canDeactivate: [{
5576
+ }] }, { type: i2.HttpClient }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { onScroll: [{
5577
+ type: HostListener,
5578
+ args: ['window:scroll']
5579
+ }], canDeactivate: [{
5138
5580
  type: HostListener,
5139
5581
  args: ['window:beforeunload']
5140
5582
  }] } });
@@ -5193,6 +5635,8 @@ class NgxMatEntityCreateDialogComponent {
5193
5635
  entityService;
5194
5636
  data;
5195
5637
  isEntityValid = false;
5638
+ validationErrors = [];
5639
+ tooltipContent = '';
5196
5640
  constructor(inputData, dialogRef, injector, dialog) {
5197
5641
  this.inputData = inputData;
5198
5642
  this.dialogRef = dialogRef;
@@ -5204,12 +5648,15 @@ class NgxMatEntityCreateDialogComponent {
5204
5648
  this.dialogRef.disableClose = true;
5205
5649
  this.entityTabs = EntityUtilities.getEntityTabs(this.data.entity, true);
5206
5650
  this.entityService = this.injector.get(this.data.EntityServiceClass);
5651
+ setTimeout(() => this.checkIsEntityValid(), 1);
5207
5652
  }
5208
5653
  /**
5209
5654
  * Checks if the entity is valid.
5210
5655
  */
5211
5656
  checkIsEntityValid() {
5212
- this.isEntityValid = EntityUtilities.isEntityValid(this.data.entity, 'create');
5657
+ this.validationErrors = ValidationUtilities.getEntityValidationErrors(this.data.entity, 'create');
5658
+ this.tooltipContent = runInInjectionContext(this.injector, () => getValidationErrorsTooltipContent(this.validationErrors));
5659
+ this.isEntityValid = this.validationErrors.length === 0;
5213
5660
  }
5214
5661
  /**
5215
5662
  * Tries add the new entity and close the dialog afterwards.
@@ -5249,7 +5696,7 @@ class NgxMatEntityCreateDialogComponent {
5249
5696
  this.dialogRef.close();
5250
5697
  }
5251
5698
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityCreateDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }, { token: i0.Injector }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
5252
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityCreateDialogComponent, isStandalone: true, selector: "ngx-mat-entity-create-dialog", ngImport: i0, template: "<div class=\"mat-dialog-title\">\n <div>{{data.createDialogData.title}}</div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"create()\" mat-raised-button [disabled]=\"!isEntityValid\">\n {{data.createDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"], dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: NgxMatEntityInputModule }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }] });
5699
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityCreateDialogComponent, isStandalone: true, selector: "ngx-mat-entity-create-dialog", ngImport: i0, template: "<div class=\"mat-dialog-title\">\n <div>{{data.createDialogData.title}}</div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n\n <div class=\"d-flex align-items-center gap-3\" style=\"margin-top: 10px;\">\n <button type=\"submit\" (click)=\"create()\" mat-raised-button\n [disabled]=\"!isEntityValid\"\n [matBadge]=\"validationErrors.length\"\n [matBadgeHidden]=\"!validationErrors.length\"\n matBadgeColor=\"warn\"\n >\n {{data.createDialogData.createButtonLabel}}\n </button>\n <ngx-mat-entity-tooltip *ngIf=\"validationErrors.length\" [tooltipContent]=\"tooltipContent\"></ngx-mat-entity-tooltip>\n </div>\n\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"], dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: NgxMatEntityInputModule }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i10.MatBadge, selector: "[matBadge]", inputs: ["matBadgeDisabled", "matBadgeColor", "matBadgeOverlap", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: TooltipComponent, selector: "ngx-mat-entity-tooltip", inputs: ["tooltipContent"] }] });
5253
5700
  }
5254
5701
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityCreateDialogComponent, decorators: [{
5255
5702
  type: Component,
@@ -5260,8 +5707,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
5260
5707
  MatDialogModule,
5261
5708
  FormsModule,
5262
5709
  MatButtonModule,
5263
- MatTabsModule
5264
- ], template: "<div class=\"mat-dialog-title\">\n <div>{{data.createDialogData.title}}</div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"create()\" mat-raised-button [disabled]=\"!isEntityValid\">\n {{data.createDialogData.createButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"] }]
5710
+ MatTabsModule,
5711
+ MatBadgeModule,
5712
+ TooltipComponent
5713
+ ], template: "<div class=\"mat-dialog-title\">\n <div>{{data.createDialogData.title}}</div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0]?.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n\n <div class=\"d-flex align-items-center gap-3\" style=\"margin-top: 10px;\">\n <button type=\"submit\" (click)=\"create()\" mat-raised-button\n [disabled]=\"!isEntityValid\"\n [matBadge]=\"validationErrors.length\"\n [matBadgeHidden]=\"!validationErrors.length\"\n matBadgeColor=\"warn\"\n >\n {{data.createDialogData.createButtonLabel}}\n </button>\n <ngx-mat-entity-tooltip *ngIf=\"validationErrors.length\" [tooltipContent]=\"tooltipContent\"></ngx-mat-entity-tooltip>\n </div>\n\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"] }]
5265
5714
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
5266
5715
  type: Inject,
5267
5716
  args: [MAT_DIALOG_DATA]
@@ -5446,6 +5895,8 @@ class NgxMatEntityEditDialogComponent {
5446
5895
  data;
5447
5896
  isEntityValid = true;
5448
5897
  isEntityDirty = false;
5898
+ validationErrors = [];
5899
+ tooltipContent = '';
5449
5900
  isEntityReadOnly;
5450
5901
  allowDelete;
5451
5902
  constructor(inputData, dialogRef, injector, dialog, http) {
@@ -5458,13 +5909,14 @@ class NgxMatEntityEditDialogComponent {
5458
5909
  ngOnInit() {
5459
5910
  this.data = new EditEntityDataBuilder(this.inputData).getResult();
5460
5911
  this.entityPriorChanges = LodashUtilities.cloneDeep(this.data.entity);
5461
- this.injector.runInContext(() => {
5912
+ runInInjectionContext(this.injector, () => {
5462
5913
  this.isEntityReadOnly = !this.data.allowUpdate(this.entityPriorChanges);
5463
5914
  this.allowDelete = this.data.allowDelete(this.entityPriorChanges);
5464
5915
  });
5465
5916
  this.dialogRef.disableClose = true;
5466
5917
  this.entityTabs = EntityUtilities.getEntityTabs(this.data.entity, false, true);
5467
5918
  this.entityService = this.injector.get(this.data.EntityServiceClass);
5919
+ setTimeout(() => this.checkIsEntityValid(), 1);
5468
5920
  }
5469
5921
  /**
5470
5922
  * Checks if the input with the given key is readonly.
@@ -5473,7 +5925,7 @@ class NgxMatEntityEditDialogComponent {
5473
5925
  * @returns Whether or not the input for the key is read only.
5474
5926
  */
5475
5927
  isReadOnly(key) {
5476
- return this.injector.runInContext(() => {
5928
+ return runInInjectionContext(this.injector, () => {
5477
5929
  const metadata = EntityUtilities.getPropertyMetadata(this.data.entity, key);
5478
5930
  return this.isEntityReadOnly || metadata.isReadOnly(this.data.entity);
5479
5931
  });
@@ -5482,9 +5934,14 @@ class NgxMatEntityEditDialogComponent {
5482
5934
  * Checks if the entity has become invalid or dirty.
5483
5935
  */
5484
5936
  async checkEntity() {
5485
- this.isEntityValid = EntityUtilities.isEntityValid(this.data.entity, 'update');
5937
+ this.checkIsEntityValid();
5486
5938
  this.isEntityDirty = await EntityUtilities.isDirty(this.data.entity, this.entityPriorChanges, this.http);
5487
5939
  }
5940
+ checkIsEntityValid() {
5941
+ this.validationErrors = ValidationUtilities.getEntityValidationErrors(this.data.entity, 'update');
5942
+ this.tooltipContent = runInInjectionContext(this.injector, () => getValidationErrorsTooltipContent(this.validationErrors));
5943
+ this.isEntityValid = this.validationErrors.length === 0;
5944
+ }
5488
5945
  /**
5489
5946
  * Tries to save the changes and close the dialog afterwards.
5490
5947
  * Also handles the confirmation if required.
@@ -5558,7 +6015,7 @@ class NgxMatEntityEditDialogComponent {
5558
6015
  * @param action - The action to run.
5559
6016
  */
5560
6017
  runEditAction(action) {
5561
- const requireConfirmDialog = this.injector.runInContext(() => {
6018
+ const requireConfirmDialog = runInInjectionContext(this.injector, () => {
5562
6019
  return action.requireConfirmDialog(this.entityPriorChanges);
5563
6020
  });
5564
6021
  if (!requireConfirmDialog) {
@@ -5577,7 +6034,7 @@ class NgxMatEntityEditDialogComponent {
5577
6034
  });
5578
6035
  }
5579
6036
  confirmRunEditAction(action) {
5580
- void this.injector.runInContext(async () => {
6037
+ void runInInjectionContext(this.injector, async () => {
5581
6038
  await action.action(this.data.entity, this.entityPriorChanges);
5582
6039
  await this.checkEntity();
5583
6040
  });
@@ -5589,12 +6046,10 @@ class NgxMatEntityEditDialogComponent {
5589
6046
  * @returns Whether or not the Action can be used.
5590
6047
  */
5591
6048
  editActionDisabled(action) {
5592
- return this.injector.runInContext(() => {
5593
- return !action.enabled(this.entityPriorChanges);
5594
- });
6049
+ return runInInjectionContext(this.injector, () => !action.enabled(this.entityPriorChanges));
5595
6050
  }
5596
6051
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityEditDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }, { token: i0.EnvironmentInjector }, { token: i1.MatDialog }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
5597
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityEditDialogComponent, isStandalone: true, selector: "ngx-mat-entity-edit-dialog", ngImport: i0, template: "<div class=\"mat-dialog-title\">\n <div>{{data.editData.title(entityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\">\n {{data.editData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.actions-container{display:flex;gap:10px}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: NgxMatEntityInputModule }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i14.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i14.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i14.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }] });
6052
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.0", type: NgxMatEntityEditDialogComponent, isStandalone: true, selector: "ngx-mat-entity-edit-dialog", ngImport: i0, template: "<div class=\"mat-dialog-title\">\n <div>{{data.editData.title(entityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <div class=\"d-flex align-items-center gap-3\" style=\"margin-top: 10px;\">\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button\n [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\"\n [matBadge]=\"validationErrors.length\"\n [matBadgeHidden]=\"!validationErrors.length\"\n matBadgeColor=\"warn\"\n >\n {{data.editData.confirmButtonLabel}}\n </button>\n <ngx-mat-entity-tooltip *ngIf=\"validationErrors.length\" [tooltipContent]=\"tooltipContent\"></ngx-mat-entity-tooltip>\n </div>\n\n\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.actions-container{display:flex;gap:10px}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: NgxMatEntityInputModule }, { kind: "component", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit", "validEmpty", "isReadOnly"], outputs: ["inputChangeEvent"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$2.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i14.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i14.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i14.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i10.MatBadge, selector: "[matBadge]", inputs: ["matBadgeDisabled", "matBadgeColor", "matBadgeOverlap", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: TooltipComponent, selector: "ngx-mat-entity-tooltip", inputs: ["tooltipContent"] }] });
5598
6053
  }
5599
6054
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImport: i0, type: NgxMatEntityEditDialogComponent, decorators: [{
5600
6055
  type: Component,
@@ -5607,8 +6062,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.0", ngImpor
5607
6062
  MatButtonModule,
5608
6063
  MatTabsModule,
5609
6064
  NgxMatEntityConfirmDialogComponent,
5610
- MatMenuModule
5611
- ], template: "<div class=\"mat-dialog-title\">\n <div>{{data.editData.title(entityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\">\n {{data.editData.confirmButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.actions-container{display:flex;gap:10px}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"] }]
6065
+ MatMenuModule,
6066
+ MatBadgeModule,
6067
+ TooltipComponent
6068
+ ], template: "<div class=\"mat-dialog-title\">\n <div>{{data.editData.title(entityPriorChanges)}}</div>\n\n <div class=\"actions-container\">\n <button *ngIf=\"data.editData.actions.length\" type=\"button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.editData.actionsLabel}}\n </button>\n <mat-menu #menu=\"matMenu\">\n <button type=\"button\" *ngFor=\"let action of data.editData.actions\" [disabled]=\"editActionDisabled(action)\" (click)=\"runEditAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n \n <button type=\"button\" *ngIf=\"allowDelete\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editData.deleteButtonLabel}}\n </button>\n </div>\n</div>\n\n<form>\n <mat-dialog-content>\n <mat-tab-group *ngIf=\"entityTabs.length > 1\" preserveContent>\n <mat-tab *ngFor=\"let tab of entityTabs\" [label]=\"tab.tabName\">\n <div class=\"row\" *ngFor=\"let row of tab.rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </mat-tab>\n </mat-tab-group>\n \n <div *ngIf=\"entityTabs.length <= 1\">\n <span class=\"no-entity-tabs\" *ngIf=\"!entityTabs.length\">\n ERROR: No Inputs. Did you correctly assign all values in the model constructor?\n </span>\n <div class=\"row\" *ngFor=\"let row of entityTabs[0].rows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n [isReadOnly]=\"isReadOnly(key)\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n </mat-dialog-content>\n \n <mat-dialog-actions>\n <div class=\"d-flex align-items-center gap-3\" style=\"margin-top: 10px;\">\n <button type=\"submit\" (click)=\"edit()\" mat-raised-button\n [disabled]=\"isEntityReadOnly || !isEntityValid || !isEntityDirty\"\n [matBadge]=\"validationErrors.length\"\n [matBadgeHidden]=\"!validationErrors.length\"\n matBadgeColor=\"warn\"\n >\n {{data.editData.confirmButtonLabel}}\n </button>\n <ngx-mat-entity-tooltip *ngIf=\"validationErrors.length\" [tooltipContent]=\"tooltipContent\"></ngx-mat-entity-tooltip>\n </div>\n\n\n <button type=\"button\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n</form>\n", styles: [".mat-dialog-title{padding:12px 20px;display:flex;justify-content:space-between;align-items:center}.mat-dialog-title div{font-size:var(--mdc-dialog-subhead-size, 14px);font-weight:var(--mdc-dialog-subhead-weight, 500)}.actions-container{display:flex;gap:10px}.no-entity-tabs{padding:10px;background-color:red;color:#f5f5f5}::ng-deep .mdc-dialog .mdc-dialog__content{padding:6px 20px!important}mat-dialog-actions{justify-content:space-between;align-items:center;padding-left:20px;padding-right:20px}\n"] }]
5612
6069
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
5613
6070
  type: Inject,
5614
6071
  args: [MAT_DIALOG_DATA]
@@ -5793,7 +6250,7 @@ class NgxMatEntityTableComponent {
5793
6250
  const dialogData = new EditEntityDataBuilder(inputDialogData).getResult();
5794
6251
  const res = await firstValueFrom(this.dialog.open(NgxMatEntityEditDialogComponent, {
5795
6252
  data: dialogData,
5796
- minWidth: '60%',
6253
+ // minWidth: '60%',
5797
6254
  autoFocus: false,
5798
6255
  restoreFocus: false
5799
6256
  }).afterClosed());
@@ -5815,11 +6272,13 @@ class NgxMatEntityTableComponent {
5815
6272
  if (!this.data.baseData.EntityClass) {
5816
6273
  throw new Error('No "EntityClass" specified for this table');
5817
6274
  }
6275
+ const entity = new this.data.baseData.EntityClass();
6276
+ EntityUtilities.setDefaultValues(entity);
5818
6277
  if (this.data.baseData.create) {
5819
- this.data.baseData.create(new this.data.baseData.EntityClass());
6278
+ this.data.baseData.create(entity);
5820
6279
  }
5821
6280
  else {
5822
- this.createDefault(new this.data.baseData.EntityClass());
6281
+ this.createDefault(entity);
5823
6282
  }
5824
6283
  }
5825
6284
  });
@@ -5981,6 +6440,15 @@ class PropertyDecoratorConfig {
5981
6440
  */
5982
6441
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5983
6442
  isReadOnly;
6443
+ /**
6444
+ * The value that the property should be prefilled with. Only active in create mode.
6445
+ */
6446
+ default;
6447
+ /**
6448
+ * A function that runs just before the inputChangeEvent every time the property is changed.
6449
+ */
6450
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6451
+ change;
5984
6452
  }
5985
6453
 
5986
6454
  /**
@@ -6522,6 +6990,7 @@ class DateTimeDateDecoratorConfigInternal extends PropertyDecoratorConfigInterna
6522
6990
  this.minTime = data.minTime;
6523
6991
  this.maxTime = data.maxTime;
6524
6992
  this.filterTime = data.filterTime;
6993
+ this.defaultWidths = [6, 12, 12];
6525
6994
  }
6526
6995
  }
6527
6996
 
@@ -7076,5 +7545,5 @@ class StringDecoratorConfig extends PropertyDecoratorConfig {
7076
7545
  * Generated bundle index. Do not edit.
7077
7546
  */
7078
7547
 
7079
- export { ArrayDecoratorConfig, DateUtilities, DecoratorTypes, Entity, EntityService, EntityUtilities, FileUtilities, NGX_EDIT_DATA, NGX_EDIT_DATA_ENTITY, NGX_EDIT_DATA_ENTITY_SERVICE, NGX_GET_VALIDATION_ERROR_MESSAGE, NgxMatEntityBaseDisplayColumnValueComponent, NgxMatEntityBaseInputComponent, NgxMatEntityConfirmDialogComponent, NgxMatEntityCreateDialogComponent, NgxMatEntityEditDialogComponent, NgxMatEntityEditPageComponent, NgxMatEntityInputComponent, NgxMatEntityInputModule, NgxMatEntityTableComponent, UnsavedChangesGuard, array, boolean, custom, date, defaultEditDataRoute, exportAsCsvMultiAction, exportAsJsonMultiAction, exportAsXmlMultiAction, file, hasMany, importFromJsonMultiAction, number, object, referencesMany, referencesOne, string };
7548
+ export { ArrayDecoratorConfig, DateUtilities, DecoratorTypes, Entity, EntityService, EntityUtilities, FileUtilities, NGX_EDIT_DATA, NGX_EDIT_DATA_ENTITY, NGX_EDIT_DATA_ENTITY_SERVICE, NGX_GET_VALIDATION_ERROR_MESSAGE, NGX_VALIDATION_ERRORS_TOOLTIP_TITLE, NgxMatEntityBaseDisplayColumnValueComponent, NgxMatEntityBaseInputComponent, NgxMatEntityConfirmDialogComponent, NgxMatEntityCreateDialogComponent, NgxMatEntityEditDialogComponent, NgxMatEntityEditPageComponent, NgxMatEntityInputComponent, NgxMatEntityInputModule, NgxMatEntityTableComponent, TooltipComponent, UnsavedChangesGuard, ValidationUtilities, array, boolean, custom, date, defaultEditDataRoute, exportAsCsvMultiAction, exportAsJsonMultiAction, exportAsXmlMultiAction, file, getValidationErrorsTooltipContent, hasMany, importFromJsonMultiAction, number, object, referencesMany, referencesOne, string };
7080
7549
  //# sourceMappingURL=ngx-material-entity.mjs.map