@mediusinc/mng-commons 7.4.0-rc.0 → 7.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 (28) hide show
  1. package/dev-scripts/version-info.js +18 -19
  2. package/fesm2022/mediusinc-mng-commons-core.mjs +69 -6
  3. package/fesm2022/mediusinc-mng-commons-core.mjs.map +1 -1
  4. package/fesm2022/mediusinc-mng-commons-filter.mjs +9 -3
  5. package/fesm2022/mediusinc-mng-commons-filter.mjs.map +1 -1
  6. package/fesm2022/mediusinc-mng-commons-form.mjs +287 -230
  7. package/fesm2022/mediusinc-mng-commons-form.mjs.map +1 -1
  8. package/fesm2022/{mediusinc-mng-commons-table-column-toggle.component-D7fm83ug.mjs → mediusinc-mng-commons-table-column-toggle.component-BS5xvoDR.mjs} +2 -2
  9. package/fesm2022/{mediusinc-mng-commons-table-column-toggle.component-D7fm83ug.mjs.map → mediusinc-mng-commons-table-column-toggle.component-BS5xvoDR.mjs.map} +1 -1
  10. package/fesm2022/{mediusinc-mng-commons-table-mediusinc-mng-commons-table-Czmm5fLT.mjs → mediusinc-mng-commons-table-mediusinc-mng-commons-table-BfEYZG7s.mjs} +279 -117
  11. package/fesm2022/mediusinc-mng-commons-table-mediusinc-mng-commons-table-BfEYZG7s.mjs.map +1 -0
  12. package/fesm2022/mediusinc-mng-commons-table.mjs +1 -1
  13. package/fesm2022/mediusinc-mng-commons-tableview-api.mjs +42 -13
  14. package/fesm2022/mediusinc-mng-commons-tableview-api.mjs.map +1 -1
  15. package/fesm2022/mediusinc-mng-commons-tableview.mjs +40 -19
  16. package/fesm2022/mediusinc-mng-commons-tableview.mjs.map +1 -1
  17. package/i18n/en.json +5 -2
  18. package/i18n/sl.json +5 -1
  19. package/package.json +1 -1
  20. package/types/mediusinc-mng-commons-core.d.ts +2 -1
  21. package/types/mediusinc-mng-commons-filter.d.ts +6 -3
  22. package/types/mediusinc-mng-commons-form.d.ts +49 -77
  23. package/types/mediusinc-mng-commons-table-api.d.ts +12 -2
  24. package/types/mediusinc-mng-commons-table.d.ts +13 -5
  25. package/types/mediusinc-mng-commons-tableview-api.d.ts +47 -8
  26. package/types/mediusinc-mng-commons-tableview.d.ts +8 -2
  27. package/fesm2022/mediusinc-mng-commons-table-mediusinc-mng-commons-table-Czmm5fLT.mjs.map +0 -1
  28. package/version-info.json +0 -11
@@ -1,6 +1,6 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { InjectionToken, inject, Injectable, forwardRef, Injector, DestroyRef, input, booleanAttribute, output, viewChild, signal, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, numberAttribute, ChangeDetectorRef, effect, ElementRef, Renderer2, afterNextRender, Directive } from '@angular/core';
3
+ import { InjectionToken, inject, Injectable, forwardRef, Injector, DestroyRef, input, booleanAttribute, output, viewChild, signal, computed, afterNextRender, ChangeDetectionStrategy, ViewEncapsulation, Component, numberAttribute, ChangeDetectorRef, effect, ElementRef, Renderer2, Directive } from '@angular/core';
4
4
  import { takeUntilDestroyed, toObservable as toObservable$1 } from '@angular/core/rxjs-interop';
5
5
  import * as i1$1 from '@angular/forms';
6
6
  import { NG_VALUE_ACCESSOR, FormsModule, NG_VALIDATORS, FormBuilder, Validators, ReactiveFormsModule, NgControl } from '@angular/forms';
@@ -8,9 +8,10 @@ import { TranslateService, TranslatePipe } from '@ngx-translate/core';
8
8
  import { AutoComplete } from 'primeng/autocomplete';
9
9
  import { InputGroup } from 'primeng/inputgroup';
10
10
  import { InputGroupAddon } from 'primeng/inputgroupaddon';
11
- import { of, tap, ReplaySubject, take, switchMap, merge, Subject, distinctUntilChanged, debounceTime, combineLatest, map as map$1 } from 'rxjs';
11
+ import { Tag } from 'primeng/tag';
12
+ import { of, tap, merge, ReplaySubject, take, Subject, distinctUntilChanged, debounceTime, combineLatest, switchMap, map as map$1 } from 'rxjs';
12
13
  import { map } from 'rxjs/operators';
13
- import { FilterMatchMode, toObservable, LoggerService, CommonsInternalError, effectWithDeps, fromSubscribeError, getErrorLogLevel, narrowI18nToTranslation, RerenderDirective, booleanWithDefaultAttribute, TemplateDirective, CommonsFeatureTypeEnum } from '@mediusinc/mng-commons/core';
14
+ import { FilterMatchMode, toObservable, LoggerService, effectWithDeps, CommonsInternalError, fromSubscribeError, getErrorLogLevel, RerenderDirective, booleanWithDefaultAttribute, narrowI18nToTranslation, TemplateDirective, CommonsFeatureTypeEnum } from '@mediusinc/mng-commons/core';
14
15
  import { Divider } from 'primeng/divider';
15
16
  import { DatePicker } from 'primeng/datepicker';
16
17
  import * as i1 from 'primeng/inputmask';
@@ -136,25 +137,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
136
137
  args: [{ providedIn: 'root' }]
137
138
  }] });
138
139
 
140
+ function createAutocompleteItem(item, opts) {
141
+ // If item is already an AutocompleteItem, return it as-is to prevent double wrapping
142
+ if (item != null && typeof item === 'object' && '__original' in item && '__value' in item) {
143
+ return item;
144
+ }
145
+ const valueProp = opts?.optionsValueProperty;
146
+ const labelProp = opts?.optionsLabelProperty;
147
+ const trackProp = opts?.optionsTrackProperty;
148
+ const isTranslate = opts?.optionsLabelTranslate;
149
+ const acValue = valueProp != null && item[valueProp] != null ? item[valueProp] : item;
150
+ const labelFromItem = ((labelProp != null && item[labelProp] != null ? item[labelProp] : item) ?? '').toString();
151
+ const trackValue = trackProp ? (item[trackProp] ?? acValue) : acValue;
152
+ return {
153
+ __original: item,
154
+ __track: typeof trackValue === 'object' ? trackValue : trackValue?.toString(),
155
+ __value: acValue,
156
+ __label: isTranslate && opts?.translate ? opts.translate.instant(labelFromItem) : labelFromItem,
157
+ __labelI18nKey: isTranslate ? labelFromItem : undefined
158
+ };
159
+ }
160
+
139
161
  const AUTOCOMPLETE_VALUE_ACCESSOR = {
140
162
  provide: NG_VALUE_ACCESSOR,
141
163
  useExisting: forwardRef(() => AutocompleteComponent),
142
164
  multi: true
143
165
  };
