@verisoft/ui-govcz 18.3.0 → 18.4.0

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 (19) hide show
  1. package/package.json +4 -4
  2. package/src/lib/components/shared-components/action-button-group/action-button-group.component.ts +1 -1
  3. package/src/lib/components/shared-components/dynamic-component/dynamic-component-factory.service.ts +75 -23
  4. package/src/lib/components/shared-components/dynamic-component/dynamic-component.component.ts +5 -4
  5. package/src/lib/components/shared-components/feature-list/directives/feature-list-column.directive.ts +10 -4
  6. package/src/lib/components/shared-components/feature-list/feature-list-page.model.ts +2 -1
  7. package/src/lib/components/shared-components/feature-list/feature-list.component.html +3 -0
  8. package/src/lib/components/shared-components/feature-list/feature-list.component.scss +1 -1
  9. package/src/lib/components/shared-components/feature-list/feature-list.component.ts +32 -5
  10. package/src/lib/components/shared-components/feature-list/index.ts +1 -0
  11. package/src/lib/components/shared-components/filter/directives/filter-field.directive.ts +19 -8
  12. package/src/lib/components/shared-components/filter/filter.component.html +1 -0
  13. package/src/lib/components/shared-components/generic-field/generic-field.component.html +52 -9
  14. package/src/lib/components/shared-components/generic-field/generic-field.component.ts +16 -1
  15. package/src/lib/components/shared-components/generic-form/generic-form.component.html +33 -20
  16. package/src/lib/components/shared-components/generic-form/generic-form.component.ts +10 -1
  17. package/src/lib/components/shared-components/generic-form/generic-form.model.ts +10 -2
  18. package/tsconfig.json +3 -1
  19. package/tsconfig.lib.prod.json +2 -1
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@verisoft/ui-govcz",
3
- "version": "18.3.0",
3
+ "version": "18.4.0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^18.2.8",
6
6
  "@angular/core": "^18.2.8",
7
7
  "@angular/router": "18.2.8",
8
8
  "@gov-design-system-ce/angular": "^1.1.1",
9
- "@verisoft/ui-core": "18.0.0",
9
+ "@verisoft/ui-core": "18.4.0",
10
10
  "@gov-design-system-ce/components": "^4.1.3-BETA-10",
11
11
  "@angular/forms": "18.2.8",
12
12
  "uuid": "^10.0.0",
13
- "@verisoft/core": "18.0.0",
13
+ "@verisoft/core": "18.4.0",
14
14
  "zxcvbn": "^4.4.2",
15
15
  "rxjs": "~7.8.0",
16
16
  "@angular/cdk": "^18.2.14",
17
17
  "@ngx-translate/core": "^15.0.0",
18
- "@verisoft/security-core": "18.0.0"
18
+ "@verisoft/security-core": "18.4.0"
19
19
  },
20
20
  "sideEffects": false
21
21
  }
@@ -15,8 +15,8 @@ import {
15
15
  queryListChanged,
16
16
  ScreenSizeService,
17
17
  UnsubscribeComponent,
18
- MenuItem,
19
18
  } from '@verisoft/ui-core';
19
+ import { MenuItem } from 'primeng/api';
20
20
  import { MenuModule } from 'primeng/menu';
