Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript getCurrent location and pass to backend to get the result and pass to Material Table data source

I have my Angular 2 project that tries to get user's current location, therefore in my class I have the following code:

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;
  }
}

But lat and lon return undefined.. The expected behaviour I want is once I got those latitude and longitude, I will send it to my backend address like following url http://localhost:8080/api/search/location?lat=123&lon=123

But it seems like setting value for lat and lon are failed.

How can I properly set the latitude and longitude in this class?

EDIT on August 3:

According libertyernie's answer below, I can successfully pass the current lat and lon into backend, but I don't know how to convert to Observable, since I try to using Table module in Angular Material, in that module for data source it must be Observable...

Here is the code after I try, but still not working...

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() { }
}

Sorry about the code is a little bit confusing.. But I don't know how to pass the result into connect() function to make Material Table works..

Full code also in Github: https://github.com/zhengye1/Eatr/tree/dev

like image 260
Vincent Zheng Avatar asked Jul 28 '17 18:07

Vincent Zheng


People also ask

How to get the current date in typescript?

The Date object is used to get the current date in TypeScript. We can use it to get the current date-time and also change it to different formats. We can create a new Date object and each time we create a Date object, it returns the current date-time. There are different ways to construct a Date object with its constructor.

What does the getusers () function do in typescript?

When we call the getUsers function, Typescript knows that we’re supposed to get back a list of User types, and so we can make use of type annotations: I use VSCode as my editor, but Typescript annotations and autocompletion features are present in most popular text editors.

What is typescript and how does it help developers?

Typescript helps developers by providing static analysis and autocomplete features for their Javascript code. When calling REST APIs, the response is normally in a serialized format, most commonly JSON.

How does typescript integrate with REST APIs?

Typescript helps developers by providing static analysis and autocomplete features for their Javascript code. When calling REST APIs, the response is normally in a serialized format, most commonly JSON. We can then divide the process of integration API calls with Typescript into two parts:


1 Answers

All of the code in getCurrentLocation() will run before the callback given to navigator.geolocation.getCurrentPosition has a chance to run. You can see this by putting another console.log statement inside the callback:

navigator.geolocation.getCurrentPosition((position) => { 
  console.log("Got position", position.coords);
  this.lat = position.coords.latitude; 
  this.lon = position.coords.longitude;
});

There are a couple of reasons that getCurrentPosition needs to use a callback:

  • The geolocation lookup might require the browser to query some online service to figure out your location
  • Users might be given a prompt asking if they want to share their location with the website (this is the default behavior in most browsers)

The solution probably involves making a wrapper around getCurrentPosition so that it returns a promise. I don't know how Angular 2 observables work so I won't be able to help much in that part, but you could have getPosition return a promise like so:

getPosition = () => {
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition((position) => { 
      resolve(position.coords);
    }, (err) => {
      reject(err);
    });
  });

And maybe getCurrentLocation could look like this (just guessing):

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();
}
like image 74
libertyernie Avatar answered Oct 07 '22 13:10

libertyernie