1

I have a function as below.

I am trying to call this with

var testVar =  new genericYiiLocation();
console.log(testVar.getLongitude());

however, I this.getLongitude() always has an empty this.longitude.

I have checked that this.longitude contains the values as expected when being set in locateSuccess(loc) and it seems ok.

Any guidance would be appreciated.

function genericYiiLocation() {

    console.log('genericYiiLocation: Creating location handler');

    this.longitude=  '';
    this.latitude=   '';
    this.accuracy=   '';

    if (Modernizr.geolocation) {
        console.log('genericYiiLocation: Location supported');
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(locateSuccess, locateFail);
        }
        else {
            alert('genericYiiLocation: Geolocation is not supported in your current browser.');
            return false;
        }
    } else {
        alert ('genericYiiLocation: no native location support');
        return false;
    }


     function locateSuccess(loc){
        console.log('genericYiiLocation: storing location data');
        this.longitude = loc.coords.longitude;
    }

    // Unsuccessful geolocation
    function locateFail(geoPositionError) {
        switch (geoPositionError.code) {
            case 0: // UNKNOWN_ERROR
                alert('An unknown error occurred, sorry');
                break;
            case 1: // PERMISSION_DENIED
                alert('Permission to use Geolocation was denied');
                break;
            case 2: // POSITION_UNAVAILABLE
                alert('Couldn\'t find you...');
                break;
            case 3: // TIMEOUT
                alert('The Geolocation request took too long and timed out');
                break;
            default:
        }
    }

    this.getLongitude = function(){
        console.log('long: '+this.longitude);
        return this.longitude;
    }
}

2 Answers 2

1

As far as I understand the reason is:

The this inside your callback locateSuccess is different from the this outside the callback. To achieve what you are intending to, you can bind the callbacks localSuccess & locateFail to this using Function.prototype.bind.

Sign up to request clarification or add additional context in comments.

4 Comments

Would you please have an example of how to do this ?
Your line navigator.geolocation.getCurrentPosition(locateSuccess, locateFail); should be changed to navigator.geolocation.getCurrentPosition(locateSuccess.bind(this), locateFail.bind(this)); Note that even though Function.prototype.bind is introduced in Javascript 1.8.5 & might not be supported in old browsers (like IE6), I'm thinking it would be supported in all browsers supporting geolocation (an HTML5 feature).
i have tried this with the same outcome. ie: this.longitude is still empty I now have navigator.geolocation.getCurrentPosition(locateSuccess.bind(this), locateFail.bind(this));
It is working fine for me Just to be on same page, here is my usage: var a = new genericYiiLocation(); console.log(a.getLongitude()); Note that the keyword new is important.
0

The following line:

            navigator.geolocation.getCurrentPosition(locateSuccess, locateFail);

causes your locateSuccess function to be executed in the global scope of your page. Hence, when the locateSuccess function tries to access this, it references the window object instead of your genericYiiLocation object.

A quick way to fix this would be to bind the genericYiiLocation object to another variable in its scope, then reference it within the locateSuccess closure like so:

function genericYiiLocation() {

    console.log('genericYiiLocation: Creating location handler');

    this.longitude=  '';
    this.latitude=   '';
    this.accuracy=   '';

    //  ADDED
    var me = this;

    if (Modernizr.geolocation) {
        console.log('genericYiiLocation: Location supported');
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(locateSuccess, locateFail);
        }
        else {
            alert('genericYiiLocation: Geolocation is not supported in your current browser.');
            return false;
        }
    } else {
        alert ('genericYiiLocation: no native location support');
        return false;
    }


    function locateSuccess(loc){
        console.log('genericYiiLocation: storing location data');
        //  CHANGED
        me.longitude = loc.coords.longitude;
    }

    // Unsuccessful geolocation
    function locateFail(geoPositionError) {
        switch (geoPositionError.code) {
            case 0: // UNKNOWN_ERROR
                alert('An unknown error occurred, sorry');
                break;
            case 1: // PERMISSION_DENIED
                alert('Permission to use Geolocation was denied');
                break;
            case 2: // POSITION_UNAVAILABLE
                alert('Couldn\'t find you...');
                break;
            case 3: // TIMEOUT
                alert('The Geolocation request took too long and timed out');
                break;
            default:
        }
    }

    this.getLongitude = function(){
        console.log('long: '+this.longitude);
        return this.longitude;
    }
}

5 Comments

Seems to work fine on my end - make sure that you see genericYiiLocation: storing location data in your console before your call to getLongitude. genericYiiLocation should really be doing all processing asynchronously, anyways.
Peter, Thanks for that. Works perfectly. I now see the issue with scope and async nature of the calls. your callback is great. thanks
Glad to help. Please upvote and accept the answer if it's the one that worked for you!
peter, would be happy to but cant figure out how :-) im new to this
lol...i cant..my reputation is too low :-( i only just joined

Your Answer

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.