Open roman-lisnyi opened 7 years ago
I was wondering how to do this as well for my Angular4 app using Angular's FormBuilder. I ended up setting the formControl's value in the callback and setting the input's style through the ng4geo-autocomplete
tag.
HTML
<ng4geo-autocomplete (componentCallback)="autoCompleteCallback($event)"></ng4geo-autocomplete>
TS
autoCompleteCallback(selectedData: any) {
this.myForm.get('myControl').setValue(selectedData.formatted_address);
}
SCSS
ng4geo-autocomplete {
#search_places {
// styles here
}
}
To set the value of the input when retrieving data from a database, I did:
TS
// dbReturnValue = whatever value was returned from the database query
this.myForm.get('myControl').setValue(dbReturnValue);
(<HTMLInputElement>document.getElementById('search_places')).value = dbReturnValue;
It's ugly, but it works.
Hi @Webberjo, i need you'r help for that's code :
autoCompleteCallback(selectedData: any) {
this.myForm.get('myControl').setValue(dbReturnValue);
(<HTMLInputElement>document.getElementById('search_places')).value = dbReturnValue;
}
Where does the " myForm " & " ('myControl') " from ?
My form look like this and i really want to add the autocomplete in my firebase :
<form #f="ngForm" (ngSubmit)="save(f.value)">
<input #adress="ngModel" [(ngModel)]="cavist.adress" name="adress" id="adress" type="text" class="form-control" required>
<button [disabled]="!f.valid" class="btn btn-primary">Enregistrer</button>
<button *ngIf="id" type="button" (click)="delete()" class="btn btn-danger">Supprimer</button>
</form>
Thank's a lot in advance.
@remyblancke myForm
is the FormGroup that holds related FormControls, myControl
is the name of the FormControl. Your example isn't using FormControls though.
With what you have, you might be able to bind the result of the callback to a backend variable or hidden input, something like...
<input type="hidden" value="{{selectedAddress}}"/>
<ng4geo-autocomplete (componentCallback)="autoCompleteCallback($event)"></ng4geo-autocomplete>
<button [disabled]="!selectedAddress" class="btn btn-primary">Enregistrer</button>
selectedAddress: string = '';
autoCompleteCallback(address: any) {
this.selectedAddress = address.formatted_address;
}
I did say my solution was ugly...
Hum, try to run your solution but not work..
Look my component.ts, maybe i that he will inspire you
import { ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';
import { ProductService } from '../../services/product.service';
import { CategoryService } from '../../services/category.service';
import { Component, OnInit } from '@angular/core';
import 'rxjs/add/operator/take';
import { MapsAPILoader } from '@agm/core';
import {} from '@types/googlemaps';
import { ViewChild, ElementRef, NgZone } from '@angular/core';
import { CavistService } from '../../services/cavist.service';
@Component({
selector: 'app-cavist-form',
templateUrl: './cavist-form.component.html',
styleUrls: ['./cavist-form.component.css']
})
export class CavistFormComponent implements OnInit {
//categories$;
//cavist = {};
// @ViewChild('search') public searchElement: ElementRef
id;
//MOI pour coriger erreurs ng build --prod
cavist = {
"title" : "",
"description" : "",
"adress" : "",
"zipcode" : "",
"city" : "",
"lat" : "",
"lng" : "",
"imageUrl" : ""
};
constructor(
private router: Router,
private route: ActivatedRoute,
private mapsAPILoader: MapsAPILoader,
private ngZone: NgZone,
//private categoryService: CategoryService,
private cavistService: CavistService) {
//this.categories$ = categoryService.getAll();
this.id = this.route.snapshot.paramMap.get('id');
if (this.id) this.cavistService.get(this.id).take(1).subscribe(p => this.cavist = p);
}
// Autocomplete
public componentData1: any = '';
autoCompleteCallback1(data: any): any {
this.componentData1 = JSON.stringify(data);
}
public userSettings5: any = {
geoCountryRestriction: ['fr'],
geoTypes: ['address'],
inputPlaceholderText?: ['Veuillez saisir votre adresse']
};
save(cavist) {
if (this.id) this.cavistService.update(this.id, cavist);
else this.cavistService.create(cavist);
this.router.navigate(['/admin/cavists']);
}
delete() {
if (!confirm('Are you sure you want to delete this cavist?')) return;
this.cavistService.delete(this.id);
this.router.navigate(['/admin/cavists']);
}
ngOnInit() {
// this.mapsAPILoader.load().then(
// () => {
// let autocomplete = new google.maps.places.Autocomplete(this.searchElement.nativeElement, {
// types: ['address'],
// componentRestrictions: {
// country: 'FR'
// }
// });
// }
// );
}
}
It's also ugly..
I suggest implementing it one step at a time and testing each step along the way. Add the component to your HTML and the callback function to your TS. Does it work? Yes - Work on getting the information you need from the callback parameter. No - Check the documentation to see if you installed and implemented it correctly.
Okay autocomplete work and parsing : look this screen Then, to inject autocomplete into my input ,I tried two solutions.
1
A first solution with the hidden input
autoCompleteCallback(address: any) {
this.selectedAddress = address.formatted_address;
}
Not working.
2
A second solution ( ugliest )
autoCompleteCallback1(data: any): any {
this.componentData1 = JSON.stringify(data);
// dbReturnValue = whatever value was returned from the database query
this.cavistService.get('ngForm').setValue(this.cavist);
(<HTMLInputElement>document.getElementById('adress')).value = this.cavist;
}
Not working yet and i have error in console like this
ERROR in src/app/admin/cavist-form/cavist-form.component.ts(67,38):
error TS2339: Property 'setValue' does not exist on type 'FirebaseObjectObservable<any>'.
src/app/admin/cavist-form/cavist-form.component.ts(68,5):
error TS2322: Type '{ "title": string; "description": string; "adress": string; "zipcode": string; "city": string; "l...' is not assignable to type 'string'.
.get()
is a FormGroup method and setValue()
is a FormControl method. My solution is for Angular's FormBuilder. Your code isn't using FormBuilder, that's why you're getting those errors.
If you do
autoCompleteCallback(data: any) {
console.log(data);
}
and open your developer tools, you will get the exact JSON structure of the returned data in your Console tab when you select a location. (like this)
Go through it, find what you need and set them in your cavist
object, like
autoCompleteCallback(data: any) {
this.cavist = {
city: data.city,
lat: data.geometry.lat,
lng: data.geometry.lng
// and the rest
};
}
I think we are getting closer to the goal. console.log gave me everything I needed but,
I tried this solution just for add address,
autoCompleteCallback(data: any) {
// console.log(data);
// this.componentData1 = JSON.stringify(data);
this.cavist = {
title: "",
description: "",
imageUrl: "",
adress: data.formatted_address,
zipcode: "",
city: "",
lat: "",
lng: ""
};
}
This code is interesting because when I select an address according to the autocomplete, all the inputs become empty, look this screen but give me error : formatted_adress undefined.
Before select address -> https://ibb.co/bQJrbS After select address -> https://ibb.co/gzbzVn
So tried something
autoCompleteCallback(data: any) {
console.log(data);
// this.componentData1 = JSON.stringify(data);
this.cavist = {
title: this.cavist.title,
description: this.cavist.description,
imageUrl: this.cavist.imageUrl,
adress: "",
zipcode: "",
city: "",
lat: "",
lng: ""
};
}
Return me good ( title, description, imageUrl ) from my cavist but I still can not get the data of the json.
For example this console.log give me "undefined".
console.log(data.formatted_address);
Also lat & lng gives me "undefined" when i try : data.geometry.lat.
I think the problem comes from the synthax of the data.
Okay find the solution
autoCompleteCallback1(data: any) {
console.log(data)
this.cavist = {
title: this.cavist.title,
description: this.cavist.description,
imageUrl: this.cavist.imageUrl,
adress: data.data.name,
zipcode: data.data.address_components[6].short_name,
city: data.data.vicinity,
lat: data.data.geometry.location.lat,
lng: data.data.geometry.location.lng
};
}
Work fine but, just one problem, zipcode is not saved.
What happens if data.data.address_components
doesn't have 7 elements in it? You'll get an error because it's trying to get information that's out of bounds.
fruits = ['apple', 'banana', 'orange'];
0 1 2
console.log(fruits[6]); // undefined, fruits only goes to 2
Also, you are assuming that the postal code information is going to be in the exact same index of address_components
every time. What if it's in address_components[5]
or address_components[7]
?
It appears to always be in the last index of the array, so you can do
autoCompleteCallback1(data: any) {
this.cavist = {
...
zipcode: data.data.address_components[data.data.address_components.length - 1].short_name,
...
}
}
this way it will always get the information from the last index, no matter how many items are in the array.
Sorry, all work's fine with :
autoCompleteCallback(data: any) {
console.log(data)
this.cavist = {
title: this.cavist.title,
description: this.cavist.description,
imageUrl: this.cavist.imageUrl,
adress: data.data.name,
zipcode: data.data.address_components[6].short_name,
city: data.data.vicinity,
lat: data.data.geometry.location.lat,
lng: data.data.geometry.location.lng
};
}
Thank you for your precious help
Zip codes are specific to only the United States, every other country in the world uses a postal code.
As for setting the input's value, try adding this to the callback
(<HTMLInputElement>document.getElementById('search_places')).value = data.data.name;
If that doesn't work, I don't know how to set it.
@Webberjo All works fine with my last code !
An other question : Do you know how I could get the address of the cavist in the placeholder of ng4-geoautocomplete?
Like :
public userSettings5: any = {
inputPlaceholderText: this.cavist.adress
};
This does not work unfortunately..
You are setting the placeholder text to the result of this.cavist.adress
which is ""
at the time of component initialization. Re-read the documentation for how to alter component settings after initialization.
Hint: It's below the list of component settings.
Hum okay it's something like that but I still do not understand how to recover cavist.adress
this.userSettings5['inputPlaceholderText'] = 'this.cavist.adress';
this.userSettings5 = Object.assign({},this.userSettings5);
This not work but that's the idea
i try these :
autoCompleteCallback1(data: any) { console.log(data); }
but console.log return undefined !
You probably forgot the $
.
↓
<ng4geo-autocomplete (componentCallback)="autoCompleteCallback($event)"></ng4geo-autocomplete>
Hello. I need your assistance. How can I add formControlName, ngModel, class or something like this into the input tag?
Thank you!