2

I am currently learning OOP in JavaScript. I'm refactoring an app and I have a problem.

I have created a Class "Weather"

 class Weather {
 constructor({longitude, latitude} = {}) {
 this.longitude = longitude;
 this.latitude = latitude;
 this.options = {
 enableHighAccuracy: true,
 timeout: 5000,
 maximumAge: 0
 };
 }
 getLongitude(){
 return this.longitude;
 }
 setLongitude(longitude){
 this.longitude = longitude;
 }
 getLatitude(){
 return this.latitude;
 }
 setLatitude(latitude){
 this.latitude = latitude;
 }
 getLocation() {
 if (Modernizr.geolocation) {
 //if locatin is enabled, show position in button
 navigator.geolocation.getCurrentPosition(this.success, this.fail, this.options);
 } else {
 alert("Sorry, you browser doesn't have geolocation");
 }
 }
 success(position){
 let pos = position.coords;
 console.log('Your actual position is :');
 console.log(`Latitude : ${pos.latitude}`);
 console.log(`Longitude: ${pos.longitude}`);
 console.log(`More or less ${position.coords.accuracy} meters.`);
 this.setLongitude(pos.longitude); // <== Doesn't work
 this.setLatitude(pos.latitude); // <== Doesn't work
 }
 fail(){
 console.log('User refused to give position');
 }
}

Everything works, I can retrieve longitude and latitude like that

let City = new Weather();
City.getLocation(); //will call getLocation and on success, it will console.log the longitude and latitude

My problem is that I can update the value of my object. When I create my object, the constuctor defines a longitude and latitude if they are passed as argument. However, in the success method, I cannot reassign value of the object.

Is there any solution ?

asked Sep 19, 2017 at 21:25
3
  • 3
    You may find its to do with the scope of the this variable, common practice is to put a var self = this; at the top, and use self where you want the class this reference. Commented Sep 19, 2017 at 21:30
  • 1
    You can use setters and getters of class javascript Commented Sep 19, 2017 at 21:32
  • You may also do like success(position){bla bla}.bind(this); Commented Sep 19, 2017 at 21:39

4 Answers 4

2

You've lost the context because the success method is passed as a reference. So the value of this when it is called does not refer to the Weather instance. You can use Function.prototype.bind method to fix this:

class Weather {
 ...
 getLocation() {
 if (Modernizr.geolocation) {
 //if locatin is enabled, show position in button
 navigator.geolocation.getCurrentPosition(
 this.success.bind(this),
 this.fail,
 this.options
 );
 } else {
 alert("Sorry, you browser doesn't have geolocation");
 }
 }
 ...
}

Alternatively, you can bind the method in the constructor, so that bind is only called once when the object is instantiated.

answered Sep 19, 2017 at 21:46
Sign up to request clarification or add additional context in comments.

Comments

0

You can use getters and setters of class javascript.

class Weather {
 constructor({longitude, latitude} = {}) { 
 this.longitude = longitude;
 this.latitude = latitude;
 ...
 }
 get Latitude(){return this.latitude};
 set Latitude(args){this.latitude=args};
 ...
}
answered Sep 19, 2017 at 21:38

Comments

0

First and foremost: Whilst it is still possible to mimic OOP in JavaScript, you should avoid this approach and instead opt for Functional Programming.

To answer your question: When you are invoking success(), as it happens on every function in JS, the context changes and this will be referring to wherever you invoke the code.

To solve this issue you can either use bind(this) or change success to a method instead of a function. Here is how it can be done:

successs: function(position){
 let pos = position.coords;
 console.log('Your actual position is :');
 console.log(`Latitude : ${pos.latitude}`);
 console.log(`Longitude: ${pos.longitude}`);
 console.log(`More or less ${position.coords.accuracy} meters.`);
 this.setLongitude(pos.longitude); // This will work now because this
 this.setLatitude(pos.latitude); // will be referring to the Weather object
}

For further information on how this works in JS please have a look at this explanation: http://blog.andrewray.me/react-es6-autobinding-and-createclass/

answered Sep 19, 2017 at 21:45

Comments

0

As Chris Walks say you are having troubles with the "this" value inside succes s function

Ther are several ways to solve it, the problem is when navigator.geolocation.getCurrentPosition calls success, it sets a different "this" value that you expect on the function

One could be

var me = this;
navigator.geolocation.getCurrentPosition(function(position) {
 me.success(position)
}, this.fail, this.options)

You will have the same proble with this.fail

Another way is

navigator.geolocation.getCurrentPosition(this.success.bind(this), this.fail.bind(this), this.options)

You can learn more from here

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Edited: As sugested first solution is wrong, a pointer to this is need

answered Sep 19, 2017 at 21:36

1 Comment

In that first example you'd still lose the this unless you use a var me = this;. You could use an arrow function for the wrapper instead to avoid that problem.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.