angular - Typescript hämta aktuell plats och skicka till backend för att få resultatet och skicka till Material Table datakälla
Jag har mitt Angular 2-projekt som försöker få användarens nuvarande plats, därför har jag följande kod i min klass:
export class CurrentLocation {
constructor(private http: Http) { }
private lat : any;
private lon : any;
private params = new URLSearchParams();
private url = 'api/search/location';
getPosition = (lat, lon) => {
navigator.geolocation.getCurrentPosition((position) => {
this.lat = position.coords.latitude;
this.lon = position.coords.longitude;
});
}
getCurrentLocation(): Observable<any> {
this.getPosition(this.lat, this.lon);
console.log(this.lat+ "," + this.lon);
//console.log(this.lat + ":" + this.lon);
this.params.set('lat', this.lat);
this.params.set('lon', this.lon);
//console.log(this.params.toString());
var result = this.http.get(this.url, { search: this.params });
result.toPromise();
return result;
}
}
Men lat och lon returnerar undefined.. Det förväntade beteendet jag vill ha är att när jag får dessa latitud och longitud, kommer jag att skicka dem till min backend-adress som följande URL http://localhost:8080/api/search/location?lat=123&lon=123
Men det verkar som att det har misslyckats att sätta värde för lat och lon.
Hur kan jag korrekt ställa in latitud och longitud i den här klassen?
REDIGERING den 3 augusti:
Enligt libertyernies svar nedan kan jag framgångsrikt skicka nuvarande lat och lon till backend, men jag vet inte hur man konverterar till Observable, eftersom jag försöker använda Table-modulen i Angular Material, i den modulen för datakälla måste det vara Observable...
Här är koden efter att jag har försökt, men den fungerar fortfarande inte...
import { Component, OnInit } from '@angular/core';
import { Http, Response, URLSearchParams } from '@angular/http';
import { DataSource } from '@angular/cdk';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import { Restaurant } from '../restaurant/restaurant';
import { Category } from '../category/category';
import { RestaurantService } from '../restaurant/restaurant.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
displayedColumns = ['Id', 'Name', 'Category', 'Address', 'City'];
exampleDatabase: ExampleHttpDatabase | null;
dataSource: ExampleDataSource | null;
location: CurrentLocation | null;
lat: any;
lon: any;
result: Promise<any>;
constructor(http: Http) {
this.exampleDatabase = new ExampleHttpDatabase(http);
this.dataSource = new ExampleDataSource(this.exampleDatabase);
this.location = new CurrentLocation(http);
}
ngOnInit() {
this.result = this.location.getCurrentLocation(this.lat, this.lon);
this.result.then(function(result){
console.log(result._body);
})
console.log(this.lat, this.lon);
this.dataSource.connect();
}
}
export class ExampleHttpDatabase {
private restaurantUrl = 'api/restaurant'; // URL to web API
getRestaurants(): Observable<Restaurant[]> {
var result = this.http.get(this.restaurantUrl)
.map(this.extractData);
result.toPromise();
return result;
}
extractData(result: Response): Restaurant[] {
return result.json().map(restaurant => {
return {
id: restaurant.id,
name: restaurant.restaurant_name,
category: restaurant.category.map(c => c.categoryName).join(','),
address: restaurant.address.address,
city: restaurant.address.city.city_name
}
});
}
constructor(private http: Http) { }
}
export class CurrentLocation {
constructor(private http: Http) { }
private lat: any;
private lon: any;
private params = new URLSearchParams();
private url = 'api/search/location';
getPosition = () => {
var latitude, longitude;
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((position) => {
resolve(position.coords);
}, (err) => {
reject(err);
});
})
}
async getCurrentLocation(lat, lon): Promise<any> {
let coords = await this.getPosition();
lat = this.lat = coords['latitude'];
lon = this.lon = coords['longitude'];
this.params.set('lat', this.lat);
this.params.set('lon', this.lon);
var result = this.http.get(this.url, { search: this.params });
return await result.toPromise();
}
}
export class ExampleDataSource extends DataSource<Restaurant> {
constructor(private _exampleDatabase: ExampleHttpDatabase) {
super();
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable<Restaurant[]> {
return this._exampleDatabase.getRestaurants();
}
disconnect() { }
}
Förlåt, koden är lite förvirrande.. Men jag vet inte hur man skickar resultatet till connect()-funktionen för att få Material Table att fungera..
Fullständig kod också på Github: https://github.com/zhengye1/Eatr/tree/dev
Svar #1
All kod i getCurrentLocation() kommer att köras innan callback-funktionen som ges till navigator.geolocation.getCurrentPosition har en chans att köras. Du kan se detta genom att lägga till en annan console.log-sats inuti callback-funktionen:
navigator.geolocation.getCurrentPosition((position) => {
console.log("Got position", position.coords);
this.lat = position.coords.latitude;
this.lon = position.coords.longitude;
});
Det finns ett par skäl till att getCurrentPosition behöver använda en callback:
- Geolokaliseringens uppslagning kan kräva att webbläsaren frågar någon onlinetjänst för att ta reda på din plats
- Användare kan få en uppmaning om de vill dela sin plats med webbplatsen (detta är standardbeteendet i de flesta webbläsare)
Lösningen innebär troligen att skapa ett omslag runt getCurrentPosition så att det returnerar ett promise. Jag vet inte hur Angular 2-observables fungerar, så jag kommer inte kunna hjälpa mycket med den delen, men du skulle kunna få getPosition att returnera ett promise så här:
getPosition = () => {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((position) => {
resolve(position.coords);
}, (err) => {
reject(err);
});
});
Och kanske skulle getCurrentLocation kunna se ut så här (bara gissar):
async getCurrentLocation(): PromiseLike<any> {
let coords = await this.getPosition(this.lat, this.lon);
this.lat = coords['latitude'];
this.lon = coords['longitude'];
this.params.set('lat', this.lat);
this.params.set('lon', this.lon);
var result = this.http.get(this.url, { search: this.params });
return await result.toPromise();
}
Svar #2
För att geolocation ska fungera på mobila webbläsare, se till att du levererar sidan via https, annars kommer mobilen att ignorera din förfrågan om plats.
