0
votes

I'm trying to use axios to get data from openweathermap, currently, I'm building the url by using a few methods to get the lat and lon from the user browser and then call a function that builds the url.

The url is built properly and without any issues, but when I try to call the api with axios, weird stuff happens (basically I'm getting my own page html code returned to me)

Here is the code:

let weather = new Vue ({
  el: '#weather',
  data: {
    error: '',
    apiUrl: '',
    city: '',
    country: '',
    icon: '',
    description: '',
    results: [],
  },
  methods: {
    getPosition: function() {
      if (navigator.geolocation){
        navigator.geolocation.getCurrentPosition(this.getUrl);
      }else{
        this.error = 'Geolocation is not supported.';
      }
    },
    getUrl: function(position){
      let lat = position.coords.latitude;
      let lon = position.coords.longitude;
      this.apiUrl = buildWeatherUrl(lat, lon);
    },
    getWeather: function(){
      axios.get(this.apiUrl).then(function (response) {
        this.city = response.data.name;
        this.results = response.data;
      }).catch( error => { console.log(error); });
    }
  },
  beforeMount() {
    this.getPosition();
  },
  mounted() {
    this.getWeather();
  }
});

This is my the first time using Vue and axios so I'm not sure what I'm doing wrong here. I also tried to add let self = this; and replace all this to self in the getWeather function but that didn't work.

The issue is that I'm trying to get the url from apiUrl which should get updated by the getUrl method. Although when getWeather is ran after mounted the url doesn't seem to be updated (if its hardcoded it works fine).

Thank you for the help.

3

3 Answers

1
votes

I suspect the problem is this line navigator.geolocation.getCurrentPosition(this.getUrl);.

When this.getUrl is called back by the navigator, the function no longer has the correct this, therefore this.apiUrl = buildWeatherUrl(lat, lon); will not work. Try binding this to this.getUrl, like so

getPosition: function() {
  if (navigator.geolocation){
    let getUrl = this.getUrl.bind(this)
    navigator.geolocation.getCurrentPosition(getUrl);
  }else{
    this.error = 'Geolocation is not supported.';
  }
},

Or simply navigator.geolocation.getCurrentPosition(this.getUrl.bind(this));

This function also has an incorrect this.

axios.get(this.apiUrl).then(function (response) {
    this.city = response.data.name;
    this.results = response.data;
  }).catch( error => { console.log(error); });

You'll either need to redo your previous fix:

I also tried to add let self = this; and replace all this to self in the getWeather function but that didn't work.

Or simply use an arrow function.

axios.get(this.apiUrl).then(response => {
    this.city = response.data.name;
    this.results = response.data;
  }).catch( error => { console.log(error); });

Here's a link to the definitive stack overflow answer about how to manage Javascript's this: https://stackoverflow.com/a/20279485/2498782

Scroll to the answer's section labeled "Common problem: Using object methods as callbacks/event handlers".

0
votes

I guess you registered the route as a POST request and not a GET request in the routes file. Just change it to GET and code will be fixed.

0
votes

I was able to fix this issue by commenting out all the vue code, then create an empty object called data and try to put the api url in that object. After failing constantly I realised that the url couldn't be passed to the object from within navigator.geolocation.getCurrentPosition so I played with global variables and something hit me, the issue was in how I was trying to get the url from within navigator.geolocation.getCurrentPosition

So I fixed the issue by adding lat and lon to data in the vue and then build the url before calling axios. That gave me the right results.

Here is the final code in case it's useful for someone.

    let weather = new Vue ({
  el: '#weather',
  data: {
    error: '',
    lat: 0,
    lon: 0,
    apiUrl: '',
    city: '',
    country: '',
    icon: '',
    description: '',
    results: [],
  },
  methods: {
    getPosition: function() {
      if (navigator.geolocation){
        var vm = this;
        navigator.geolocation.getCurrentPosition(this.updatePosition);
      }else{
        this.error = 'Geolocation is not supported.';
      }
    },
    updatePosition: function(position) {
        this.lat = position.coords.latitude;
        this.lon = position.coords.longitude;
    },
    getWeather: function(){
      let url = buildWeatherUrl(this.lat, this.lon);

      axios
      .get(url)
      .catch(function (error) {
        console.log(error);
      })
      .then(function (response) {
        console.log(response.data);
      });