user9061132
user9061132

Reputation:

Google Distance Matrix Api React Js Cant Set Distance To The State

I have it working it will log the response to the console but then I can't set the distance to the state I will put all the code below.

getDist(dest){
var self = this;
var origin = this.state.location,
    destination = this.state.dest,
    service = new window.google.maps.DistanceMatrixService();

    service.getDistanceMatrix(
    {
        origins: [origin],
        destinations: [destination],
        travelMode: window.google.maps.TravelMode.DRIVING,
        avoidHighways: false,
        avoidTolls: false,
        unitSystem: window.google.maps.UnitSystem.IMPERIAL
      }, 
      this.callback
    );
}

callback(response, status) {
    const self = this;
    if(status === "OK") {
        console.log(response);
        var dest = response.destinationAddresses[0];
        var dist = response.rows[0].elements[0].distance.text;
        return response;
    } else {
        alert("Error: " + status);
    }
  }

ive tried to set the state in the callback function and it says that setState({}) is not a function. ive tried to set the state by doing this this.setState({ distFromLoc: self.callback }) but that just sets the call back function code to the state which is not what I want I have reached the end of my knowledge and the other web developer I work with makes no sense with our logic.

I just need to be able to set state for 2 seconds as im looping through a list of about 36 jobs and after every search it is going to check whether that job is close enough to the person searching or not.

Thanks in advance -Andy

Edit 1: I have edited my code it doesnt error any more but it still wont let me return the data would you be able to maybe show me what im doing wrong?

going to add the class that calls it, because it is saying that i cant use .then on a function to turn the function into a promise function.

updateSearchResults(data) {
this.setState({
  searching: true,
});
var self = this;
var output = [];
console.log('Here we will search the db using user data for suitable jobs');
console.log('do some math to work out how many pagination we need for the amount of returned jobs and update the state accordingly');
data.forEach(item => {
  console.log('before');
  this.getDist(item.postcode).then(function (res){
    console.log('after');
    console.log(this.state.distFromLoc);
    if (this.state.location === '') {
      if (item.option === 'Part Time' && this.state.partTime && !this.state.weekend){
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('1');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('2');
          output.push(item);
        }
      } else if (item.option === 'Weekends' && this.state.weekend && !this.state.partTime){
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('3');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('4');
          output.push(item);
        }
      } else if (item.option === 'both' && this.state.weekend && this.state.partTime){
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('5');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('6');
          output.push(item);
        }
      } else if (!this.state.weekend && !this.state.partTime) {
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('7');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('8');
          output.push(item);
        }
      }
    } else if (this.state.distFromLoc <= this.state.distance) {
      console.log(this.state.distFromLoc);
      console.log(this.state.distance);
      if (item.option === 'Part Time' && this.state.partTime && !this.state.weekend){
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('9');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('10');
          output.push(item);
        }
      } else if (item.option === 'Weekends' && this.state.weekend && !this.state.partTime){
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('11');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('12');
          output.push(item);
        }
      } else if (item.option === 'both' && this.state.weekend && this.state.partTime){
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('13');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('14');
          output.push(item);
        }
      } else if (!this.state.weekend && !this.state.partTime) {
        if (item.title.toLowerCase().match(this.state.keywords.toLowerCase()) !== null ) {
          console.log('15');
          output.push(item)
        } else if (this.state.keywords === ''){
          console.log('16');
          output.push(item);
        }
      }
    }
  })
  .catch(function (err){
    console.log(err);
  });
});
window.setTimeout(function() {
self.setState({
  dataToShow: output,
  searching: false,
  current: 1,
});
const dataLength = self.state.dataToShow.length
self.setState({
  amountOfJobs: dataLength
})}, 10000)
}

getDist(dest){
var self = this;
const wrappedCallback = (...args) => this.callback(...args);
var origin = this.state.location,
    destination = dest,
    service = new window.google.maps.DistanceMatrixService();

    service.getDistanceMatrix(
    {
        origins: [origin],
        destinations: [destination],
        travelMode: window.google.maps.TravelMode.DRIVING,
        avoidHighways: false,
        avoidTolls: false,
        unitSystem: window.google.maps.UnitSystem.IMPERIAL
      }, wrappedCallback 
    );
}

callback(response, status) {
    const self = this;
    if(status === "OK") {
        console.log(response);
        var dest = response.destinationAddresses[0];
        if (response.rows[0].elements[0].status === "ZERO_RESULTS"){

        } else if (response.rows[0].elements[0].status === "OK"){
          var dist = response.rows[0].elements[0].distance.text;
          this.setState({
            distFromLoc: dist
          })
        }
    } else {
        alert("Error: " + status);
    }
  }

i know im doing something wrong i just cant work out what it is exactly.

current error im getting is this TypeError: Cannot read property 'then' of undefined why cant i put a promise on the function.

Upvotes: 0

Views: 2031

Answers (2)

Eli&#226; Melfior
Eli&#226; Melfior

Reputation: 369

There might be an alternative solution, but it uses a global variable:

window.callback = function( ) {};

window.callback = (code, name) => {
    me.setState({stateVariable: code});     
};

You might change this code accordingly and use the callback in any place of your code (because it was declared globally with an arrow function that preserves context, it is a closure)

Upvotes: 0

Duncan Thacker
Duncan Thacker

Reputation: 5188

This is a binding problem and one of the main reasons to avoid using classes in javascript. Here's where your problem is:

service.getDistanceMatrix({
    origins: [origin],
    destinations: [destination],
    travelMode: window.google.maps.TravelMode.DRIVING,
    avoidHighways: false,
    avoidTolls: false,
    unitSystem: window.google.maps.UnitSystem.IMPERIAL
  }, 
  this.callback
);

When you provide the callback as this.callback, you're passing in a function. When that function gets called, however, it no longer has the context it needs to know what this actually is, because the calling code is now in Google's API. There's 3 solutions to this problem.

1) Bind the function so that it knows what this is

 //boundCallback will now always have the correct value for "this"
const boundCallback = this.callback.bind( this ); 

2) Wrap it in a fat arrow function (ES6 only)

//fat arrow always takes the value of "this" from surrounding scope
const wrappedCallback = (...args) => this.callback(...args);

3) Use React.createClass() for your component This is my preferred solution - if you create your component with React.createClass() instead of using class Comp extends React.Component, all the functions are automatically bound for you, so you never need to mess about - this.callback is always correct.

Upvotes: 1

Related Questions