21
21
  import {
22
22
  combineLatestWith,
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import {
2
3
  Injectable,
3
4
  ViewContainerRef,
@@ -6,22 +7,29 @@ import {
6
7
  Injector,
7
8
  ComponentRef,
8
9
  ComponentFactory,
9
- OnInit,
10
10
  OnChanges,
11
11
  SimpleChanges,
12
12
  SimpleChange,
13
+ EventEmitter,
14
+ OnDestroy,
13
15
  } from '@angular/core';
16
+ import { ExtendedComponent } from '@verisoft/ui-core';
17
+ import { Subscription } from 'rxjs';
14
18
 
15
19
  @Injectable({
16
20
  providedIn: 'root',
17
21
  })
18
- export class DynamicComponentFactoryService {
19
- constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
22
+ export class DynamicComponentFactoryService implements OnDestroy {
23
+ constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
24
+
25
+ ngOnDestroy(): void {
26
+ this.unsubscribeComponentEvents(this);
27
+ }
20
28
 
21
29
  async createDynamicComponent<TComponent>(
22
30
  componentType: Type<TComponent>,
23
31
  viewContainerRef: ViewContainerRef,
24
- inputs: Partial<TComponent>,
32
+ inputs: ExtendedComponent<TComponent>,
25
33
  injector: Injector | undefined = undefined
26
34
  ) {
27
35
  const componentFactory =
@@ -32,7 +40,6 @@ export class DynamicComponentFactoryService {
32
40
  undefined,
33
41
  injector
34
42
  );
35
-
36
43
  this.setComponentDataInt(componentFactory, component, inputs);
37
44
  this.fireComponentEvents(component.instance, inputs);
38
45
  return component;
@@ -49,27 +56,26 @@ export class DynamicComponentFactoryService {
49
56
  this.setComponentDataInt(factory, component, inputs);
50
57
  }
51
58
 
52
- private fireComponentEvents<TComponent>(instance: TComponent, inputs: Partial<TComponent>) {
53
- if (instance) {
54
- const onChangeComponent = instance as unknown as OnChanges;
55
- if (onChangeComponent.ngOnChanges && inputs) {
56
- const changeEventArgs = Object.keys(inputs).reduce((changes: SimpleChanges, key: string) => {
57
- const inputValue = (inputs as { [key: string]: unknown })[key];
58
- changes[key] = new SimpleChange(undefined, inputValue, true);
59
- return changes;
60
- }, {} as SimpleChanges);
61
-
62
-
63
- onChangeComponent.ngOnChanges(changeEventArgs);
64
- }
59
+ private unsubscribeComponentEvents<TComponent>(instance: TComponent) {
60
+ const subscriptionStoreKey = '__outputSubscriptions__';
61
+ const subscriptions = (instance as any)[subscriptionStoreKey] as Map<string, Subscription>;
65
62
 
66
- const onInitComponent = instance as unknown as OnInit;
67
- if (onInitComponent.ngOnInit) {
68
- onInitComponent.ngOnInit();
69
- }
63
+ if (subscriptions) {
64
+ subscriptions.forEach((sub) => sub.unsubscribe());
65
+ subscriptions.clear();
70
66
  }
71
67
  }
72
68
 
69
+ private fireComponentEvents<TComponent>(
70
+ instance: TComponent,
71
+ inputs: ExtendedComponent<TComponent>
72
+ ) {
73
+ if (!instance || typeof instance !== 'object') return;
74
+
75
+ this.fireInputComponentEvents(instance, inputs);
76
+ this.fireOutputComponentEvents(instance, inputs);
77
+ }
78
+
73
79
  private setComponentDataInt<TComponent>(
74
80
  factory: ComponentFactory<TComponent>,
75
81
  component: ComponentRef<TComponent>,
@@ -83,8 +89,54 @@ export class DynamicComponentFactoryService {
83
89
  .forEach((x) => {
84
90
  (<{ [key: string]: unknown }>component.instance)[x] = (<
85
91
  { [key: string]: unknown }
86
- >inputs)[x];
92
+ >inputs)[x];
87
93
  });
88
94
  }
89
95
  }
96
+
97
+ private fireInputComponentEvents<TComponent>(
98
+ instance: TComponent,
99
+ inputs: ExtendedComponent<TComponent>
100
+ ) {
101
+ const onChangeComponent = instance as unknown as OnChanges;
102
+ if (onChangeComponent.ngOnChanges && inputs) {
103
+ const changeEventArgs = Object.keys(inputs).reduce((changes: SimpleChanges, key: string) => {
104
+ const inputValue = (inputs as { [key: string]: unknown })[key];
105
+ changes[key] = new SimpleChange(undefined, inputValue, true);
106
+ return changes;
107
+ }, {} as SimpleChanges);
108
+
109
+ onChangeComponent.ngOnChanges(changeEventArgs);
110
+ }
111
+ }
112
+
113
+ private fireOutputComponentEvents<TComponent>(
114
+ instance: TComponent & object,
115
+ inputs: ExtendedComponent<TComponent>
116
+ ) {
117
+ const outputs = Object.keys(inputs).filter((key) => {
118
+ const emitter = (instance as Record<string, any>)[key];
119
+ return emitter instanceof EventEmitter;
120
+ });
121
+
122
+ const subscriptionStoreKey = '__outputSubscriptions__';
123
+ if (!(subscriptionStoreKey in instance)) {
124
+ (instance as any)[subscriptionStoreKey] = new Map<string, Subscription>();
125
+ }
126
+ const subscriptions = (instance as any)[subscriptionStoreKey] as Map<string, Subscription>;
127
+
128
+ for (const outputKey of outputs) {
129
+ const eventEmitter = (instance as Record<string, any>)[outputKey] as EventEmitter<any>;
130
+ const callback = inputs[outputKey] as (value: any) => void;
131
+
132
+ if (eventEmitter && typeof callback === 'function') {
133
+ if (subscriptions.has(outputKey)) {
134
+ subscriptions.get(outputKey)!.unsubscribe();
135
+ }
136
+
137
+ const subscription = eventEmitter.subscribe((value: any) => callback(value));
138
+ subscriptions.set(outputKey, subscription);
139
+ }
140
+ }
141
+ }
90
142
  }
@@ -11,6 +11,7 @@ import {
11
11
  ViewChild,
12
12
  ViewContainerRef,
13
13
  } from '@angular/core';
14
+ import { ExtendedComponent } from '@verisoft/ui-core';
14
15
  import { DynamicComponentFactoryService } from './dynamic-component-factory.service';
15
16
 
16
17
  @Component({
@@ -22,7 +23,7 @@ import { DynamicComponentFactoryService } from './dynamic-component-factory.serv
22
23
  export class DynamicComponent<TComponent> implements AfterViewInit, OnChanges {
23
24
  @Input() componentType!: Type<TComponent>;
24
25
 
25
- @Input() data!: Partial<TComponent>;
26
+ @Input() data!: ExtendedComponent<TComponent>;
26
27
 
27
28
  @ViewChild('dynamicContainer', { read: ViewContainerRef, static: true })
28
29
  container!: ViewContainerRef;
@@ -34,15 +35,15 @@ export class DynamicComponent<TComponent> implements AfterViewInit, OnChanges {
34
35
  private injector = inject(Injector);
35
36
 
36
37
  ngOnChanges(): void {
37
- this.crateComponent();
38
+ this.createComponent();
38
39
  }
39
40
 
40
41
  ngAfterViewInit(): void {
41
- this.crateComponent();
42
+ this.createComponent();
42
43
  this.changeDetectorRef.detectChanges();
43
44
  }
44
45
 
45
- private crateComponent() {
46
+ private createComponent() {
46
47
  if (this.container) {
47
48
  this.factoryServices.createDynamicComponent(
48
49
  this.componentType,
@@ -1,5 +1,5 @@
1
1
  import { Directive, Input } from '@angular/core';
2
- import { TableColumnDirective } from '@verisoft/ui-core';
2
+ import { GenericFieldType, GenericFieldTypeType, TableColumnDirective } from '@verisoft/ui-core';
3
3
  import { FEATURE_LIST_COLUMN_PROVIDER, FeatureListColumnDefinition, FeatureListColumnProvider } from '../feature-list-page.model';
4
4
 
5
5
  @Directive({
@@ -14,13 +14,19 @@ import { FEATURE_LIST_COLUMN_PROVIDER, FeatureListColumnDefinition, FeatureListC
14
14
  },
15
15
  ],
16
16
  })
17
- export class FeatureListColumnDirective<T> extends TableColumnDirective<T> implements FeatureListColumnProvider<T> {
18
- @Input()
19
- filter = false;
17
+ export class FeatureListColumnDirective<T>
18
+ extends TableColumnDirective<T>
19
+ implements FeatureListColumnProvider<T>
20
+ {
21
+ @Input() filter = false;
22
+
23
+ @Input() type: GenericFieldTypeType = GenericFieldType.text;
20
24
 
21
25
  override getDefinition(): FeatureListColumnDefinition<T> {
22
26
  const definition = super.getDefinition() as FeatureListColumnDefinition<T>;
23
27
  definition.filter = this.filter;
28
+ definition.type = this.type;
29
+ definition.format = this.format;
24
30
  return definition;
25
31
  }
26
32
  }
@@ -1,6 +1,6 @@
1
1
  import { InjectionToken } from '@angular/core';
2
2
  import { Route } from '@angular/router';
3
- import { ColumnDefinition } from '@verisoft/ui-core';
3
+ import { ColumnDefinition, GenericFieldTypeType } from '@verisoft/ui-core';
4
4
  import { FeatureListPageComponent } from './feature-list-page.component';
5
5
 
6
6
  export interface FeatureListPageConfig {
@@ -30,6 +30,7 @@ export function addFeatureListPage(
30
30
 
31
31
  export interface FeatureListColumnDefinition<T> extends ColumnDefinition<T> {
32
32
  filter?: boolean;
33
+ type?: GenericFieldTypeType;
33
34
  }
34
35
 
35
36
  export const FEATURE_LIST_COLUMN_PROVIDER = new InjectionToken(
@@ -48,6 +48,9 @@
48
48
  [autoBind]="true"
49
49
  [datasource]="datasource"
50
50
  [columns]="columns"
51
+ [extraFilter]="extraFilter"
52
+ [maximumColumnLength]="maximumColumnLength"
53
+ [disableCustomClicks]="disableCustomClicks"
51
54
  (selectionChange)="selectItems($event)"
52
55
  >
53
56
  </v-table>
@@ -7,4 +7,4 @@
7
7
 
8
8
  :host {
9
9
  @extend .full-height-container;
10
- }
10
+ }
@@ -25,12 +25,13 @@ import {
25
25
  DialogService,
26
26
  downloadFile,
27
27
  GenericFieldDefinition,
28
+ MAX_COLUMN_CHAR_COUNT,
28
29
  TableDatasourceDirective,
29
30
  TableFilterDirective,
30
31
  TableSelectionMode,
31
32
  TableSelectionModeType,
32
33
  } from '@verisoft/ui-core';
33
- import { forkJoin, Observable, of, switchMap, take } from 'rxjs';
34
+ import { take, switchMap, forkJoin, Observable, of } from 'rxjs';
34
35
  import { Icons } from '../../../icons';
35
36
  import { TableComponent } from '../../table';
36
37
  import {
@@ -75,7 +76,7 @@ export class FeatureListComponent<T> implements AfterViewInit {
75
76
 
76
77
  @Input() autoBind = true;
77
78
 
78
- @Input({ required: true }) title!: string;
79
+ @Input() title!: string;
79
80
 
80
81
  @Input() columns!: FeatureListColumnDefinition<T>[];
81
82
 
@@ -119,21 +120,37 @@ export class FeatureListComponent<T> implements AfterViewInit {
119
120
 
120
121
  @Input() datasource!: DatasourceType<T>;
121
122
 
123
+ @Input() extraFilter!: any;
124
+
125
+ @Input() disableCustomClicks = false;
126
+
127
+ @Input() maximumColumnLength = MAX_COLUMN_CHAR_COUNT;
128
+
122
129
  @Output() addClick = new EventEmitter();
123
130
 
124
131
  @Output() downloadClick = new EventEmitter();
125
132
 
126
133
  @Output() deleteClick = new EventEmitter<T[]>();
127
134
 
135
+ @Output() selectionChange = new EventEmitter();
136
+
137
+ @Input() set selectionMode(mode: TableSelectionModeType | undefined) {
138
+ this._selectionMode = mode;
139
+ }
140
+
141
+ get selectionMode(): TableSelectionModeType | undefined {
142
+ return this.canDelete
143
+ ? TableSelectionMode.single
144
+ : this._selectionMode;
145
+ }
146
+
128
147
  icons = Icons;
129
148
 
130
149
  private httpClient = inject(HttpClient);
131
150
 
132
151
  private baseUrl: string = inject(BASE_URL_PATH);
133
152
 
134
- get selectionMode(): TableSelectionModeType | undefined {
135
- return this.canDelete ? TableSelectionMode.single : undefined;
136
- }
153
+ private _selectionMode: TableSelectionModeType | undefined;
137
154
 
138
155
  private cdRef = inject(ChangeDetectorRef);
139
156
 
@@ -153,10 +170,20 @@ export class FeatureListComponent<T> implements AfterViewInit {
153
170
  if (this.fieldDeclarations?.length) {
154
171
  this.filters = this.fieldDeclarations?.toArray();
155
172
  }
173
+
174
+ this.cdRef.detectChanges();
156
175
  }
157
176
 
158
177
  selectItems(items: T[]) {
159
178
  this.selection = items ?? [];
179
+
180
+ if (this.selectionMode !== undefined) {
181
+ this.selectionChange.emit(
182
+ this.selectionMode === 'multiple'
183
+ ? this.selection
184
+ : this.selection[0]
185
+ );
186
+ }
160
187
  }
161
188
 
162
189
  startDeleteItems() {
@@ -2,3 +2,4 @@ export * from './feature-list.component';
2
2
  export * from './feature-list-page.model';
3
3
  export * from './directives/feature-list-column.directive';
4
4
  export * from './directives/feature-list-filter-field.directive';
5
+ export * from './feature-list-filter.pipe';
@@ -1,4 +1,6 @@
1
1
  import { Directive, Input } from '@angular/core';
2
+ import { ValidatorFn } from '@angular/forms';
3
+ import { DatasourceType } from '@verisoft/core';
2
4
  import { GenericFieldDefinition, GenericFieldType, GenericFieldTypeType } from '@verisoft/ui-core';
3
5
 
4
6
  @Directive({
@@ -7,18 +9,27 @@ import { GenericFieldDefinition, GenericFieldType, GenericFieldTypeType } from '
7
9
  standalone: true,
8
10
  })
9
11
  export class FilterFieldDirective implements GenericFieldDefinition {
10
-
11
- @Input({ required: true }) name!: string;
12
+ @Input({ required: true }) name!: string;
12
13
 
13
- @Input() type?: GenericFieldTypeType | undefined = GenericFieldType.text;
14
+ @Input() type: GenericFieldTypeType | undefined = GenericFieldType.text;
14
15
 
15
- @Input() label?: string | undefined;
16
+ @Input() label: string | undefined;
16
17
 
17
- @Input() optionLabel!: string;
18
+ @Input() optionLabel!: string;
18
19
 
19
- @Input() optionValue?: string | undefined;
20
+ @Input() optionValue: string | undefined;
20
21
 
21
- @Input() options?: unknown[] | undefined;
22
+ @Input() options: unknown[] | undefined;
22
23
 
23
- @Input() value?: unknown;
24
+ @Input() value?: unknown;
25
+
26
+ @Input() validator?: ValidatorFn[];
27
+
28
+ @Input() datasource: DatasourceType<any> | undefined;
29
+
30
+ @Input() filterField?: string;
31
+
32
+ @Input() showFilter?: boolean;
33
+
34
+ @Input() localSearch?: boolean;
24
35
  }
@@ -27,6 +27,7 @@
27
27
  [fields]="declaration"
28
28
  [formGroup]="formGroup"
29
29
  ></v-generic-form>
30
+ <v-button label="X" class="mt-3" (click)="clear()" />
30
31
  </div>
31
32
  }
32
33
  <div class="v-filter_action-buttons d-flex">
@@ -4,8 +4,8 @@
4
4
  [floatLabel]="floatLabel === true"
5
5
  [size]="size"
6
6
  [formControl]="formControl"
7
- ></v-textfield>
8
- } @if (type === fieldTypes.dropdown) {
7
+ />
8
+ } @else if (type === fieldTypes.dropdown && !datasource) {
9
9
  <v-dropdown
10
10
  [label]="!floatLabel ? label : ''"
11
11
  [floatLabel]="floatLabel ? label : ''"
@@ -14,14 +14,36 @@
14
14
  [optionLabel]="optionLabel"
15
15
  [optionValue]="optionValue ?? optionLabel"
16
16
  [loading]="loading"
17
+ [forceMinWidth]="true"
17
18
  [formControl]="formControl"
19
+ [showFilter]="showFilter ?? false"
20
+ [localSearch]="localSearch ?? false"
18
21
  (changeEvent)="changed.emit($event)"
19
22
  (clearEvent)="cleared.emit($event)"
20
23
  (lazyLoadEvent)="lazyLoad.emit($any($event))"
21
24
  (showEvent)="showed.emit($event)"
22
- >
23
- </v-dropdown>
24
- } @else if (type === fieldTypes.multiselect) {
25
+ />
26
+ } @else if (type === fieldTypes.dropdown && datasource) {
27
+ <v-dropdown
28
+ useDatasource
29
+ [forceMinWidth]="true"
30
+ [datasource]="datasource"
31
+ [optionLabel]="optionLabel"
32
+ [optionValue]="optionValue ?? optionLabel"
33
+ [label]="!floatLabel ? label : ''"
34
+ [floatLabel]="floatLabel ? label : ''"
35
+ [testId]="testId"
36
+ [loading]="loading"
37
+ [formControl]="formControl"
38
+ [showFilter]="showFilter ?? false"
39
+ [filterField]="filterField ?? 'fulltext'"
40
+ [localSearch]="localSearch ?? false"
41
+ (changeEvent)="changed.emit($event)"
42
+ (clearEvent)="cleared.emit($event)"
43
+ (lazyLoadEvent)="lazyLoad.emit($any($event))"
44
+ (showEvent)="showed.emit($event)"
45
+ />
46
+ } @else if (type === fieldTypes.multiselect && !datasource) {
25
47
  <v-multiselect
26
48
  [label]="!floatLabel ? label : ''"
27
49
  [floatLabel]="floatLabel ? label : ''"
@@ -35,14 +57,35 @@
35
57
  (clearEvent)="cleared.emit($event)"
36
58
  (lazyLoadEvent)="lazyLoad.emit($any($event))"
37
59
  (showEvent)="showed.emit($event)"
38
- >
39
- </v-multiselect>
60
+ />
61
+ } @else if (type === fieldTypes.multiselect && datasource) {
62
+ <v-multiselect
63
+ useDatasource
64
+ [datasource]="datasource"
65
+ [optionLabel]="optionLabel"
66
+ [optionValue]="optionValue ?? optionLabel"
67
+ [label]="!floatLabel ? label : ''"
68
+ [floatLabel]="floatLabel ? label : ''"
69
+ [testId]="testId"
70
+ [loading]="loading"
71
+ [formControl]="formControl"
72
+ (changeEvent)="changed.emit($event)"
73
+ (clearEvent)="cleared.emit($event)"
74
+ (lazyLoadEvent)="lazyLoad.emit($any($event))"
75
+ (showEvent)="showed.emit($event)"
76
+ />
40
77
  } @else if (type === fieldTypes.checkbox) {
41
78
  <v-tristatecheckbox
42
79
  [label]="label"
43
80
  [testId]="testId"
44
81
  [formControl]="formControl"
45
- ></v-tristatecheckbox>
82
+ />
83
+ } @else if (type === fieldTypes.simplecheckbox) {
84
+ <v-checkbox
85
+ [label]="label"
86
+ [testId]="testId"
87
+ [formControl]="formControl"
88
+ />
46
89
  } @else if (type === fieldTypes.calendar) {
47
90
  <v-calendar
48
91
  [label]="!floatLabel ? label : ''"
@@ -50,5 +93,5 @@
50
93
  [testId]="testId"
51
94
  [formControl]="formControl"
52
95
  [icon]="icons.calendar"
53
- ></v-calendar>
96
+ />
54
97
  }
@@ -1,3 +1,4 @@
1
+ import { CommonModule } from '@angular/common';
1
2
  import {
2
3
  ChangeDetectionStrategy,
3
4
  Component,
@@ -7,11 +8,13 @@ import {
7
8
  } from '@angular/core';
8
9
  import { ReactiveFormsModule } from '@angular/forms';
9
10
  import {
11
+ DatasourceType,
10
12
  FilterEvent,
11
13
  LazyLoadEvent,
12
14
  } from '@verisoft/core';
13
15
  import {
14
16
  BaseFormInputComponent,
17
+ DatasourceDirective,
15
18
  FieldSize,
16
19
  FieldSizeType,
17
20
  GENERIC_FIELD_COMPONENT_TOKEN,
@@ -21,6 +24,7 @@ import {
21
24
  } from '@verisoft/ui-core';
22
25
  import { Icons } from '../../../icons';
23
26
  import { CalendarComponent } from '../../calendar';
27
+ import { CheckboxComponent } from '../../checkbox';
24
28
  import { DropdownComponent } from '../../dropdown';
25
29
  import { MultiselectComponent } from '../../multiselect';
26
30
  import { TextfieldComponent } from '../../textfield';
@@ -30,13 +34,16 @@ import { TristatecheckboxComponent } from '../../tristatecheckbox';
30
34
  selector: 'v-generic-field',
31
35
  standalone: true,
32
36
  imports: [
37
+ CommonModule,
33
38
  DropdownComponent,
34
39
  CalendarComponent,
35
40
  TristatecheckboxComponent,
36
41
  MultiselectComponent,
37
42
  TextfieldComponent,
38
43
  ReactiveFormsModule,
39
- ],
44
+ CheckboxComponent,
45
+ DatasourceDirective,
46
+ ],
40
47
  providers: [
41
48
  {
42
49
  provide: GENERIC_FIELD_COMPONENT_TOKEN,
@@ -68,6 +75,14 @@ export class GenericFieldComponent<T>
68
75
 
69
76
  @Input() filter = true;
70
77
 
78
+ @Input() datasource?: DatasourceType<T>
79
+
80
+ @Input() filterField?: string;
81
+
82
+ @Input() showFilter?: boolean;
83
+
84
+ @Input() localSearch?: boolean;
85
+
71
86
  @Output() changed = new EventEmitter<any>();
72
87
  @Output() showed = new EventEmitter<any>();
73
88
  @Output() cleared = new EventEmitter<any>();
@@ -1,10 +1,33 @@
1
1
  @if (formGroupComputed) {
2
- <div class="v-generic-form row" [formGroup]="formGroupComputed">
3
- @for(field of fields; track field){ @if (columnClass) {
4
- <div class="v-generic-form__column {{ columnClass }}">
2
+ <div
3
+ class="v-generic-form"
4
+ [ngClass]="showAsRow ? 'd-flex flex-row' : 'row'"
5
+ [formGroup]="formGroupComputed"
6
+ >
7
+ @for(field of fields; track field) { @if (columnClass) {
8
+ <div class="v-generic-form__column {{ columnClass }}">
9
+ <v-generic-field
10
+ [type]="field.type"
11
+ [label]="field.label ?? 'NOT SET' | translate"
12
+ [floatLabel]="field.floatLabel"
13
+ [testId]="field.testId"
14
+ [options]="field.options"
15
+ [optionLabel]="field.optionLabel"
16
+ [optionValue]="field.optionValue ?? field.optionLabel"
17
+ [options]="field.options"
18
+ [size]="field.size"
19
+ [formControlName]="field.name"
20
+ [datasource]="field.datasource"
21
+ [showFilter]="field.showFilter"
22
+ [filterField]="field.filterField"
23
+ [localSearch]="field.localSearch"
24
+ ></v-generic-field>
25
+ </div>
26
+ } @else {
5
27
  <v-generic-field
28
+ class="me-4"
6
29
  [type]="field.type"
7
- [label]="field.label"
30
+ [label]="field.label ?? 'NOT SET' | translate"
8
31
  [floatLabel]="field.floatLabel"
9
32
  [testId]="field.testId"
10
33
  [options]="field.options"
@@ -13,21 +36,11 @@
13
36
  [options]="field.options"
14
37
  [size]="field.size"
15
38
  [formControlName]="field.name"
39
+ [datasource]="field.datasource"
40
+ [showFilter]="field.showFilter"
41
+ [filterField]="field.filterField"
42
+ [localSearch]="field.localSearch"
16
43
  ></v-generic-field>
44
+ } }
17
45
  </div>
18
- } @else {
19
- <v-generic-field
20
- [type]="field.type"
21
- [label]="field.label"
22
- [floatLabel]="field.floatLabel"
23
- [testId]="field.testId"
24
- [options]="field.options"
25
- [optionLabel]="field.optionLabel"
26
- [optionValue]="field.optionValue ?? field.optionLabel"
27
- [options]="field.options"
28
- [size]="field.size"
29
- [formControlName]="field.name"
30
- ></v-generic-field>
31
- } }
32
- </div>
33
- }
46
+ }
@@ -1,3 +1,4 @@
1
+ import { CommonModule } from '@angular/common';
1
2
  import {
2
3
  ChangeDetectionStrategy,
3
4
  Component,
@@ -6,6 +7,7 @@ import {
6
7
  SimpleChanges,
7
8
  } from '@angular/core';
8
9
  import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
10
+ import { TranslateModule } from '@ngx-translate/core';
9
11
  import { GenericFieldDefinition } from '@verisoft/ui-core';
10
12
  import { GenericFieldComponent } from '../generic-field';
11
13
  import {
@@ -16,7 +18,12 @@ import {
16
18
  @Component({
17
19
  selector: 'v-generic-form',
18
20
  standalone: true,
19
- imports: [GenericFieldComponent, ReactiveFormsModule],
21
+ imports: [
22
+ CommonModule,
23
+ GenericFieldComponent,
24
+ ReactiveFormsModule,
25
+ TranslateModule,
26
+ ],
20
27
  templateUrl: './generic-form.component.html',
21
28
  changeDetection: ChangeDetectionStrategy.OnPush,
22
29
  })
@@ -27,6 +34,8 @@ export class GenericFormComponent implements OnChanges {
27
34
 
28
35
  @Input() columns?: number;
29
36
 
37
+ @Input() showAsRow!: boolean;
38
+
30
39
  formGroupComputed!: UntypedFormGroup;
31
40
 
32
41
  columnClass?: string;
@@ -22,9 +22,17 @@ export function generateFormGroup(
22
22
  field.name,
23
23
  new UntypedFormControl(field.value, field.validator)
24
24
  );
25
- } else {
25
+ } else if (control && control.value !== field.value) {
26
+ control.setValue(field.value);
26
27
  control.setValidators(field.validator ?? null);
27
28
  }
29
+ else {
30
+ control.setValidators(field.validator ?? null);
31
+ }
32
+
33
+ if (field.readonly && (control || formGroup.get(field.name))) {
34
+ formGroup.get(field.name)?.disable();
35
+ }
28
36
  });
29
37
  if (!inputGroupChanged) {
30
38
  for (const field in formGroup.controls) {
@@ -55,6 +63,6 @@ export function getColumnClass(value?: number): string | undefined {
55
63
  case 6:
56
64
  return 'col-12 col-md-2';
57
65
  }
58
-
66
+
59
67
  return 'col-12 col-md-1';
60
68
  }
package/tsconfig.json CHANGED
@@ -25,6 +25,8 @@
25
25
  "enableI18nLegacyMessageIdFormat": false,
26
26
  "strictInjectionParameters": true,
27
27
  "strictInputAccessModifiers": true,
28
- "strictTemplates": true
28
+ "strictTemplates": true,
29
+ "compilationMode": "partial",
30
+ "enableIvy": true
29
31
  }
30
32
  }
@@ -4,6 +4,7 @@
4
4
  "declarationMap": false
5
5
  },
6
6
  "angularCompilerOptions": {
7
- "compilationMode": "partial"
7
+ "compilationMode": "partial",
8
+ "enableIvy": true
8
9
  }
9
10
  }