144
166
  class AutocompleteComponent {
167
+ #injector;
168
+ #destroyRef;
169
+ #translate;
170
+ #labelLookupService;
171
+ #logger;
172
+ #isInited;
173
+ #searchSubscription;
174
+ #dataProviderService;
175
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
176
+ #onChangeFn;
177
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
178
+ #onTouchedFn;
179
+ #value;
180
+ #valueItem;
181
+ #disabledWritable;
182
+ #isPanelShown;
183
+ #isFocused;
184
+ #userSelectedItem;
185
+ #queryResultCacheSubject;
186
+ #currentQuery;
145
187
  get value() {
146
- return this._value;
188
+ return this.#value;
189
+ }
190
+ get valueAsItem() {
191
+ return this.#valueItem;
147
192
  }
148
193
  constructor() {
149
- this.injector = inject(Injector);
150
- this.destroyRef = inject(DestroyRef);
151
- this.translate = inject(TranslateService);
152
- this.labelLookupService = inject(LookupLabelResolutionService);
153
- this.logger = inject(LoggerService).create('AutocompleteComponent');
194
+ this.#injector = inject(Injector);
195
+ this.#destroyRef = inject(DestroyRef);
196
+ this.#translate = inject(TranslateService);
197
+ this.#labelLookupService = inject(LookupLabelResolutionService);
198
+ this.#logger = inject(LoggerService).create('AutocompleteComponent');
154
199
  this.dataProvider = input.required(...(ngDevMode ? [{ debugName: "dataProvider" }] : []));
155
200
  this.optionsTrackProperty = input(...(ngDevMode ? [undefined, { debugName: "optionsTrackProperty" }] : []));
156
- this.optionsValuePropertyInit = input(undefined, { ...(ngDevMode ? { debugName: "optionsValuePropertyInit" } : {}), alias: 'optionsValueProperty' });
157
- this.optionsLabelPropertyInit = input(undefined, { ...(ngDevMode ? { debugName: "optionsLabelPropertyInit" } : {}), alias: 'optionsLabelProperty' });
201
+ this.optionsValueProperty = input(undefined, ...(ngDevMode ? [{ debugName: "optionsValueProperty" }] : []));
202
+ this.optionsLabelProperty = input(undefined, ...(ngDevMode ? [{ debugName: "optionsLabelProperty" }] : []));
158
203
  this.optionsLabelTranslate = input(false, { ...(ngDevMode ? { debugName: "optionsLabelTranslate" } : {}), transform: booleanAttribute });
159
204
  this.inlineSearch = input(false, { ...(ngDevMode ? { debugName: "inlineSearch" } : {}), transform: booleanAttribute });
160
205
  this.openOnFocus = input(false, { ...(ngDevMode ? { debugName: "openOnFocus" } : {}), transform: booleanAttribute });
@@ -165,6 +210,7 @@ class AutocompleteComponent {
165
210
  this.showClear = input(false, { ...(ngDevMode ? { debugName: "showClear" } : {}), transform: booleanAttribute });
166
211
  this.autoClear = input(false, { ...(ngDevMode ? { debugName: "autoClear" } : {}), transform: booleanAttribute });
167
212
  this.selectFirst = input(false, { ...(ngDevMode ? { debugName: "selectFirst" } : {}), transform: booleanAttribute }); //on every input field change return first given value (or null)
213
+ this.allowInput = input(false, { ...(ngDevMode ? { debugName: "allowInput" } : {}), transform: booleanAttribute });
168
214
  this.searchTrim = input(undefined, ...(ngDevMode ? [{ debugName: "searchTrim" }] : []));
169
215
  this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : {}), transform: booleanAttribute, alias: 'disabled' });
170
216
  this.templates = input([], ...(ngDevMode ? [{ debugName: "templates" }] : []));
