I have the Angular UI project, and I am attempting to create an address autoComplete component for my app. I am unable to get this working.
i have created a component called locationAutoComplete.component.ts
import { Component, ViewChild, EventEmitter, Output, OnInit, AfterViewInit, Input } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { appModuleAnimation } from '@shared/animations/routerTransition';
/// <reference types=”@types/googlemaps” />
@Component({
selector: 'LocationAutocompleteComponent',
templateUrl: './locationAutoComplete.component.html',
animations: [appModuleAnimation()]
})
export class LocationAutocompleteComponent implements OnInit, AfterViewInit {
@Input() addressType: string;
@Output() setAddress: EventEmitter<any> = new EventEmitter();
@ViewChild('addresstext') addresstext: any;
locationAutocompleteInput: string;
queryWait: boolean;
constructor() {
}
ngOnInit() {
}
ngAfterViewInit() {
this.getPlaceAutocomplete();
}
private getPlaceAutocomplete() {
const autocomplete = new google.maps.places.Autocomplete(this.addresstext.nativeElement,
{
componentRestrictions: { country: 'US' },
types: [this.addressType] // 'establishment' / 'address' / 'geocode'
});
google.maps.event.addListener(autocomplete, 'place_changed', () => {
const place = autocomplete.getPlace();
this.invokeEvent(place);
});
}
invokeEvent(place: Object) {
this.setAddress.emit(place);
}
}
- Added a script reference to my Index.html
<!doctype html>
<html lang="en" dir="ltr">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
<title>Orca</title>
<base href="/">
<meta property="og:title" content="Orca" />
<meta property="og:image" content="" />
<meta property="og:description" content="Base solution for your next web application" />
<meta property="og:url" content="">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="">
<meta name="description" content="">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<script src="https://maps.googleapis.com/maps/api/js?key=[API_KEY]&libraries=places"></script>
</body>
</html>
- Included the locationAutoComplete.component.ts in a modal editing screen.
<div bsModal #createOrEditModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="createOrEditModal" aria-hidden="true" [config]="{backdrop: 'static'}">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form *ngIf="active" #locationForm="ngForm" novalidate (ngSubmit)="save()" autocomplete="off">
<div class="modal-header">
<h4 class="modal-title">
<span *ngIf="location.id">{{l("EditLocation")}}</span>
<span *ngIf="!location.id">{{l("CreateNewLocation")}}</span>
</h4>
<button type="button" class="close" (click)="close()" aria-label="Close" [disabled]="saving">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group m-form__group">
<label for="LocationGroupName">{{l("LocationGroup")}}</label>
<div class="input-group">
<input class="form-control" id="LocationGroupName" name="locationGroupName" [(ngModel)]="locationGroupName" type="text" disabled>
<div class="input-group-append">
<button class="btn btn-primary blue" (click)="openSelectLocationGroupModal()" type="button"><i class="fa fa-search"></i> {{l("Pick")}}</button>
</div> <div class="input-group-prepend">
<button class="btn btn-danger" type="button" (click)="setLocationGroupIdNull()"><i class="fa fa-times"></i></button>
</div>
</div>
</div>
<input class="form-control" name="location.locationGroupId" [(ngModel)]="location.locationGroupId" type="text" hidden>
<div class="form-group">
<label for="Location_Name">{{l("Name")}} *</label>
<input type="text" id="Location_Name" class="form-control" [(ngModel)]="location.name" name="Name" minlength="1" maxlength="50" required />
</div>
<div class="form-group">
<label for="Location_Description">{{l("Description")}}</label>
<input type="text" id="Location_Description" class="form-control" [(ngModel)]="location.description" name="Description" minlength="0" maxlength="280" />
</div>
<div class="form-group">
<label for="Location_Lookup">{{l("LocationLookup")}}</label>
<LocationAutocompleteComponent (setAddress)="getEstablishmentAddress($event)" addressType="establishment"></LocationAutocompleteComponent>
</div>
<div class="form-group">
<label for="Location_StreetAddress">{{l("StreetAddress")}} *</label>
<input type="text" id="Location_StreetAddress" class="form-control" [(ngModel)]="location.streetAddress" name="StreetAddress" minlength="1" maxlength="100" required />
</div>
<div class="form-group">
<label for="Location_City">{{l("City")}} *</label>
<input type="text" id="Location_City" class="form-control" [(ngModel)]="location.city" name="City" minlength="1" maxlength="100" required />
</div>
<div class="form-group">
<label for="Location_StateProv">{{l("StateProv")}} *</label>
<input type="text" id="Location_StateProv" class="form-control" [(ngModel)]="location.stateProv" name="StateProv" minlength="1" maxlength="100" required />
</div>
<div class="form-group">
<label for="Location_Country">{{l("Country")}} *</label>
<input type="text" id="Location_Country" class="form-control" [(ngModel)]="location.country" name="Country" minlength="1" maxlength="100" required />
</div>
<div class="form-group">
<label for="Location_PostalCode">{{l("PostalCode")}}</label>
<input type="text" id="Location_PostalCode" class="form-control" [(ngModel)]="location.postalCode" name="PostalCode" minlength="1" maxlength="100" />
</div>
<div class="form-group">
<label for="Location_Latitude">{{l("Latitude")}}</label>
<input type="number" id="Location_Latitude" class="form-control" [(ngModel)]="location.latitude" name="Latitude" />
</div>
<div class="form-group">
<label for="Location_Longitude">{{l("Longitude")}}</label>
<input type="number" id="Location_Longitude" class="form-control" [(ngModel)]="location.longitude" name="Longitude" />
</div>
</div>
<div class="modal-footer">
<button [disabled]="saving" type="button" class="btn btn-default" (click)="close()">{{l("Cancel")}}</button>
<button type="submit" class="btn btn-primary blue" [disabled]="!locationForm.form.valid" [buttonBusy]="saving" [busyText]="l('SavingWithThreeDot')"><i class="fa fa-save"></i> <span>{{l("Save")}}</span></button>
</div>
</form>
</div>
</div>
<locationGroupLookupTableModal #locationGroupLookupTableModal (modalSave)="getNewLocationGroupId()"></locationGroupLookupTableModal>
</div>
I am seeing calls to my Google API based on the traffic on the google console, but I am not getting the autoComplete experience on the UI.
Interestingly, when I start to type an address, nothing happens. But when I hit enter after typing the address. i see the following in chrome dev tools
<br>
CreateOrEditLocationModalComponent.html:41 ERROR TypeError: _co.getEstablishmentAddress is not a function
at Object.eval [as handleEvent] (CreateOrEditLocationModalComponent.html:41)
at handleEvent (core.js:23107)
at callWithDebugContext (core.js:24177)
at Object.debugHandleEvent [as handleEvent] (core.js:23904)
at dispatchEvent (core.js:20556)
at core.js:22046
at SafeSubscriber.schedulerFn [as _next] (core.js:13527)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:194)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (Subscriber.js:132)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (Subscriber.js:76)
View_CreateOrEditLocationModalComponent_1 @ CreateOrEditLocationModalComponent.html:41
push../node_modules/@angular/core/fesm5/core.js.DebugContext_.logError @ core.js:24139
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError @ core.js:15772
dispatchEvent @ core.js:20560
(anonymous) @ core.js:22046
schedulerFn @ core.js:13527
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:194
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:132
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:76
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:53
push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47
push../node_modules/@angular/core/fesm5/core.js.EventEmitter.emit @ core.js:13499
push../src/app/shared/common/locationUtilities/locationAutoComplete.component.ts.LocationAutocompleteComponent.invokeEvent @ locationAutoComplete.component.ts:44
(anonymous) @ locationAutoComplete.component.ts:38
Nd.A @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:170
_.R.trigger @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:167
Rd @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:70
Rd @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:70
_.S.set @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:170
(anonymous) @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:72
_.p.Vl @ places_impl.js:26
Nd.A @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:170
_.R.trigger @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:167
(anonymous) @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:69
Nd.A @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:170
_.R.trigger @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:167
b4 @ places_impl.js:15
_.p.Al @ places_impl.js:30
(anonymous) @ js?key=AIzaSyBKIkofPok4_DYZBy6oZt9Sq2wuDP-CpQk&libraries=places:69
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
invokeTask @ zone.js:1693
globalZoneAwareCallback @ zone.js:1719
Show 6 more frames
CreateOrEditLocationModalComponent.html:41 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 66, nodeDef: {…}, elDef: {…}, elView: {…}}
5 Answer(s)
-
0
The error message is pretty straightforward. Implement
getEstablishmentAddress
. -
0
I have implemented this within the modal edit component's TS, but i am still not getting the desired behavior. I am not getting the AutoComplete dropdown window to appear as soon as you begin typing.
import { Component, ViewChild, Injector, Output, EventEmitter, NgZone} from '@angular/core'; import { ModalDirective } from 'ngx-bootstrap'; import { finalize } from 'rxjs/operators'; import { LocationsServiceProxy, CreateOrEditLocationDto } from '@shared/service-proxies/service-proxies'; import { AppComponentBase } from '@shared/common/app-component-base'; import * as moment from 'moment'; import { LocationGroupLookupTableModalComponent } from './locationGroup-lookup-table-modal.component'; @Component({ selector: 'createOrEditLocationModal', templateUrl: './create-or-edit-location-modal.component.html' }) export class CreateOrEditLocationModalComponent extends AppComponentBase { @ViewChild('createOrEditModal') modal: ModalDirective; @ViewChild('locationGroupLookupTableModal') locationGroupLookupTableModal: LocationGroupLookupTableModalComponent; @Output() modalSave: EventEmitter<any> = new EventEmitter<any>(); active = false; saving = false; location: CreateOrEditLocationDto = new CreateOrEditLocationDto(); locationGroupName = ''; address: Object; establishmentAddress: Object; formattedAddress: string; formattedEstablishmentAddress: string; phone: string; constructor(injector: Injector, private _locationsServiceProxy: LocationsServiceProxy, public zone: NgZone) { super(injector); } show(locationId?: number): void { if (!locationId) { this.location = new CreateOrEditLocationDto(); this.location.id = locationId; this.locationGroupName = ''; this.active = true; this.modal.show(); } else { this._locationsServiceProxy.getLocationForEdit(locationId).subscribe(result => { this.location = result.location; this.locationGroupName = result.locationGroupName; this.active = true; this.modal.show(); }); } } save(): void { this.saving = true; this._locationsServiceProxy.createOrEdit(this.location) .pipe(finalize(() => { this.saving = false;})) .subscribe(() => { this.notify.info(this.l('SavedSuccessfully')); this.close(); this.modalSave.emit(null); }); } openSelectLocationGroupModal() { this.locationGroupLookupTableModal.id = this.location.locationGroupId; this.locationGroupLookupTableModal.displayName = this.locationGroupName; this.locationGroupLookupTableModal.show(); } setLocationGroupIdNull() { this.location.locationGroupId = null; this.locationGroupName = ''; } getNewLocationGroupId() { this.location.locationGroupId = this.locationGroupLookupTableModal.id; this.locationGroupName = this.locationGroupLookupTableModal.displayName; } close(): void { this.active = false; this.modal.hide(); } getAddress(place: object) { this.address = place['formatted_address']; this.phone = this.getPhone(place); this.formattedAddress = place['formatted_address']; this.zone.run(() => this.formattedAddress = place['formatted_address']); } getEstablishmentAddress(place: object) { this.establishmentAddress = place['formatted_address']; this.phone = this.getPhone(place); this.formattedEstablishmentAddress = place['formatted_address']; this.zone.run(() => { this.formattedEstablishmentAddress = place['formatted_address']; this.phone = place['formatted_phone_number']; }); } getAddrComponent(place, componentTemplate) { let result; for (let i = 0; i < place.address_components.length; i++) { const addressType = place.address_components[i].types[0]; if (componentTemplate[addressType]) { result = place.address_components[i][componentTemplate[addressType]]; return result; } } return; } getStreetNumber(place) { const COMPONENT_TEMPLATE = { street_number: 'short_name' }, streetNumber = this.getAddrComponent(place, COMPONENT_TEMPLATE); return streetNumber; } getStreet(place) { const COMPONENT_TEMPLATE = { route: 'long_name' }, street = this.getAddrComponent(place, COMPONENT_TEMPLATE); return street; } getCity(place) { const COMPONENT_TEMPLATE = { locality: 'long_name' }, city = this.getAddrComponent(place, COMPONENT_TEMPLATE); return city; } getState(place) { const COMPONENT_TEMPLATE = { administrative_area_level_1: 'short_name' }, state = this.getAddrComponent(place, COMPONENT_TEMPLATE); return state; } getDistrict(place) { const COMPONENT_TEMPLATE = { administrative_area_level_2: 'short_name' }, state = this.getAddrComponent(place, COMPONENT_TEMPLATE); return state; } getCountryShort(place) { const COMPONENT_TEMPLATE = { country: 'short_name' }, countryShort = this.getAddrComponent(place, COMPONENT_TEMPLATE); return countryShort; } getCountry(place) { const COMPONENT_TEMPLATE = { country: 'long_name' }, country = this.getAddrComponent(place, COMPONENT_TEMPLATE); return country; } getPostCode(place) { const COMPONENT_TEMPLATE = { postal_code: 'long_name' }, postCode = this.getAddrComponent(place, COMPONENT_TEMPLATE); return postCode; } getPhone(place) { const COMPONENT_TEMPLATE = { formatted_phone_number: 'formatted_phone_number' }, phone = this.getAddrComponent(place, COMPONENT_TEMPLATE); return phone; } }
-
0
-
0
Hi @abrewer
Does that work for you if you do it in a raw Angular project ?
-
0
Thanks for the reply, but I found the problem!
I was using my autoComplete component within a modal, and the autoComplete dropdown panel need to be "raised" higher than the modal.
Simply adding
.pac-container { z-index: 10000 !important; }
to my CSS caused this to work.