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.
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.
5 Answers
Reset to default 12I 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.
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.
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.
In my case Safari 13 didnt work with ES6 const
hence i needed to replace it with var
var lastTimer
anywhere. If you haven't declared the variable, then try puttingvar lastTimer;
just before thevar dropDownMenu = {
line. – user1106925 Commented Jun 13, 2012 at 19:20this.lastTimer
. – user1106925 Commented Jun 13, 2012 at 19:28