@@ -172,69 +218,49 @@ class AutocompleteComponent {
172
218
  // eslint-disable-next-line @angular-eslint/no-output-native
173
219
  this.blur = output();
174
220
  this.primeAutocomplete = viewChild(AutoComplete, ...(ngDevMode ? [{ debugName: "primeAutocomplete" }] : []));
175
- this.isInited = false;
176
- this.searchSubscription = null;
177
- this.dataProviderService = null;
221
+ this.#isInited = false;
222
+ this.#searchSubscription = null;
223
+ this.#dataProviderService = null;
178
224
  // eslint-disable-next-line @typescript-eslint/no-empty-function
179
- this.onChangeFn = () => { };
225
+ this.#onChangeFn = () => { };
180
226
  // eslint-disable-next-line @typescript-eslint/no-empty-function
181
- this.onTouchedFn = () => { };
227
+ this.#onTouchedFn = () => { };
182
228
  this.ngModelValue = signal(undefined, ...(ngDevMode ? [{ debugName: "ngModelValue" }] : []));
183
- this._disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
184
- this.disabled = computed(() => this._disabled() || this.disabledInput(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
229
+ this.#disabledWritable = signal(false, ...(ngDevMode ? [{ debugName: "#disabledWritable" }] : []));
230
+ this.disabled = computed(() => this.#disabledWritable() || this.disabledInput(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
185
231
  this.suggestions = signal([], ...(ngDevMode ? [{ debugName: "suggestions" }] : []));
186
- this.isPanelShown = false;
187
- this.isFocused = false;
232
+ this.#isPanelShown = false;
233
+ this.#isFocused = false;
188
234
  this.prependTemplates = computed(() => this.templates().filter(t => t.name() === 'prepend'), ...(ngDevMode ? [{ debugName: "prependTemplates" }] : []));
189
235
  this.appendTemplates = computed(() => this.templates().filter(t => t.name() === 'append'), ...(ngDevMode ? [{ debugName: "appendTemplates" }] : []));
190
- this.optionsLabelProperty = computed(() => {
191
- if (this.optionsLabelTranslate()) {
192
- // setup translation properties
193
- if (this.optionsLabelPropertyInit()) {
194
- return `${this.optionsLabelPropertyInit()}_i18n`;
195
- }
196
- else if (!this.optionsLabelPropertyInit() && !this.optionsValuePropertyInit()) {
197
- return 'title_i18n';
198
- }
199
- else {
200
- throw new CommonsInternalError(`Invalid use with value (${this.optionsValuePropertyInit()}) and label (${this.optionsLabelPropertyInit()}) property setup.`, {
201
- name: 'AutocompleteComponentError'
202
- });
203
- }
204
- }
205
- return this.optionsLabelPropertyInit();
206
- }, ...(ngDevMode ? [{ debugName: "optionsLabelProperty" }] : []));
207
- this.optionsValueProperty = computed(() => {
208
- if (this.optionsLabelTranslate()) {
209
- // setup translation properties
210
- if (!this.optionsLabelPropertyInit() && !this.optionsValuePropertyInit()) {
211
- return 'value';
212
- }
213
- else if (!this.optionsLabelPropertyInit()) {
214
- throw new CommonsInternalError(`Invalid use with value (${this.optionsValuePropertyInit()}) and label (${this.optionsLabelPropertyInit()}) property setup.`, {
215
- name: 'AutocompleteComponentError'
216
- });
217
- }
218
- }
219
- return this.optionsValuePropertyInit();
220
- }, ...(ngDevMode ? [{ debugName: "optionsValueProperty" }] : []));
221
236
  effectWithDeps([this.ngModelValue, this.primeAutocomplete, this.multiselect], ([ngModelValue, primeAutocomplete, multiselect]) => {
222
- // it hurts no one to re-write this
223
- this._value = this.convertValueWithOptionsValuePropSetting(ngModelValue);
224
- this._rawValue = ngModelValue;
237
+ this.#value = this.#getValueFromItem(ngModelValue);
238
+ this.#valueItem = ngModelValue;
225
239
  // sync to autcomplete only if all is ready
226
240
  if (primeAutocomplete != null &&
227
241
  multiselect === primeAutocomplete?.multiple &&
228
- (this._rawValue == null || (multiselect && Array.isArray(this._rawValue)) || (!multiselect && !Array.isArray(this._rawValue)))) {
229
- primeAutocomplete?.updateModel(this._rawValue);
242
+ (this.#valueItem == null || (multiselect && Array.isArray(this.#valueItem)) || (!multiselect && !Array.isArray(this.#valueItem)))) {
243
+ primeAutocomplete?.updateModel(this.#valueItem);
244
+ }
245
+ });
246
+ effectWithDeps([this.optionsLabelTranslate, this.optionsLabelProperty, this.optionsValueProperty], ([isLabelTranslate, labelProp, valueProp]) => {
247
+ if (isLabelTranslate && labelProp == null && valueProp) {
248
+ throw new CommonsInternalError(`Invalid use with value (${valueProp}) and label (${labelProp}) property setup.`, {
249
+ name: 'AutocompleteComponentError'
250
+ });
251
+ }
252
+ });
253
+ merge([this.#translate.onTranslationChange, this.#translate.onLangChange])
254
+ .pipe(takeUntilDestroyed())
255
+ .subscribe(() => {
256
+ this.suggestions.update(items => items.map(item => this.#createAutocompleteItem(item.__original)));
257
+ });
258
+ afterNextRender(() => {
259
+ this.#setItemsAndDataProvider();
260
+ if (this.selectFirst() && !this.#value) {
261
+ this.onSearch(undefined, true);
230
262
  }
231
263
  });
232
- }
233
- ngOnInit() {
234
- this.setItemsAndDataProvider();
235
- if (this.selectFirst() && !this._value) {
236
- this.onSearch(undefined, true);
237
- }
238
264
  }
239
265
  onSearch(event, isInit = false) {
240
266
  // openOnFocus enables this method to be called when input is focused. The dropdown button calls this method and puts the focus on the input field, which causes 2 calls.
@@ -243,11 +269,11 @@ class AutocompleteComponent {
243
269
  return;
244
270
  // cancel any existing requests
245
271
  if (!this.inlineSearch()) {
246
- this.searchSubscription?.unsubscribe();
272
+ this.#searchSubscription?.unsubscribe();
247
273
  }
248
274
  const optionsLabelProperty = this.optionsLabelProperty();
249
- const query = this.trimValue(event?.query);
250
- this.currentQuery = query;
275
+ const query = this.#trimSearchQuery(event?.query);
276
+ this.#currentQuery = query;
251
277
  const params = {
252
278
  limit: 50
253
279
  };
@@ -262,159 +288,154 @@ class AutocompleteComponent {
262
288
  }
263
289
  };
264
290
  }
265
- if (!this.queryResultCacheSubject || !this.inlineSearch()) {
266
- if (!this.queryResultCacheSubject) {
267
- this.queryResultCacheSubject = new ReplaySubject(1);
291
+ if (!this.#queryResultCacheSubject || !this.inlineSearch()) {
292
+ if (!this.#queryResultCacheSubject) {
293
+ this.#queryResultCacheSubject = new ReplaySubject(1);
268
294
  }
269
- this.searchSubscription = this.getLookup(params, query)
270
- .pipe(takeUntilDestroyed(this.destroyRef))
295
+ this.#searchSubscription = this.#getLookup(params, query)
296
+ .pipe(takeUntilDestroyed(this.#destroyRef))
271
297
  .subscribe({
272
298
  next: items => {
273
- this.queryResultCacheSubject?.next(items);
299
+ this.#queryResultCacheSubject?.next(items);
274
300
  const optionsValueProperty = this.optionsValueProperty();
275
301
  const dataProvider = this.dataProvider();
276
302
  if (dataProvider && optionsValueProperty) {
277
- items.forEach(item => this.labelLookupService.storeEntry(dataProvider, optionsValueProperty, item[optionsValueProperty], item));
303
+ items.forEach(item => this.#labelLookupService.storeEntry(dataProvider, optionsValueProperty, item[optionsValueProperty], item));
278
304
  }
279
- this.setSuggestionsFromItems(items, query);
280
- if (isInit && !this._value) {
281
- this.selectFirstItem();
305
+ this.#setSuggestionsFromLookupItems(items, query);
306
+ if (isInit && !this.#value) {
307
+ this.#selectFirstItem();
282
308
  }
283
309
  },
284
310
  error: err => {
285
- this.setSuggestionsFromItems([], query);
311
+ this.#setSuggestionsFromLookupItems([], query);
286
312
  const error = fromSubscribeError(err, 'AutocompleteComponentError', {
287
313
  search: query,
288
314
  params: params
289
315
  });
290
- this.logger.log(error, getErrorLogLevel(error));
316
+ this.#logger.log(error, getErrorLogLevel(error));
291
317
  }
292
318
  });
293
319
  }
294
- else if (this.queryResultCacheSubject) {
295
- this.searchSubscription = this.queryResultCacheSubject.pipe(take(1)).subscribe(result => {
296
- this.setSuggestionsFromItems(result, query);
320
+ else if (this.#queryResultCacheSubject) {
321
+ this.#searchSubscription = this.#queryResultCacheSubject.pipe(take(1)).subscribe(result => {
322
+ this.#setSuggestionsFromLookupItems(result, query);
297
323
  });
298
324
  }
299
325
  }
300
- selectFirstItem() {
301
- if (!this.selectFirst() || this.multiselect())
302
- return;
303
- const suggestions = this.suggestions();
304
- if (suggestions.length > 0 && !this.userSelectedItem) {
305
- this.setValue(suggestions[0]);
306
- }
307
- else if (!this.userSelectedItem) {
308
- // handles the case if the user provides an input and de-focuses the input field before suggestions are loaded or if there are no suggestions at all
309
- this.setValue(null);
310
- }
311
- }
312
326
  /**
313
327
  * Triggered by user when selecting an item from an autocomplete suggestion list.
314
328
  */
315
329
  onSelect(event) {
316
330
  let newValue = event.value;
317
- if (this.multiselect() && Array.isArray(this._rawValue) && this._rawValue.length > 0) {
318
- newValue = [...this._rawValue, newValue];
331
+ if (this.multiselect() && Array.isArray(this.#valueItem) && this.#valueItem.length > 0) {
332
+ newValue = [...this.#valueItem, newValue];
319
333
  }
320
334
  else if (this.multiselect()) {
321
335
  newValue = [newValue];
322
336
  }
323
- this.setValue(newValue, true);
324
- this.isFocused = false;
337
+ this.#setValueItem(newValue, true);
338
+ this.#isFocused = false;
325
339
  }
326
340
  /**
327
341
  * Triggered by user when selecting an item from an autocomplete suggestion list.
328
342
  */
329
343
  onUnselect(event) {
330
344
  let newValue = null;
331
- if (this.multiselect() && Array.isArray(this._rawValue) && this._rawValue.length > 0) {
332
- const cmpProp = this.optionsValueProperty() ?? this.optionsTrackProperty();
333
- newValue = this._rawValue.filter(i => (cmpProp ? i[cmpProp] !== event.value[cmpProp] : i !== event.value));
345
+ if (this.multiselect() && Array.isArray(this.#valueItem) && this.#valueItem.length > 0) {
346
+ newValue = this.#valueItem.filter(i => i.__track !== event.value.__track);
334
347
  }
335
348
  else if (this.multiselect()) {
336
349
  newValue = [];
337
350
  }
338
- this.setValue(newValue, true);
339
- this.isFocused = false;
351
+ this.#setValueItem(newValue, true);
352
+ this.#isFocused = false;
340
353
  }
341
354
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
342
355
  onFocus(event) {
343
- this.isFocused = true;
356
+ this.#isFocused = true;
344
357
  }
345
358
  /**
346
359
  * calls the selectFirst item anytime the input field goes out of focus and if the suggestions panel is not displayed.
347
360
  */
348
361
  onBlur(event) {
349
- this.isFocused = false;
362
+ this.#isFocused = false;
350
363
  const inputSearchVal = this.primeAutocomplete()?.inputEL?.nativeElement?.value;
351
- if (this.autoClear() && this._value != null && (inputSearchVal == null || inputSearchVal === '')) {
352
- this.propagateValueChange(null);
364
+ if (this.autoClear() && this.#value != null && (inputSearchVal == null || inputSearchVal === '')) {
365
+ this.#propagateValueItemChange(null);
353
366
  }
354
- else if (!this.isPanelShown) {
355
- this.selectFirstItem();
367
+ else if (!this.#isPanelShown) {
368
+ this.#selectFirstItem();
356
369
  }
357
- this.onTouchedFn();
370
+ this.#onTouchedFn();
358
371
  this.blur.emit(event);
359
372
  }
360
- onShow() {
361
- this.isPanelShown = true;
373
+ onPanelShow() {
374
+ this.#isPanelShown = true;
362
375
  }
363
376
  /**
364
377
  * calls the selectFirst item anytime the suggestions panel is closed and input field isn't focused.
365
378
  */
366
- onHide() {
367
- this.isPanelShown = false;
368
- if (!this.isFocused) {
369
- this.selectFirstItem();
379
+ onPanelHide() {
380
+ this.#isPanelShown = false;
381
+ if (!this.#isFocused) {
382
+ this.#selectFirstItem();
370
383
  }
371
384
  }
372
385
  onClear() {
373
- if (this._value != null) {
374
- this.propagateValueChange(this.multiselect() ? [] : null);
386
+ if (this.#value != null) {
387
+ this.#propagateValueItemChange(this.multiselect() ? [] : null);
375
388
  }
376
389
  }
377
390
  registerOnChange(fn) {
378
- this.onChangeFn = fn;
391
+ this.#onChangeFn = fn;
379
392
  }
380
393
  registerOnTouched(fn) {
381
- this.onTouchedFn = fn;
394
+ this.#onTouchedFn = fn;
382
395
  }
383
396
  setDisabledState(isDisabled) {
384
- setTimeout(() => this._disabled.set(isDisabled));
397
+ setTimeout(() => this.#disabledWritable.set(isDisabled));
385
398
  }
386
399
  writeValue(value) {
387
- this.setItemsAndDataProvider();
400
+ this.#setItemsAndDataProvider();
388
401
  // write value immediately - it is important so that first select is not triggered!
389
- this._value = value;
390
- const optionsValuePropertyInit = this.optionsValuePropertyInit();
391
- if (optionsValuePropertyInit && value != null && (typeof value !== 'object' || (Array.isArray(value) && value?.length > 0))) {
402
+ this.#value = value;
403
+ const optionsValuePropertyInit = this.optionsValueProperty();
404
+ if (optionsValuePropertyInit && value != null && (typeof value !== 'object' || (Array.isArray(value) && value?.filter(v => v != null).length > 0))) {
392
405
  const isMultiValue = Array.isArray(value);
393
- const lookupValue = isMultiValue ? [...value] : [value];
394
- const matchedItems = lookupValue?.map(v => this.suggestions().find(i => v === i[optionsValuePropertyInit])).filter(Boolean);
395
- if (matchedItems && matchedItems.length === value?.length) {
396
- this.setValueFromWrite(isMultiValue ? matchedItems : matchedItems[0]);
406
+ const valueAsItemsArray = (isMultiValue ? [...value.filter(v => v != null)] : [value]).map(i => this.#createAutocompleteItem(i));
407
+ const matchedItems = valueAsItemsArray?.map(v => this.suggestions().find(i => v.__track === i.__track)).filter(Boolean);
408
+ if (matchedItems.length === valueAsItemsArray?.length) {
409
+ this.#setValueFromWrite(isMultiValue ? matchedItems : matchedItems[0]);
397
410
  }
398
411
  else {
399
- this.labelLookupService
400
- .getEntries(this.dataProvider(), this.dataProviderService, optionsValuePropertyInit, lookupValue)
412
+ this.#labelLookupService
413
+ .getEntries(this.dataProvider(), this.#dataProviderService, optionsValuePropertyInit, valueAsItemsArray.map(i => i.__track))
401
414
  .pipe(take(1))
402
415
  .subscribe({
403
416
  next: items => {
404
- const matchedItems = lookupValue?.map(v => items.find(i => v == i[optionsValuePropertyInit]) ?? this.#createObjFromValue(v));
405
- this.setValueFromWrite(isMultiValue ? matchedItems : matchedItems[0]);
417
+ // transform items to autocomplete items for comparation needs
418
+ const lookupAutocompleteItems = items.map(i => this.#createAutocompleteItem(i));
419
+ const matchedItems = valueAsItemsArray?.map((v, idx) => lookupAutocompleteItems.find(i => v.__track === i.__track)?.__original ??
420
+ this.#createValueLabelObjectFromOnlyValue(valueAsItemsArray[idx].__original));
421
+ this.#setValueFromWrite(isMultiValue ? matchedItems : matchedItems[0]);
406
422
  },
407
423
  error: () => {
408
- this.setValueFromWrite(isMultiValue ? this.#createObjFromValue(lookupValue[0]) : lookupValue?.map(v => this.#createObjFromValue(v)));
424
+ this.#setValueFromWrite(isMultiValue
425
+ ? this.#createValueLabelObjectFromOnlyValue(valueAsItemsArray[0].__original)
426
+ : valueAsItemsArray?.map(v => this.#createValueLabelObjectFromOnlyValue(v.__original)));
409
427
  }
410
428
  });
411
429
  }
412
430
  }
413
431
  else {
414
- this.setValueFromWrite(value);
432
+ this.#setValueFromWrite(value);
415
433
  }
416
434
  }
417
- #createObjFromValue(val) {
435
+ /**
436
+ * Transforms value and create fake object with value as value prop and label prop.
437
+ */
438
+ #createValueLabelObjectFromOnlyValue(val) {
418
439
  if (val == null) {
419
440
  return val;
420
441
  }
@@ -429,93 +450,116 @@ class AutocompleteComponent {
429
450
  }
430
451
  return obj;
431
452
  }
432
- setItemsAndDataProvider() {
433
- if (this.isInited) {
453
+ #setItemsAndDataProvider() {
454
+ if (this.#isInited) {
434
455
  return;
435
456
  }
436
457
  const dataProvider = this.dataProvider();
437
- this.dataProviderService = dataProvider.serviceType ? this.injector.get(dataProvider.serviceType) : null;
438
- this.isInited = true;
458
+ this.#dataProviderService = dataProvider.serviceType ? this.#injector.get(dataProvider.serviceType) : null;
459
+ this.#isInited = true;
439
460
  }
440
- setValueFromWrite(value) {
441
- if (value && this.optionsLabelTranslate()) {
442
- value = this.i18nPopulateItems([value], this.translate.instant(this.i18nGetItemsKeys([value])))[0];
461
+ /**
462
+ * Sets value from write. This must not be of type AutocompleteItem.
463
+ * @param value
464
+ * @private
465
+ */
466
+ #setValueFromWrite(value) {
467
+ // Normalize value to always be internal item
468
+ let normalizedValue = value;
469
+ if (Array.isArray(value)) {
470
+ normalizedValue = value.map(v => this.#createAutocompleteItem(v));
443
471
  }
444
- if (this.ngModelValue() == null && this._rawValue != null) {
472
+ else if (value != null) {
473
+ normalizedValue = this.#createAutocompleteItem(value);
474
+ }
475
+ if (this.ngModelValue() == null && this.#valueItem != null) {
445
476
  // value must first be set to synchronise states, then in next async cycle set to wanted null value
446
- this.ngModelValue.set(this._rawValue);
477
+ this.ngModelValue.set(this.#valueItem);
447
478
  setTimeout(() => {
448
- this.ngModelValue.set(value);
479
+ this.ngModelValue.set(normalizedValue);
449
480
  });
450
481
  }
451
482
  else {
452
- this.ngModelValue.set(value);
483
+ this.ngModelValue.set(normalizedValue);
453
484
  }
454
485
  }
455
- getLookup(params, query) {
456
- return toObservable(this.dataProvider().lookup(params, this.dataProviderService, query)).pipe(switchMap(items => {
457
- if (this.optionsLabelTranslate()) {
458
- const translatedItems = this.i18nGetItemsKeys(items);
459
- if (translatedItems.length === 0) {
460
- return of([]);
461
- }
462
- return this.translate.stream(translatedItems).pipe(map((translations) => this.i18nPopulateItems(items, translations)));
463
- }
464
- else {
465
- return of(items);
466
- }
467
- }));
468
- }
469
- i18nGetItemsKeys(items) {
470
- return items.map(item => (typeof item === 'object' && this.optionsLabelPropertyInit() ? item[this.optionsLabelPropertyInit()] : item));
471
- }
472
- i18nPopulateItems(items, i18nMap) {
473
- return items.map(item => {
474
- if (typeof item === 'object' && this.optionsLabelPropertyInit()) {
475
- const label = item[this.optionsLabelPropertyInit()];
476
- const translation = narrowI18nToTranslation(i18nMap, label);
477
- if (translation) {
478
- return { ...item, [this.optionsLabelProperty()]: translation };
479
- }
480
- return { ...item };
481
- }
482
- else {
483
- const translation = narrowI18nToTranslation(i18nMap, item);
484
- return {
485
- [this.optionsLabelProperty()]: translation ?? item,
486
- [this.optionsValueProperty()]: item
487
- };
488
- }
489
- });
486
+ #selectFirstItem() {
487
+ if (!this.selectFirst() || this.multiselect())
488
+ return;
489
+ const suggestions = this.suggestions();
490
+ if (suggestions.length > 0 && !this.#userSelectedItem) {
491
+ this.#setValueItem(suggestions[0]);
492
+ }
493
+ else if (!this.#userSelectedItem) {
494
+ // handles the case if the user provides an input and de-focuses the input field before suggestions are loaded or if there are no suggestions at all
495
+ this.#setValueItem(null);
496
+ }
490
497
  }
491
- setSuggestionsFromItems(items, query) {
492
- if (query && query !== this.currentQuery) {
498
+ #getLookup(params, query) {
499
+ return toObservable(this.dataProvider().lookup(params, this.#dataProviderService, query)).pipe(map(res => res.map(item => this.#createAutocompleteItem(item))));
500
+ }
501
+ #setSuggestionsFromLookupItems(items, query) {
502
+ if (query && query !== this.#currentQuery) {
493
503
  // Skip processing to avoid outdated queries during inline search updates.
494
504
  return;
495
505
  }
506
+ // Normalize items to always be objects
507
+ const autocompleteItems = items.map(i => this.#createAutocompleteItem(i));
496
508
  if (this.inlineSearch()) {
497
509
  const queryLowerCase = query?.toLowerCase() ?? '';
498
- const filteredItems = items.filter(i => {
499
- let itemLabel = i;
500
- const optionsLabelProperty = this.optionsLabelProperty();
501
- if (optionsLabelProperty && typeof i === 'object') {
502
- itemLabel = i[optionsLabelProperty];
503
- }
504
- if (itemLabel == null) {
505
- return queryLowerCase == null || !queryLowerCase.length;
506
- }
507
- if (typeof itemLabel !== 'string') {
508
- itemLabel = itemLabel.toString();
509
- }
510
- return itemLabel.toLowerCase().startsWith(queryLowerCase);
510
+ const filteredItems = autocompleteItems.filter(i => {
511
+ return i.__label.toLowerCase().startsWith(queryLowerCase);
511
512
  });
512
- this.suggestions.set([...filteredItems]);
513
- this.userSelectedItem = undefined;
513
+ this.#setSuggestionsWithCustomInput(filteredItems, query);
514
+ this.#userSelectedItem = undefined;
514
515
  }
515
516
  else {
516
- this.suggestions.set([...items]);
517
- this.userSelectedItem = undefined;
517
+ this.#setSuggestionsWithCustomInput(autocompleteItems, query);
518
+ this.#userSelectedItem = undefined;
519
+ }
520
+ }
521
+ #setSuggestionsWithCustomInput(items, query) {
522
+ // Mark items as selected or suggested
523
+ const currentValue = this.#valueItem;
524
+ // Directly modify items array instead of creating copies
525
+ items = items
526
+ .filter(item => item != null)
527
+ .map(item => {
528
+ let isSelected = false;
529
+ // Check if item is selected
530
+ if (currentValue != null) {
531
+ if (Array.isArray(currentValue)) {
532
+ isSelected = this.multiselect() ? currentValue.some(v => v.__track === item.__track) : false;
533
+ }
534
+ else {
535
+ isSelected = currentValue.__track === item.__track;
536
+ }
537
+ }
538
+ return {
539
+ ...item,
540
+ __isCustomInput: false,
541
+ __isSuggested: !isSelected,
542
+ __isSelected: isSelected
543
+ };
544
+ });
545
+ let finalItems = items;
546
+ // Add custom input as first item if allowCustomInput is enabled and query exists
547
+ if (this.allowInput() && query && query.length > 0) {
548
+ // Check if custom input already exists in items
549
+ const customInputExists = items.some(item => item.__label.toLowerCase() === query.toLowerCase());
550
+ if (!customInputExists) {
551
+ finalItems = [
552
+ {
553
+ ...this.#createAutocompleteItem(query),
554
+ __isCustom: true,
555
+ __isSuggested: false,
556
+ __isSelected: false
557
+ },
558
+ ...finalItems
559
+ ];
560
+ }
518
561
  }
562
+ this.suggestions.set(finalItems);
519
563
  }
520
564
  /**
521
565
  * Selects and sets new value.
@@ -523,16 +567,16 @@ class AutocompleteComponent {
523
567
  * @param value Represents the object value.
524
568
  * @param fromUser If set value is triggered from user.
525
569
  */
526
- setValue(value, fromUser = false) {
570
+ #setValueItem(value, fromUser = false) {
527
571
  if (fromUser) {
528
- this.userSelectedItem = value;
572
+ this.#userSelectedItem = value ?? undefined;
529
573
  }
530
574
  else {
531
575
  this.ngModelValue.set(value);
532
576
  }
533
- this.propagateValueChange(value);
577
+ this.#propagateValueItemChange(value);
534
578
  }
535
- trimValue(value) {
579
+ #trimSearchQuery(value) {
536
580
  switch (this.searchTrim()) {
537
581
  case 'start':
538
582
  return value?.trimStart();
@@ -544,42 +588,42 @@ class AutocompleteComponent {
544
588
  return value;
545
589
  }
546
590
  }
591
+ #createAutocompleteItem(item) {
592
+ return createAutocompleteItem(item, {
593
+ translate: this.#translate,
594
+ optionsTrackProperty: this.optionsTrackProperty(),
595
+ optionsValueProperty: this.optionsValueProperty(),
596
+ optionsLabelProperty: this.optionsLabelProperty(),
597
+ optionsLabelTranslate: this.optionsLabelTranslate()
598
+ });
599
+ }
547
600
  /**
548
- * Propagates final value to _value, on change fn and outputs.
601
+ * Propagates final value to #value, on change fn and outputs.
549
602
  */
550
- propagateValueChange(value) {
551
- this._value = this.convertValueWithOptionsValuePropSetting(value);
552
- this._rawValue = value;
553
- this.onChangeFn(this._value);
554
- this.valueChange.emit(this._value);
555
- }
556
- convertValueWithOptionsValuePropSetting(value) {
557
- const optionsValueProperty = this.optionsValueProperty();
558
- if (!optionsValueProperty) {
559
- return value;
560
- }
561
- if (this.multiselect() && Array.isArray(value)) {
562
- return value.map((item) => {
563
- if (item && typeof item === 'object') {
564
- return item[optionsValueProperty];
565
- }
566
- return null;
567
- });
603
+ #propagateValueItemChange(value) {
604
+ this.#value = this.#getValueFromItem(value);
605
+ this.#valueItem = value;
606
+ this.#onChangeFn(this.#value);
607
+ this.valueChange.emit(this.#value);
608
+ }
609
+ #getValueFromItem(item) {
610
+ if (item == null) {
611
+ return item;
568
612
  }
569
- else if (value && typeof value === 'object') {
570
- return value[optionsValueProperty];
613
+ else if (Array.isArray(item)) {
614
+ return this.multiselect() ? item.map(item => item.__value) : [];
571
615
  }
572
616
  else {
573
- return value;
617
+ return item?.__value;
574
618
  }
575
619
  }
576
620
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
577
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AutocompleteComponent, isStandalone: true, selector: "mng-autocomplete", inputs: { dataProvider: { classPropertyName: "dataProvider", publicName: "dataProvider", isSignal: true, isRequired: true, transformFunction: null }, optionsTrackProperty: { classPropertyName: "optionsTrackProperty", publicName: "optionsTrackProperty", isSignal: true, isRequired: false, transformFunction: null }, optionsValuePropertyInit: { classPropertyName: "optionsValuePropertyInit", publicName: "optionsValueProperty", isSignal: true, isRequired: false, transformFunction: null }, optionsLabelPropertyInit: { classPropertyName: "optionsLabelPropertyInit", publicName: "optionsLabelProperty", isSignal: true, isRequired: false, transformFunction: null }, optionsLabelTranslate: { classPropertyName: "optionsLabelTranslate", publicName: "optionsLabelTranslate", isSignal: true, isRequired: false, transformFunction: null }, inlineSearch: { classPropertyName: "inlineSearch", publicName: "inlineSearch", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, dropdownClassName: { classPropertyName: "dropdownClassName", publicName: "dropdownClassName", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, autoClear: { classPropertyName: "autoClear", publicName: "autoClear", isSignal: true, isRequired: false, transformFunction: null }, selectFirst: { classPropertyName: "selectFirst", publicName: "selectFirst", isSignal: true, isRequired: false, transformFunction: null }, searchTrim: { classPropertyName: "searchTrim", publicName: "searchTrim", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, templates: { classPropertyName: "templates", publicName: "templates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur" }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], viewQueries: [{ propertyName: "primeAutocomplete", first: true, predicate: AutoComplete, descendants: true, isSignal: true }], ngImport: i0, template: "<p-inputgroup [class]=\"{'has-prepends': prependTemplates().length > 0}\">\n @for (pt of prependTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"pt.template\"></ng-container>\n </p-inputgroup-addon>\n }\n <p-autoComplete\n *mngRerender=\"multiselect()\"\n [placeholder]=\"placeholder()\"\n [dropdown]=\"true\"\n [dataKey]=\"optionsTrackProperty()\"\n [optionLabel]=\"optionsLabelProperty()\"\n [suggestions]=\"suggestions()\"\n [multiple]=\"multiselect()\"\n [showEmptyMessage]=\"true\"\n [emptyMessage]=\"'mngAutocomplete.noMatches' | translate\"\n [class]=\"className()\"\n [panelStyleClass]=\"dropdownClassName()\"\n [minQueryLength]=\"openOnFocus() ? 0 : 1\"\n [showClear]=\"showClear()\"\n [forceSelection]=\"autoClear()\"\n [disabled]=\"disabled()\"\n [completeOnFocus]=\"openOnFocus()\"\n (completeMethod)=\"onSearch($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onFocus)=\"onFocus($event)\"\n (onBlur)=\"onBlur($event)\"\n (onClear)=\"onClear()\"\n (onShow)=\"onShow()\"\n (onHide)=\"onHide()\"\n appendTo=\"body\"\n dropdownMode=\"current\" />\n @for (at of appendTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"at.template\"></ng-container>\n </p-inputgroup-addon>\n }\n</p-inputgroup>\n", styles: [".has-prepends .p-autocomplete-input-multiple{border-top-left-radius:0!important;border-bottom-left-radius:0!important}p-inputgroup{font-size:1rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "component", type: InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "component", type: InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RerenderDirective, selector: "[mngRerender]", inputs: ["mngRerender"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
621
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: AutocompleteComponent, isStandalone: true, selector: "mng-autocomplete", inputs: { dataProvider: { classPropertyName: "dataProvider", publicName: "dataProvider", isSignal: true, isRequired: true, transformFunction: null }, optionsTrackProperty: { classPropertyName: "optionsTrackProperty", publicName: "optionsTrackProperty", isSignal: true, isRequired: false, transformFunction: null }, optionsValueProperty: { classPropertyName: "optionsValueProperty", publicName: "optionsValueProperty", isSignal: true, isRequired: false, transformFunction: null }, optionsLabelProperty: { classPropertyName: "optionsLabelProperty", publicName: "optionsLabelProperty", isSignal: true, isRequired: false, transformFunction: null }, optionsLabelTranslate: { classPropertyName: "optionsLabelTranslate", publicName: "optionsLabelTranslate", isSignal: true, isRequired: false, transformFunction: null }, inlineSearch: { classPropertyName: "inlineSearch", publicName: "inlineSearch", isSignal: true, isRequired: false, transformFunction: null }, openOnFocus: { classPropertyName: "openOnFocus", publicName: "openOnFocus", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, dropdownClassName: { classPropertyName: "dropdownClassName", publicName: "dropdownClassName", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, autoClear: { classPropertyName: "autoClear", publicName: "autoClear", isSignal: true, isRequired: false, transformFunction: null }, selectFirst: { classPropertyName: "selectFirst", publicName: "selectFirst", isSignal: true, isRequired: false, transformFunction: null }, allowInput: { classPropertyName: "allowInput", publicName: "allowInput", isSignal: true, isRequired: false, transformFunction: null }, searchTrim: { classPropertyName: "searchTrim", publicName: "searchTrim", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, templates: { classPropertyName: "templates", publicName: "templates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur" }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], viewQueries: [{ propertyName: "primeAutocomplete", first: true, predicate: AutoComplete, descendants: true, isSignal: true }], ngImport: i0, template: "<p-inputgroup [class]=\"{'has-prepends': prependTemplates().length > 0}\">\n @for (pt of prependTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"pt.template\"></ng-container>\n </p-inputgroup-addon>\n }\n <p-autoComplete\n *mngRerender=\"multiselect()\"\n [placeholder]=\"placeholder()\"\n [dropdown]=\"true\"\n dataKey=\"__track\"\n optionLabel=\"__label\"\n optionValue=\"__value\"\n [suggestions]=\"suggestions()\"\n [multiple]=\"multiselect()\"\n [showEmptyMessage]=\"true\"\n [emptyMessage]=\"'mngAutocomplete.noMatches' | translate\"\n [class]=\"className()\"\n [panelStyleClass]=\"dropdownClassName()\"\n [minQueryLength]=\"openOnFocus() ? 0 : 1\"\n [showClear]=\"showClear()\"\n [forceSelection]=\"autoClear() || allowInput()\"\n autoOptionFocus=\"true\"\n [selectOnFocus]=\"allowInput()\"\n [disabled]=\"disabled()\"\n [completeOnFocus]=\"openOnFocus()\"\n (completeMethod)=\"onSearch($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onFocus)=\"onFocus($event)\"\n (onBlur)=\"onBlur($event)\"\n (onClear)=\"onClear()\"\n (onShow)=\"onPanelShow()\"\n (onHide)=\"onPanelHide()\"\n appendTo=\"body\"\n dropdownMode=\"current\">\n <ng-template let-item #item>\n <div style=\"display: flex; align-items: center; justify-content: space-between; width: 100%\">\n <span>{{ item.__label }}</span>\n @if (allowInput()) {\n <div style=\"display: flex; gap: 0.25rem\">\n @if (item.__isSelected) {\n <p-tag [value]=\"'general.selected' | translate\" severity=\"success\" />\n } @else if (item.__isSuggested) {\n <p-tag [value]=\"'general.suggested' | translate\" />\n } @else if (item.__isCustom) {\n <p-tag [value]=\"'general.custom' | translate\" severity=\"warn\" />\n }\n </div>\n }\n </div>\n </ng-template>\n </p-autoComplete>\n @for (at of appendTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"at.template\"></ng-container>\n </p-inputgroup-addon>\n }\n</p-inputgroup>\n", styles: ["mng-autocomplete .has-prepends .p-autocomplete-input-multiple{border-top-left-radius:0!important;border-bottom-left-radius:0!important}mng-autocomplete p-inputgroup{font-size:1rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "component", type: InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "component", type: InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RerenderDirective, selector: "[mngRerender]", inputs: ["mngRerender"] }, { kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
578
622
  }
579
623
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: AutocompleteComponent, decorators: [{
580
624
  type: Component,
581
- args: [{ selector: 'mng-autocomplete', encapsulation: ViewEncapsulation.None, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], imports: [TranslatePipe, FormsModule, AutoComplete, InputGroup, InputGroupAddon, NgTemplateOutlet, RerenderDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p-inputgroup [class]=\"{'has-prepends': prependTemplates().length > 0}\">\n @for (pt of prependTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"pt.template\"></ng-container>\n </p-inputgroup-addon>\n }\n <p-autoComplete\n *mngRerender=\"multiselect()\"\n [placeholder]=\"placeholder()\"\n [dropdown]=\"true\"\n [dataKey]=\"optionsTrackProperty()\"\n [optionLabel]=\"optionsLabelProperty()\"\n [suggestions]=\"suggestions()\"\n [multiple]=\"multiselect()\"\n [showEmptyMessage]=\"true\"\n [emptyMessage]=\"'mngAutocomplete.noMatches' | translate\"\n [class]=\"className()\"\n [panelStyleClass]=\"dropdownClassName()\"\n [minQueryLength]=\"openOnFocus() ? 0 : 1\"\n [showClear]=\"showClear()\"\n [forceSelection]=\"autoClear()\"\n [disabled]=\"disabled()\"\n [completeOnFocus]=\"openOnFocus()\"\n (completeMethod)=\"onSearch($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onFocus)=\"onFocus($event)\"\n (onBlur)=\"onBlur($event)\"\n (onClear)=\"onClear()\"\n (onShow)=\"onShow()\"\n (onHide)=\"onHide()\"\n appendTo=\"body\"\n dropdownMode=\"current\" />\n @for (at of appendTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"at.template\"></ng-container>\n </p-inputgroup-addon>\n }\n</p-inputgroup>\n", styles: [".has-prepends .p-autocomplete-input-multiple{border-top-left-radius:0!important;border-bottom-left-radius:0!important}p-inputgroup{font-size:1rem}\n"] }]
582
- }], ctorParameters: () => [], propDecorators: { dataProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataProvider", required: true }] }], optionsTrackProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsTrackProperty", required: false }] }], optionsValuePropertyInit: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsValueProperty", required: false }] }], optionsLabelPropertyInit: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsLabelProperty", required: false }] }], optionsLabelTranslate: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsLabelTranslate", required: false }] }], inlineSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "inlineSearch", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnFocus", required: false }] }], multiselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiselect", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], dropdownClassName: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownClassName", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], autoClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClear", required: false }] }], selectFirst: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectFirst", required: false }] }], searchTrim: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTrim", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], templates: [{ type: i0.Input, args: [{ isSignal: true, alias: "templates", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], blur: [{ type: i0.Output, args: ["blur"] }], primeAutocomplete: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AutoComplete), { isSignal: true }] }] } });
625
+ args: [{ selector: 'mng-autocomplete', encapsulation: ViewEncapsulation.None, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], imports: [TranslatePipe, FormsModule, AutoComplete, InputGroup, InputGroupAddon, NgTemplateOutlet, RerenderDirective, Tag], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p-inputgroup [class]=\"{'has-prepends': prependTemplates().length > 0}\">\n @for (pt of prependTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"pt.template\"></ng-container>\n </p-inputgroup-addon>\n }\n <p-autoComplete\n *mngRerender=\"multiselect()\"\n [placeholder]=\"placeholder()\"\n [dropdown]=\"true\"\n dataKey=\"__track\"\n optionLabel=\"__label\"\n optionValue=\"__value\"\n [suggestions]=\"suggestions()\"\n [multiple]=\"multiselect()\"\n [showEmptyMessage]=\"true\"\n [emptyMessage]=\"'mngAutocomplete.noMatches' | translate\"\n [class]=\"className()\"\n [panelStyleClass]=\"dropdownClassName()\"\n [minQueryLength]=\"openOnFocus() ? 0 : 1\"\n [showClear]=\"showClear()\"\n [forceSelection]=\"autoClear() || allowInput()\"\n autoOptionFocus=\"true\"\n [selectOnFocus]=\"allowInput()\"\n [disabled]=\"disabled()\"\n [completeOnFocus]=\"openOnFocus()\"\n (completeMethod)=\"onSearch($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onFocus)=\"onFocus($event)\"\n (onBlur)=\"onBlur($event)\"\n (onClear)=\"onClear()\"\n (onShow)=\"onPanelShow()\"\n (onHide)=\"onPanelHide()\"\n appendTo=\"body\"\n dropdownMode=\"current\">\n <ng-template let-item #item>\n <div style=\"display: flex; align-items: center; justify-content: space-between; width: 100%\">\n <span>{{ item.__label }}</span>\n @if (allowInput()) {\n <div style=\"display: flex; gap: 0.25rem\">\n @if (item.__isSelected) {\n <p-tag [value]=\"'general.selected' | translate\" severity=\"success\" />\n } @else if (item.__isSuggested) {\n <p-tag [value]=\"'general.suggested' | translate\" />\n } @else if (item.__isCustom) {\n <p-tag [value]=\"'general.custom' | translate\" severity=\"warn\" />\n }\n </div>\n }\n </div>\n </ng-template>\n </p-autoComplete>\n @for (at of appendTemplates(); track $index) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"at.template\"></ng-container>\n </p-inputgroup-addon>\n }\n</p-inputgroup>\n", styles: ["mng-autocomplete .has-prepends .p-autocomplete-input-multiple{border-top-left-radius:0!important;border-bottom-left-radius:0!important}mng-autocomplete p-inputgroup{font-size:1rem}\n"] }]
626
+ }], ctorParameters: () => [], propDecorators: { dataProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataProvider", required: true }] }], optionsTrackProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsTrackProperty", required: false }] }], optionsValueProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsValueProperty", required: false }] }], optionsLabelProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsLabelProperty", required: false }] }], optionsLabelTranslate: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsLabelTranslate", required: false }] }], inlineSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "inlineSearch", required: false }] }], openOnFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnFocus", required: false }] }], multiselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiselect", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], dropdownClassName: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropdownClassName", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], autoClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClear", required: false }] }], selectFirst: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectFirst", required: false }] }], allowInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowInput", required: false }] }], searchTrim: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTrim", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], templates: [{ type: i0.Input, args: [{ isSignal: true, alias: "templates", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], blur: [{ type: i0.Output, args: ["blur"] }], primeAutocomplete: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AutoComplete), { isSignal: true }] }] } });
583
627
 
584
628
  const DATETIME_PICKER_VALUE_ACCESSOR = {
585
629
  provide: NG_VALUE_ACCESSOR,
@@ -1227,7 +1271,7 @@ class DropdownComponent {
1227
1271
  }
1228
1272
  this.setItems(res, query);
1229
1273
  this._loading.set(false);
1230
- this.selectFirstItem(); // only selects first item if selectFirstItemInput is set accordingly
1274
+ this.selectFirstOrRefreshOption(); // only selects first item if selectFirstItemInput is set accordingly
1231
1275
  this.adjustValueOnItemsValuePropertyTypeMismatch();
1232
1276
  },
1233
1277
  error: err => {
@@ -1307,7 +1351,7 @@ class DropdownComponent {
1307
1351
  this.propagateValueChange(primeMultiselect.value);
1308
1352
  }
1309
1353
  }
1310
- selectFirstItem() {
1354
+ selectFirstOrRefreshOption() {
1311
1355
  if (this.firstTimeSettingItems && this.items().length > 0 && this.selectFirstItemInput() && !this._value) {
1312
1356
  const optionsValueProperty = this.optionsValueProperty();
1313
1357
  const value = optionsValueProperty ? this.items()[0][optionsValueProperty] : this.items()[0];
@@ -1315,6 +1359,19 @@ class DropdownComponent {
1315
1359
  this.firstTimeSettingItems = false;
1316
1360
  this.propagateValueChange(value);
1317
1361
  }
1362
+ else {
1363
+ const valueProperty = this.optionsValueProperty();
1364
+ const labelProperty = this.optionsLabelProperty();
1365
+ if (this._value == null || !labelProperty || this.items().length === 0) {
1366
+ return;
1367
+ }
1368
+ if (valueProperty) {
1369
+ const selectedOption = this.items().find(item => item[valueProperty] === this._value);
1370
+ if (selectedOption) {
1371
+ this.ngModelValue.set(selectedOption[valueProperty]);
1372
+ }
1373
+ }
1374
+ }
1318
1375
  }
1319
1376
  transformItems(items) {
1320
1377
  if (this.optionsLabelTranslate()) {