I work on an angular 2 application. I have a google maps in it, with autocomplete. I have an input (with google autocomplete), and a search button. When i hit the search button, I send the input data to google geocode, and put a marker on the map. It's sounds simple, but after this, the angular2 data bindig just stop working. The input don't get the formatted address, the addressIsValid dont turn on true.
HTML:
<div class="input-group">
<input autocorrect="off" autocapitalize="off" spellcheck="off" type="text"
class="form-control" [(ngModel)]="addressInput" #search id="address" (keydown)="addressChanged()">
<div class="input-group-btn">
<button id="addressSubmitButton" type="submit" class="btn btn-default" [class.btn-success]="addressIsValid"
(click)="submited(search.value)">
{{ (addressIsValid ? 'addressInput.success' : 'addressInput.search') | translate }}
</button>
</div>
Code:
export class AddressInputComponent implements OnInit {
public map: google.maps.Map;
public autocomplete: google.maps.places.Autocomplete;
private geocoder: google.maps.Geocoder = new google.maps.Geocoder();
public marker: google.maps.Marker;
public defaultZoom: number;
public defaultLat: number;
public defaultLng: number;
public errorCode: number;
private addressIsValid: boolean;
@Input('address') private addressInput: string;
@Output() addressUpdated: EventEmitter<string> = new EventEmitter();
@ViewChild("search")
public searchElementRef: ElementRef;
constructor() {
this.addressIsValid = false;
}
ngOnInit() {
this.defaultZoom = 7;
this.defaultLat = 47.338941;
this.defaultLng = 19.396167;
this.errorCode = null;
this.autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement, {
types: ["address"]
});
this._setMapToDefault();
this.autocomplete.bindTo('bounds', this.map);
this.autocomplete.addListener('place_changed', () => {
this.addressInput = this.autocomplete.getPlace().formatted_address;
})
}
private _setMapToDefault() {
this.map = new google.maps.Map(document.getElementById('map'), {
center: {lat: this.defaultLat, lng: this.defaultLng},
zoom: this.defaultZoom,
scrollwheel: false,
});
this.marker = new google.maps.Marker();
this.marker.setMap(this.map);
}
submited() {
this.geocoder.geocode( { 'address': this.addressInput}, (results, status) => {
if (status == google.maps.GeocoderStatus.OK) {
setInterval(this._changeInput(results[0]), 200);
} else {
this.addressIsValid = false;
this.errorCode = 1;
this._setMapToDefault();
}
});
}
private _changeInput(result) {
this.errorCode = null;
if (result.address_components[0].types[0] != "street_number") {
this.addressIsValid = false;
this.errorCode = 2;
this._setMapToDefault();
return;
}
// jQuery('#address').val(result.formatted_address);
this.addressInput = result.formatted_address;
this.addressUpdated.emit(this.addressInput);
this.addressIsValid = true;
this.map.setCenter(result.geometry.location);
this.map.setZoom(17);
this.marker.setPosition(result.geometry.location);
this.marker.setVisible(true);
}
private addressChanged() {
if (this.addressIsValid == true) {
this.addressIsValid = false;
this._setMapToDefault();
}
}
}
Change detection is not triggered because google.maps
uses its own sets of events/addListener calls. These events are -not- so called monkey patched by zone.js
and therefor do not run in the Angular zone, which logically will not trigger a change detection cycle.
So you can solve this by injecting the ngZone
service in your component, on which you can reenter the angular zone using the run
method:
constructor(private ngZone: NgZone) {}
ngOnInit() {
//...
this.autocomplete.addListener('place_changed', () => {
this.ngZone.run(() => {
this.addressInput = this.autocomplete.getPlace().formatted_address;
});
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With