novo-elements 13.1.0-next.4 → 13.1.0-next.5

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.
@@ -14,7 +14,11 @@ declare class GooglePlacesService {
14
14
  private platformId;
15
15
  private _global;
16
16
  private _localStorageService;
17
+ private mapsLoad?;
18
+ private mapsLoadKey?;
17
19
  constructor(_http: HttpClient, platformId: Object, _global: GlobalRef, _localStorageService: LocalStorageService);
20
+ loadGoogleMaps(settings: PlacesSettings): Promise<void>;
21
+ private injectGoogleMapsScript;
18
22
  getPredictions(url: string, query: string, sessionToken?: string): Promise<any>;
19
23
  getLatLngDetail(url: string, lat: number, lng: number): Promise<any>;
20
24
  getPlaceDetails(url: string, placeId: string, sessionToken?: string): Promise<any>;
@@ -55,6 +59,10 @@ interface PlacesSettings {
55
59
  currentLocIconUrl?: string;
56
60
  searchIconUrl?: string;
57
61
  locationIconUrl?: string;
62
+ /** Bullhorn-managed key; when set, the library lazy-loads the Maps JS SDK with it instead of relying on a host script tag. */
63
+ googleApiKey?: string;
64
+ /** Extra Maps JS loader query params, merged over the defaults (libraries=places, loading=async). */
65
+ googleMapsLoaderParams?: Record<string, string>;
58
66
  }
59
67
  /** Normalized address prediction; raw provider records are mapped into this via normalizePrediction. */
60
68
  interface AddressLookupPrediction {
@@ -72,6 +80,7 @@ declare class PlacesListComponent extends BasePickerResults implements OnInit, O
72
80
  private _global;
73
81
  private _googlePlacesService;
74
82
  private cdr;
83
+ private addressConfig;
75
84
  private static readonly SESSION_TOKEN_TIMEOUT_MS;
76
85
  userSettings: PlacesSettings;
77
86
  termChange: EventEmitter<any>;
@@ -94,7 +103,7 @@ declare class PlacesListComponent extends BasePickerResults implements OnInit, O
94
103
  model: any;
95
104
  onModelChange: Function;
96
105
  onModelTouched: Function;
97
- constructor(platformId: Object, _elmRef: ElementRef, _global: GlobalRef, _googlePlacesService: GooglePlacesService, cdr: ChangeDetectorRef);
106
+ constructor(platformId: Object, _elmRef: ElementRef, _global: GlobalRef, _googlePlacesService: GooglePlacesService, cdr: ChangeDetectorRef, addressConfig?: PlacesSettings);
98
107
  ngOnInit(): any;
99
108
  ngOnChanges(): any;
100
109
  writeValue(model: any): void;
@@ -125,7 +134,7 @@ declare class PlacesListComponent extends BasePickerResults implements OnInit, O
125
134
  private getPlaceLocationInfo;
126
135
  private setRecentLocation;
127
136
  private getRecentLocations;
128
- static ɵfac: i0.ɵɵFactoryDeclaration<PlacesListComponent, never>;
137
+ static ɵfac: i0.ɵɵFactoryDeclaration<PlacesListComponent, [null, null, null, null, null, { optional: true; }]>;
129
138
  static ɵcmp: i0.ɵɵComponentDeclaration<PlacesListComponent, "google-places-list", never, { "userSettings": { "alias": "userSettings"; "required": false; }; }, { "termChange": "termChange"; "select": "select"; "matchesUpdated": "matchesUpdated"; }, never, never, false, never>;
130
139
  }
131
140
 
@@ -1,40 +1,40 @@
1
1
  import * as i0 from '@angular/core';
2
- import { TemplateRef, ViewContainerRef, OnInit, OnChanges, AfterContentInit, AfterViewInit, OnDestroy, ElementRef, ChangeDetectorRef, SimpleChanges, QueryList, InputSignal, Signal, AfterContentChecked, InjectionToken } from '@angular/core';
3
- import * as i15 from '@angular/forms';
2
+ import { TemplateRef, ViewContainerRef, OnInit, OnChanges, AfterContentInit, AfterViewInit, OnDestroy, ElementRef, ChangeDetectorRef, SimpleChanges, QueryList, InputSignal, Signal, AfterContentChecked, PipeTransform, InjectionToken } from '@angular/core';
3
+ import * as i16 from '@angular/forms';
4
4
  import { FormGroup, FormControl, ControlContainer, FormControlName, UntypedFormGroup, AbstractControl, FormBuilder, FormArray } from '@angular/forms';
5
5
  import { NovoLabelService } from 'novo-elements/services';
6
6
  import { Subject, Subscription } from 'rxjs';
7
7
  import { Day } from 'date-fns';
8
- import * as i25 from 'novo-elements/elements/field';
8
+ import * as i26 from 'novo-elements/elements/field';
9
9
  import { NovoPickerToggleElement } from 'novo-elements/elements/field';
10
- import * as i18 from 'novo-elements/elements/places';
11
- import { PlacesListComponent } from 'novo-elements/elements/places';
12
- import * as i23 from 'novo-elements/elements/select';
10
+ import * as i19 from 'novo-elements/elements/places';
11
+ import { PlacesListComponent, PlacesSettings } from 'novo-elements/elements/places';
12
+ import * as i24 from 'novo-elements/elements/select';
13
13
  import { NovoSelectElement } from 'novo-elements/elements/select';
14
- import * as i28 from 'novo-elements/elements/tabbed-group-picker';
14
+ import * as i29 from 'novo-elements/elements/tabbed-group-picker';
15
15
  import { NovoTabbedGroupPickerElement, TabbedGroupPickerTab, TabbedGroupPickerButtonConfig } from 'novo-elements/elements/tabbed-group-picker';
16
- import * as i14 from '@angular/common';
17
- import * as i16 from '@angular/cdk/drag-drop';
18
- import * as i17 from '@angular/cdk/table';
19
- import * as i19 from 'novo-elements/elements/autocomplete';
20
- import * as i20 from 'novo-elements/elements/button';
21
- import * as i21 from 'novo-elements/elements/common';
22
- import * as i22 from 'novo-elements/elements/form';
23
- import * as i24 from 'novo-elements/elements/non-ideal-state';
24
- import * as i26 from 'novo-elements/elements/flex';
25
- import * as i27 from 'novo-elements/elements/tabs';
26
- import * as i29 from 'novo-elements/elements/loading';
27
- import * as i30 from 'novo-elements/elements/card';
28
- import * as i31 from 'novo-elements/elements/date-picker';
29
- import * as i32 from 'novo-elements/elements/date-time-picker';
30
- import * as i33 from 'novo-elements/elements/icon';
31
- import * as i34 from 'novo-elements/elements/radio';
32
- import * as i35 from 'novo-elements/elements/search';
33
- import * as i36 from 'novo-elements/elements/switch';
34
- import * as i37 from 'novo-elements/elements/chips';
35
- import * as i38 from 'novo-elements/elements/select-search';
36
- import * as i39 from 'novo-elements/elements/dropdown';
37
- import * as i40 from 'novo-elements/elements/tooltip';
16
+ import * as i15 from '@angular/common';
17
+ import * as i17 from '@angular/cdk/drag-drop';
18
+ import * as i18 from '@angular/cdk/table';
19
+ import * as i20 from 'novo-elements/elements/autocomplete';
20
+ import * as i21 from 'novo-elements/elements/button';
21
+ import * as i22 from 'novo-elements/elements/common';
22
+ import * as i23 from 'novo-elements/elements/form';
23
+ import * as i25 from 'novo-elements/elements/non-ideal-state';
24
+ import * as i27 from 'novo-elements/elements/flex';
25
+ import * as i28 from 'novo-elements/elements/tabs';
26
+ import * as i30 from 'novo-elements/elements/loading';
27
+ import * as i31 from 'novo-elements/elements/card';
28
+ import * as i32 from 'novo-elements/elements/date-picker';
29
+ import * as i33 from 'novo-elements/elements/date-time-picker';
30
+ import * as i34 from 'novo-elements/elements/icon';
31
+ import * as i35 from 'novo-elements/elements/radio';
32
+ import * as i36 from 'novo-elements/elements/search';
33
+ import * as i37 from 'novo-elements/elements/switch';
34
+ import * as i38 from 'novo-elements/elements/chips';
35
+ import * as i39 from 'novo-elements/elements/select-search';
36
+ import * as i40 from 'novo-elements/elements/dropdown';
37
+ import * as i41 from 'novo-elements/elements/tooltip';
38
38
 
39
39
  /** Base interface for a condidation template directives. */
40
40
  interface ConditionDef {
@@ -176,15 +176,35 @@ interface FieldConfig<T extends BaseFieldDef> {
176
176
  find: (name: string) => T;
177
177
  }
178
178
  interface AddressData {
179
- address_components: AddressComponent[];
180
- formatted_address: string;
181
- geometry: AddressGeometry;
179
+ address_components?: AddressComponent[];
180
+ formatted_address?: string;
181
+ geometry?: AddressGeometry;
182
182
  name?: string;
183
- place_id: string;
183
+ place_id?: string;
184
+ address1?: string;
185
+ address2?: string;
186
+ city?: string;
187
+ state?: string;
188
+ zip?: string;
189
+ countryName?: string;
190
+ countryCode?: string;
191
+ formattedAddress?: string;
192
+ location?: AddressGeoPoint;
193
+ viewport?: AddressDetailViewport;
194
+ referenceId?: string;
195
+ postalCodes?: string[];
184
196
  radius?: AddressRadius;
185
197
  postal_codes?: string[];
186
198
  types?: string[];
187
199
  }
200
+ interface AddressGeoPoint {
201
+ latitude: number;
202
+ longitude: number;
203
+ }
204
+ interface AddressDetailViewport {
205
+ northeast: AddressGeoPoint;
206
+ southwest: AddressGeoPoint;
207
+ }
188
208
  interface AddressRadius {
189
209
  value: number;
190
210
  units: AddressRadiusUnitsName;
@@ -431,6 +451,7 @@ declare class NovoDefaultAddressConditionDef extends AbstractConditionFieldDef i
431
451
  term: string;
432
452
  private _addressChangesSubscription;
433
453
  element: ElementRef<any>;
454
+ protected readonly addressConfig: PlacesSettings;
434
455
  constructor(labelService: NovoLabelService);
435
456
  ngOnDestroy(): void;
436
457
  onKeyup(event: any, viewIndex: any): void;
@@ -629,9 +650,19 @@ declare class CriteriaBuilderComponent implements OnInit, OnDestroy, AfterConten
629
650
  static ɵcmp: i0.ɵɵComponentDeclaration<CriteriaBuilderComponent, "novo-criteria-builder", never, { "config": { "alias": "config"; "required": false; }; "controlName": { "alias": "controlName"; "required": false; }; "allowedGroupings": { "alias": "allowedGroupings"; "required": false; }; "editTypeFn": { "alias": "editTypeFn"; "required": false; }; "addressConfig": { "alias": "addressConfig"; "required": false; }; "dateConfig": { "alias": "dateConfig"; "required": false; }; "canBeEmpty": { "alias": "canBeEmpty"; "required": false; }; "HideFirstOperator": { "alias": "hideFirstOperator"; "required": false; }; }, {}, ["_contentFieldDefs"], never, false, never>;
630
651
  }
631
652
 
653
+ /**
654
+ * Resolves a display label from an address value. Google client-SDK results use formatted_address;
655
+ * address-search-service results use formattedAddress.
656
+ */
657
+ declare class AddressLabelPipe implements PipeTransform {
658
+ transform(item: AddressData): string;
659
+ static ɵfac: i0.ɵɵFactoryDeclaration<AddressLabelPipe, never>;
660
+ static ɵpipe: i0.ɵɵPipeDeclaration<AddressLabelPipe, "addressLabel", false>;
661
+ }
662
+
632
663
  declare class NovoQueryBuilderModule {
633
664
  static ɵfac: i0.ɵɵFactoryDeclaration<NovoQueryBuilderModule, never>;
634
- static ɵmod: i0.ɵɵNgModuleDeclaration<NovoQueryBuilderModule, [typeof CriteriaBuilderComponent, typeof ConditionBuilderComponent, typeof ConditionInputOutlet, typeof ConditionOperatorOutlet, typeof ConditionGroupComponent, typeof NovoDefaultAddressConditionDef, typeof NovoDefaultBooleanConditionDef, typeof NovoDefaultDateConditionDef, typeof NovoDefaultDateTimeConditionDef, typeof NovoConditionOperatorsDef, typeof NovoConditionInputDef, typeof NovoConditionFieldDef, typeof NovoDefaultStringConditionDef, typeof NovoDefaultNumberConditionDef, typeof NovoDefaultIdConditionDef, typeof NovoDefaultPickerConditionDef, typeof NovoConditionTemplatesComponent], [typeof i14.CommonModule, typeof i15.FormsModule, typeof i15.ReactiveFormsModule, typeof i16.DragDropModule, typeof i17.CdkTableModule, typeof i18.GooglePlacesModule, typeof i19.NovoAutoCompleteModule, typeof i20.NovoButtonModule, typeof i21.NovoCommonModule, typeof i22.NovoFormModule, typeof i23.NovoSelectModule, typeof i24.NovoNonIdealStateModule, typeof i25.NovoFieldModule, typeof i21.NovoOptionModule, typeof i26.NovoFlexModule, typeof i27.NovoTabModule, typeof i28.NovoTabbedGroupPickerModule, typeof i29.NovoLoadingModule, typeof i30.NovoCardModule, typeof i31.NovoDatePickerModule, typeof i32.NovoDateTimePickerModule, typeof i33.NovoIconModule, typeof i21.NovoOverlayModule, typeof i34.NovoRadioModule, typeof i35.NovoSearchBoxModule, typeof i36.NovoSwitchModule, typeof i37.NovoChipsModule, typeof i38.NovoSelectSearchModule, typeof i39.NovoDropdownModule, typeof i22.NovoFormExtrasModule, typeof i40.NovoTooltipModule], [typeof CriteriaBuilderComponent, typeof ConditionBuilderComponent, typeof NovoDefaultAddressConditionDef, typeof NovoDefaultBooleanConditionDef, typeof NovoDefaultDateConditionDef, typeof NovoDefaultDateTimeConditionDef, typeof NovoConditionOperatorsDef, typeof NovoConditionInputDef, typeof NovoConditionFieldDef, typeof NovoDefaultStringConditionDef, typeof NovoDefaultNumberConditionDef, typeof NovoDefaultIdConditionDef, typeof NovoDefaultPickerConditionDef, typeof NovoConditionTemplatesComponent]>;
665
+ static ɵmod: i0.ɵɵNgModuleDeclaration<NovoQueryBuilderModule, [typeof AddressLabelPipe, typeof CriteriaBuilderComponent, typeof ConditionBuilderComponent, typeof ConditionInputOutlet, typeof ConditionOperatorOutlet, typeof ConditionGroupComponent, typeof NovoDefaultAddressConditionDef, typeof NovoDefaultBooleanConditionDef, typeof NovoDefaultDateConditionDef, typeof NovoDefaultDateTimeConditionDef, typeof NovoConditionOperatorsDef, typeof NovoConditionInputDef, typeof NovoConditionFieldDef, typeof NovoDefaultStringConditionDef, typeof NovoDefaultNumberConditionDef, typeof NovoDefaultIdConditionDef, typeof NovoDefaultPickerConditionDef, typeof NovoConditionTemplatesComponent], [typeof i15.CommonModule, typeof i16.FormsModule, typeof i16.ReactiveFormsModule, typeof i17.DragDropModule, typeof i18.CdkTableModule, typeof i19.GooglePlacesModule, typeof i20.NovoAutoCompleteModule, typeof i21.NovoButtonModule, typeof i22.NovoCommonModule, typeof i23.NovoFormModule, typeof i24.NovoSelectModule, typeof i25.NovoNonIdealStateModule, typeof i26.NovoFieldModule, typeof i22.NovoOptionModule, typeof i27.NovoFlexModule, typeof i28.NovoTabModule, typeof i29.NovoTabbedGroupPickerModule, typeof i30.NovoLoadingModule, typeof i31.NovoCardModule, typeof i32.NovoDatePickerModule, typeof i33.NovoDateTimePickerModule, typeof i34.NovoIconModule, typeof i22.NovoOverlayModule, typeof i35.NovoRadioModule, typeof i36.NovoSearchBoxModule, typeof i37.NovoSwitchModule, typeof i38.NovoChipsModule, typeof i39.NovoSelectSearchModule, typeof i40.NovoDropdownModule, typeof i23.NovoFormExtrasModule, typeof i41.NovoTooltipModule], [typeof CriteriaBuilderComponent, typeof ConditionBuilderComponent, typeof NovoDefaultAddressConditionDef, typeof NovoDefaultBooleanConditionDef, typeof NovoDefaultDateConditionDef, typeof NovoDefaultDateTimeConditionDef, typeof NovoConditionOperatorsDef, typeof NovoConditionInputDef, typeof NovoConditionFieldDef, typeof NovoDefaultStringConditionDef, typeof NovoDefaultNumberConditionDef, typeof NovoDefaultIdConditionDef, typeof NovoDefaultPickerConditionDef, typeof NovoConditionTemplatesComponent]>;
635
666
  static ɵinj: i0.ɵɵInjectorDeclaration<NovoQueryBuilderModule>;
636
667
  }
637
668
 
@@ -640,4 +671,4 @@ declare const NOVO_CRITERIA_BUILDER: InjectionToken<any>;
640
671
  declare const NOVO_CONDITION_BUILDER: InjectionToken<any>;
641
672
 
642
673
  export { AbstractConditionFieldDef, BaseConditionFieldDef, ConditionBuilderComponent, ConditionInputOutlet, ConditionOperatorOutlet, Conjunction, CriteriaBuilderComponent, NOVO_CONDITION_BUILDER, NOVO_CRITERIA_BUILDER, NOVO_QUERY_BUILDER, NovoConditionFieldDef, NovoConditionInputDef, NovoConditionOperatorsDef, NovoConditionTemplatesComponent, NovoDefaultAddressConditionDef, NovoDefaultBooleanConditionDef, NovoDefaultDateConditionDef, NovoDefaultDateTimeConditionDef, NovoDefaultIdConditionDef, NovoDefaultNumberConditionDef, NovoDefaultPickerConditionDef, NovoDefaultStringConditionDef, NovoQueryBuilderModule, Operator, RadiusUnits };
643
- export type { AddressComponent, AddressCriteriaConfig, AddressData, AddressGeometry, AddressGeometryLocation, AddressGeometryViewport, AddressRadius, AddressRadiusUnitsName, BaseFieldDef, Condition, ConditionDef, ConditionGroup, ConditionOrConditionGroup, ConditionType, Criteria, DateCriteriaConfig, FieldConfig, NestedConditionGroup, NestedCriteria, OperatorName, QueryBuilderConfig, QueryFilterOutlet };
674
+ export type { AddressComponent, AddressCriteriaConfig, AddressData, AddressDetailViewport, AddressGeoPoint, AddressGeometry, AddressGeometryLocation, AddressGeometryViewport, AddressRadius, AddressRadiusUnitsName, BaseFieldDef, Condition, ConditionDef, ConditionGroup, ConditionOrConditionGroup, ConditionType, Criteria, DateCriteriaConfig, FieldConfig, NestedConditionGroup, NestedCriteria, OperatorName, QueryBuilderConfig, QueryFilterOutlet };
@@ -1,7 +1,7 @@
1
1
  import * as i3 from '@angular/common';
2
2
  import { isPlatformBrowser, CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { PLATFORM_ID, Inject, Injectable, forwardRef, EventEmitter, Output, Input, Component, NgModule, InjectionToken } from '@angular/core';
4
+ import { PLATFORM_ID, Inject, Injectable, InjectionToken, forwardRef, EventEmitter, Output, Input, Optional, Component, NgModule } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
6
6
  import { BasePickerResults } from 'novo-elements/elements/picker';
7
7
  import * as i2 from 'novo-elements/services';
@@ -18,6 +18,53 @@ class GooglePlacesService {
18
18
  this._global = _global;
19
19
  this._localStorageService = _localStorageService;
20
20
  }
21
+ // Ensure the Google Maps JS SDK is available before any window.google usage.
22
+ // No-ops when the SDK is already present (host script tag) or no key is configured (search-service path).
23
+ loadGoogleMaps(settings) {
24
+ const _window = this._global.nativeGlobal;
25
+ if (_window?.google?.maps?.places) {
26
+ return Promise.resolve();
27
+ }
28
+ if (!isPlatformBrowser(this.platformId) || !settings?.googleApiKey) {
29
+ return Promise.resolve();
30
+ }
31
+ if (!this.mapsLoad) {
32
+ this.mapsLoadKey = settings.googleApiKey;
33
+ this.mapsLoad = this.injectGoogleMapsScript(settings);
34
+ }
35
+ else if (this.mapsLoadKey && this.mapsLoadKey !== settings.googleApiKey) {
36
+ // The Maps JS API can only be loaded once per page; a second, different key is ignored.
37
+ console.warn('GooglePlacesService: the Google Maps SDK is already loading with a different key; ignoring the new googleApiKey.');
38
+ }
39
+ return this.mapsLoad;
40
+ }
41
+ injectGoogleMapsScript(settings) {
42
+ return new Promise((resolve, reject) => {
43
+ const _window = this._global.nativeGlobal;
44
+ // Build params one at a time so undefined override values are dropped instead of serialized as "undefined".
45
+ // The component uses the legacy Places API (AutocompleteService, PlacesService) which requires the
46
+ // synchronous library load — google.maps.places is fully populated when onload fires.
47
+ const params = new URLSearchParams();
48
+ params.set('key', settings.googleApiKey);
49
+ params.set('libraries', 'places');
50
+ for (const [key, value] of Object.entries(settings.googleMapsLoaderParams ?? {})) {
51
+ if (value !== undefined && value !== null) {
52
+ params.set(key, value);
53
+ }
54
+ }
55
+ const script = document.createElement('script');
56
+ script.src = `https://maps.googleapis.com/maps/api/js?${params.toString()}`;
57
+ script.async = true;
58
+ script.onload = () => resolve();
59
+ script.onerror = () => {
60
+ // Clear both cached fields so a later attempt can retry with any key.
61
+ this.mapsLoad = undefined;
62
+ this.mapsLoadKey = undefined;
63
+ reject(new Error('Failed to load the Google Maps JavaScript API.'));
64
+ };
65
+ document.head.appendChild(script);
66
+ });
67
+ }
21
68
  getPredictions(url, query, sessionToken) {
22
69
  return new Promise((resolve) => {
23
70
  const separator = url.includes('?') ? '&' : '?';
@@ -164,14 +211,12 @@ class GooglePlacesService {
164
211
  const _window = this._global.nativeGlobal;
165
212
  const placesService = new _window.google.maps.places.PlacesService(document.createElement('div'));
166
213
  placesService.getDetails({ placeId }, (result) => {
167
- if (result === null || result.length === 0) {
214
+ if (result === null) {
215
+ resolve(false);
216
+ }
217
+ else if (result.length === 0) {
168
218
  this.getGeoPaceDetailByReferance(result.referance).then((referanceData) => {
169
- if (!referanceData) {
170
- resolve(false);
171
- }
172
- else {
173
- resolve(referanceData);
174
- }
219
+ resolve(referanceData || false);
175
220
  });
176
221
  }
177
222
  else {
@@ -282,6 +327,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
282
327
  args: [PLATFORM_ID]
283
328
  }] }, { type: i2.GlobalRef }, { type: i2.LocalStorageService }] });
284
329
 
330
+ /** App-wide address-lookup config; when provided, every novo-address enables autocomplete on Address 1. */
331
+ const NOVO_ADDRESS_CONFIG = new InjectionToken('NOVO_ADDRESS_CONFIG');
332
+
285
333
  // NG2
286
334
  // Value accessor for the component (supports ngModel)
287
335
  const PLACES_VALUE_ACCESSOR = {
@@ -291,13 +339,16 @@ const PLACES_VALUE_ACCESSOR = {
291
339
  };
292
340
  class PlacesListComponent extends BasePickerResults {
293
341
  static { this.SESSION_TOKEN_TIMEOUT_MS = 3 * 60 * 1000; }
294
- constructor(platformId, _elmRef, _global, _googlePlacesService, cdr) {
342
+ constructor(platformId, _elmRef, _global, _googlePlacesService, cdr,
343
+ // Fallback config from the app-wide token; used when [userSettings] does not provide a field.
344
+ addressConfig = null) {
295
345
  super(_elmRef, cdr);
296
346
  this.platformId = platformId;
297
347
  this._elmRef = _elmRef;
298
348
  this._global = _global;
299
349
  this._googlePlacesService = _googlePlacesService;
300
350
  this.cdr = cdr;
351
+ this.addressConfig = addressConfig;
301
352
  this.termChange = new EventEmitter();
302
353
  this.select = new EventEmitter();
303
354
  this.matchesUpdated = new EventEmitter();
@@ -337,6 +388,8 @@ class PlacesListComponent extends BasePickerResults {
337
388
  currentLocIconUrl: '',
338
389
  searchIconUrl: '',
339
390
  locationIconUrl: '',
391
+ googleApiKey: '',
392
+ googleMapsLoaderParams: {},
340
393
  };
341
394
  this.onModelChange = () => { };
342
395
  this.onModelTouched = () => { };
@@ -498,6 +551,10 @@ class PlacesListComponent extends BasePickerResults {
498
551
  if (this.settings.showRecentSearch) {
499
552
  this.getRecentLocations();
500
553
  }
554
+ if (this.settings.useGoogleGeoApi && !this.settings.googleApiKey) {
555
+ console.warn('google-places-list: No googleApiKey configured — Google Places autocomplete is disabled. ' +
556
+ 'Pass address.googleApiKey to NovoElementProviders.forRoot() to enable it.');
557
+ }
501
558
  if (!this.settings.useGoogleGeoApi) {
502
559
  if (!this.settings.geoPredictionServerUrl) {
503
560
  this.isSettingsError = true;
@@ -529,21 +586,25 @@ class PlacesListComponent extends BasePickerResults {
529
586
  }
530
587
  }
531
588
  // function to set user settings if it is available.
589
+ // Priority: [userSettings] input > NOVO_ADDRESS_CONFIG token > defaultSettings.
532
590
  setUserSettings() {
533
591
  const _tempObj = {};
534
- if (this.userSettings && typeof this.userSettings === 'object') {
535
- const keys = Object.keys(this.defaultSettings);
536
- for (const value of keys) {
537
- _tempObj[value] = this.userSettings[value] !== undefined ? this.userSettings[value] : this.defaultSettings[value];
592
+ const keys = Object.keys(this.defaultSettings);
593
+ for (const value of keys) {
594
+ if (this.userSettings?.[value] !== undefined) {
595
+ _tempObj[value] = this.userSettings[value];
596
+ }
597
+ else if (this.addressConfig?.[value] !== undefined) {
598
+ _tempObj[value] = this.addressConfig[value];
599
+ }
600
+ else {
601
+ _tempObj[value] = this.defaultSettings[value];
538
602
  }
539
- return _tempObj;
540
- }
541
- else {
542
- return this.defaultSettings;
543
603
  }
604
+ return _tempObj;
544
605
  }
545
606
  // function to get the autocomplete list based on user input.
546
- getListQuery(value) {
607
+ async getListQuery(value) {
547
608
  this.recentDropdownOpen = false;
548
609
  if (this.settings.useGoogleGeoApi) {
549
610
  const _tempParams = {
@@ -555,14 +616,27 @@ class PlacesListComponent extends BasePickerResults {
555
616
  _tempParams.geoLocation = this.settings.geoLocation;
556
617
  _tempParams.radius = this.settings.geoRadius;
557
618
  }
558
- this._googlePlacesService.getGeoPrediction(_tempParams).then((result) => {
619
+ try {
620
+ await this._googlePlacesService.loadGoogleMaps(this.settings);
621
+ if (!this._global.nativeGlobal?.google?.maps?.places) {
622
+ this.updateListItem([]);
623
+ return;
624
+ }
625
+ const result = await this._googlePlacesService.getGeoPrediction(_tempParams);
559
626
  this.updateListItem(result);
560
- });
627
+ }
628
+ catch (err) {
629
+ console.error('Failed to load Google Maps for address predictions', err);
630
+ this.updateListItem([]);
631
+ }
561
632
  }
562
633
  else {
563
634
  this._googlePlacesService.getPredictions(this.settings.geoPredictionServerUrl, value, this.ensureSessionToken()).then((result) => {
564
635
  result = this.extractServerList(this.settings.serverResponseListHierarchy, result);
565
636
  this.updateListItem(result);
637
+ }).catch((err) => {
638
+ console.error('Failed to load address predictions from server', err);
639
+ this.updateListItem([]);
566
640
  });
567
641
  }
568
642
  }
@@ -626,14 +700,22 @@ class PlacesListComponent extends BasePickerResults {
626
700
  });
627
701
  }
628
702
  // function to execute to get location detail based on latitude and longitude.
629
- getCurrentLocationInfo(latlng) {
703
+ async getCurrentLocationInfo(latlng) {
630
704
  if (this.settings.useGoogleGeoApi) {
631
- this._googlePlacesService.getGeoLatLngDetail(latlng).then((result) => {
705
+ try {
706
+ await this._googlePlacesService.loadGoogleMaps(this.settings);
707
+ const result = await this._googlePlacesService.getGeoLatLngDetail(latlng);
632
708
  if (result) {
633
709
  this.setRecentLocation(result);
634
710
  }
711
+ }
712
+ catch (err) {
713
+ console.error('Failed to load Google Maps for current location', err);
714
+ }
715
+ finally {
716
+ // Always clear the spinner, even if the SDK never loaded.
635
717
  this.gettingCurrentLocationFlag = false;
636
- });
718
+ }
637
719
  }
638
720
  else {
639
721
  this._googlePlacesService.getLatLngDetail(this.settings.geoLatLangServiceUrl, latlng.lat, latlng.lng).then((result) => {
@@ -642,6 +724,9 @@ class PlacesListComponent extends BasePickerResults {
642
724
  this.setRecentLocation(result);
643
725
  }
644
726
  this.gettingCurrentLocationFlag = false;
727
+ }).catch((err) => {
728
+ console.error('Failed to get current location detail from server', err);
729
+ this.gettingCurrentLocationFlag = false;
645
730
  });
646
731
  }
647
732
  }
@@ -649,9 +734,16 @@ class PlacesListComponent extends BasePickerResults {
649
734
  async getPlaceLocationInfo(selectedData) {
650
735
  const placeId = selectedData.placeId;
651
736
  if (this.settings.useGoogleGeoApi) {
652
- const data = await this._googlePlacesService.getGeoPlaceDetail(placeId);
653
- if (data) {
654
- this.setRecentLocation(data);
737
+ try {
738
+ // Ensure the SDK is loaded before getGeoPlaceDetail touches window.google.
739
+ await this._googlePlacesService.loadGoogleMaps(this.settings);
740
+ const data = await this._googlePlacesService.getGeoPlaceDetail(placeId);
741
+ if (data) {
742
+ this.setRecentLocation(data);
743
+ }
744
+ }
745
+ catch (err) {
746
+ console.error('Failed to load Google Maps for place details', err);
655
747
  }
656
748
  }
657
749
  else {
@@ -662,6 +754,9 @@ class PlacesListComponent extends BasePickerResults {
662
754
  this.setRecentLocation(result);
663
755
  }
664
756
  }
757
+ catch (err) {
758
+ console.error('Failed to load place details from server', err);
759
+ }
665
760
  finally {
666
761
  // The details call ends the Google billing session; clear the token even if the request
667
762
  // failed so the next interaction starts a fresh session.
@@ -693,7 +788,7 @@ class PlacesListComponent extends BasePickerResults {
693
788
  this.recentSearchData = data && data.length ? data : [];
694
789
  });
695
790
  }
696
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PlacesListComponent, deps: [{ token: PLATFORM_ID }, { token: i0.ElementRef }, { token: i2.GlobalRef }, { token: GooglePlacesService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
791
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PlacesListComponent, deps: [{ token: PLATFORM_ID }, { token: i0.ElementRef }, { token: i2.GlobalRef }, { token: GooglePlacesService }, { token: i0.ChangeDetectorRef }, { token: NOVO_ADDRESS_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
697
792
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PlacesListComponent, isStandalone: false, selector: "google-places-list", inputs: { userSettings: "userSettings" }, outputs: { termChange: "termChange", select: "select", matchesUpdated: "matchesUpdated" }, providers: [PLACES_VALUE_ACCESSOR], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<novo-list direction=\"vertical\">\n @for (data of matches; track $index) {\n <novo-list-item (click)=\"selectedListNode($event, $index)\" [ngClass]=\"{ active: data === activeMatch }\">\n <item-header>\n <item-avatar icon=\"location\"></item-avatar>\n <item-title>{{ data.primaryText }}</item-title>\n </item-header>\n <item-content>{{ data.secondaryText }}</item-content>\n </novo-list-item>\n }\n</novo-list>\n", styles: [":host{display:grid}:host novo-list{border:1px solid #4a89dc;background-color:#fff}:host novo-list novo-list-item{cursor:pointer;flex:0 0;transition:background-color .25s}:host novo-list novo-list-item>div{width:100%}:host novo-list novo-list-item.active{background-color:#e0ebf9}:host novo-list novo-list-item:hover{background-color:#f1f6fc}:host novo-list novo-list-item item-content{flex-flow:row wrap}:host novo-list novo-list-item item-content>*{flex:0 0 33%;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4.NovoListElement, selector: "novo-list", inputs: ["theme", "direction"] }, { kind: "component", type: i4.NovoListItemElement, selector: "novo-list-item, a[list-item], button[list-item]" }, { kind: "component", type: i4.NovoItemAvatarElement, selector: "item-avatar, novo-item-avatar", inputs: ["icon", "color"] }, { kind: "component", type: i4.NovoItemTitleElement, selector: "item-title, novo-item-title" }, { kind: "component", type: i4.NovoItemHeaderElement, selector: "item-header, novo-item-header" }, { kind: "component", type: i4.NovoItemContentElement, selector: "item-content, novo-item-content", inputs: ["direction"] }] }); }
698
793
  }
699
794
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PlacesListComponent, decorators: [{
@@ -702,7 +797,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
702
797
  }], ctorParameters: () => [{ type: Object, decorators: [{
703
798
  type: Inject,
704
799
  args: [PLATFORM_ID]
705
- }] }, { type: i0.ElementRef }, { type: i2.GlobalRef }, { type: GooglePlacesService }, { type: i0.ChangeDetectorRef }], propDecorators: { userSettings: [{
800
+ }] }, { type: i0.ElementRef }, { type: i2.GlobalRef }, { type: GooglePlacesService }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
801
+ type: Optional
802
+ }, {
803
+ type: Inject,
804
+ args: [NOVO_ADDRESS_CONFIG]
805
+ }] }], propDecorators: { userSettings: [{
706
806
  type: Input
707
807
  }], termChange: [{
708
808
  type: Output
@@ -723,9 +823,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
723
823
  exports: [PlacesListComponent], imports: [CommonModule, FormsModule, NovoListModule], providers: [GooglePlacesService, provideHttpClient(withInterceptorsFromDi())] }]
724
824
  }] });
725
825
 
726
- /** App-wide address-lookup config; when provided, every novo-address enables autocomplete on Address 1. */
727
- const NOVO_ADDRESS_CONFIG = new InjectionToken('NOVO_ADDRESS_CONFIG');
728
-
729
826
  /**
730
827
  * Generated bundle index. Do not edit.
731
828
  */