Safari on IOS generates "ReferenceError: Can't find variable:"

The following code is working correctly for all browsers including Safari on Mac, with the exception of Safari on the iPhone.

I have a timer Object that could potentially be running that is defined like so:

//delay background change until animation is finished
lastTimer = setTimeout(function () {
  $('#' + targetDiv).removeClass('open');
}, 150);

Later, I need to check if the timer is running, and if so cancel it. Here is the code I am using:

if (lastTimer != null) { clearTimeout(lastTimer); }

This is where IOS Safari generates the JavaScript Error:

"ReferenceError: Can't find variable: lastTimer".

Any ideas on why the check for null is not preventing the error, like it seems to with the other browsers?

Here is the full code for the two pertaining functions in answer to the reply below: (edited with solution)

// Class for handling the animations for the drop down menus
var dropDownMenu = {
lastTimer: null,
openMenu: function (targetDiv) {
    if (targetDiv != null) {
        var targetHeight = $('#' + targetDiv).height();
        $('#' + targetDiv).stop(true); //stop an previous animations and clear queue
        if (this.lastTimer != null) { clearTimeout(this.lastTimer); } //stop possible pending timer to prevent background change
        console.log("testing b");
        $('#mainNavigation #dropDownMenu ul').removeClass('open'); // make sure all closed menus show corrent bgd
        $('#' + targetDiv).animate({
            bottom: -(targetHeight + 30)
        }, 200, 'swing');
        $('#' + targetDiv).addClass('open');
    }

},
closeMenu: function (targetDiv) {
    if (targetDiv != null) {
        $('#' + targetDiv).stop(true); //stop an previous animations and clear queue
        $('#' + targetDiv).animate({
            bottom: 0
        }, 200, 'swing');
        //delay background change until animation is finished
        this.lastTimer = setTimeout(function () {
            $('#' + targetDiv).removeClass('open');
        }, 150);
    }
}
}

When the error happens in ios the execution stops and my test console.log immediately after does not execute.

Answers


Your issue seems to be that on IOS, the openMenu is being invoked first.

This means that you're trying to get the value of an undeclared variable, resulting in the ReferenceError.

Oddly, you can assign to an undeclared variable, which implicitly makes it global. So if closeMenu is called first, then the assignment happens first, making the variable implicitly declared.

The proper solution is to always declare variables before using them.

var lastTimer;

But as it turned out, you preferred to use a property on the current object instead of a variable. As such, the solution was to access the property in the methods...

this.lastTimer

This will never throw a ReferenceError, even if the property is not declared.


I want to chime in on this to explain. Mobile Safari is less forgiving when checking for undefined using the simple check,

if variable

When you come across situations like this then use,

if typeof variable === "undefined"

Attaching the variable to "this" is one solution here but it's just taking advantage of the fact that definedVariable.undefinedProperty returns undefined, whereas referencing an undefined variable directly will cause the reference error in some runtime environments.

I would advise not getting into the habit of attaching to "this" if it's not necessary.


There's one other potential issue that I think needs to be stated. Safari on iOS* can be very aggressive on caching and not reloading a clean copy of your code.

e.g. if you executed one version of your code without the variable defined, then fixed the code but the error continues to show on reloading (even if you close the browser/reboot the phone)

To solve this, tap and hold (aka Long Press) the reload icon in the address bar and a menu pops up with 2 options Request Desktop Site and Reload Without Content Blockers. Choosing either one of these causes a Real reload of all of the content... which resolves the issue with any cached buggy code.

*Not just Safari. Chrome on iOS (which is built on Apple's version of WebKit) can exhibit the same issue.


You have a global variable in your code. Not declaring var makes it global.

Try changing:

if (lastTimer != null)

to

if (typeof lastTimer !=="undefined" && lastTimer)

if you are sticking with it being global.


Need Your Help

Replacing empty values in a CSV using powershell?

powershell csv powershell-v2.0 powershell-v3.0

I am faced with a challenge and I am new to development (but a long time sys admin).

WPF TabControl and DataTemplates

wpf tabcontrol datatemplate

I've got a set of ViewModels that I'm binding to the ItemsSource property of a TabControl. Let's call those ViewModels AViewModel, BViewModel, and CViewModel. Each one of those needs to have a diff...