ReferenceError: count_1 is not defined in a Joomla module - javascript

This is my script:
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var START_DATE_1 = new Date("July 18, 2016 10:30:00"); // put in the starting date here
var INTERVAL_1 = 3; // in seconds
var INCREMENT_1 = 1; // increase per tick
var START_VALUE_1 = 0; // initial value when it's the start date
var count_1 = 0;
var msInterval_1 = INTERVAL_1 * 1000;
var now_1 = new Date();
count_1 = parseInt((now_1 - START_DATE_1)/msInterval_1) * INCREMENT_1 + START_VALUE_1;
document.getElementById('counter_1').innerHTML = count_1;
setInterval("count_1 += INCREMENT_1; document.getElementById('counter_1').innerHTML = count_1;", msInterval_1);
});
</script>
I've placed it inside a Joomla module. Firebug says: "ReferenceError: count_1 is not defined"
Why? How can I solve it?

You should pass a function instead of a string to the setInterval call. When you pass a string, it is executed in the global scope, and count_1 variable exists only in the scope of the callback function passed to addEventListener.
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var START_DATE_1 = new Date("July 18, 2016 10:30:00"); // put in the starting date here
var INTERVAL_1 = 3; // in seconds
var INCREMENT_1 = 1; // increase per tick
var START_VALUE_1 = 0; // initial value when it's the start date
var count_1 = 0;
var msInterval_1 = INTERVAL_1 * 1000;
var now_1 = new Date();
count_1 = parseInt((now_1 - START_DATE_1)/msInterval_1) * INCREMENT_1 + START_VALUE_1;
document.getElementById('counter_1').innerHTML = count_1;
setInterval(function() {
count_1 += INCREMENT_1;
document.getElementById('counter_1').innerHTML = count_1;
}, msInterval_1);
});
</script>

When you pass in a string as the first argument to the timers function, they actually create a script object with that as source:
[Otherwise]
Perform HostEnsureCanCompileStrings(callerRealm, calleeRealm). If this throws an exception, report the exception.
Let script source be the first method argument.
Let settings object be method context's environment settings object.
Let script be the result of creating a classic script using script source and settings object.
Run the classic script script.
https://html.spec.whatwg.org/multipage/webappapis.html#dom-setinterval
So, it's not exactly as eval where you actually get access to the scope of the function. The script object should have access to the global scope. The reason it fails is because is because it looks for count_1 on the global scope through count_1 += INCREMENT which isn't find and therefore returns the ReferenceError.
Best way to avoid this type of errors is to not use a string as an argument for the timers function.

Related

Instance methods not in scope of JS module in NodeJS?

I'm trying to create a non-singleton object in NodeJS but when calling internal instance methods within the object, they are "undefined".
// We auto-refresh the cached data every 'refreshInterval' milliseconds
var refreshInterval = 30*1000;
var refreshTimer = null;
// We stop refreshing 'idleTimeout' milliseconds after the last request for our data
var idleTimeout = 5 * 60 * 1000; // 5 minutes
var idleTimer = null;
var cachedData = null;
var queryCallback = null;
function Cache(options) {
if (options) {
this.refreshInterval = options.refreshInterval || 30;
this.queryCallback = options.queryCallback || null;
this.idleTimeout = options.idleTimeout || 5 * 60 * 1000;
}
}
Cache.prototype.data = function(callback) {
updateIdle();
if (cachedData) {
callback(cachedData);
} else {
queryData(function(newdata) {
callback(newdata);
});
}
}
Cache.prototype.updateIdle = function() {
idleTimer && clearTimeout(idleTimer);
idleTimer = setTimeout(haltRefresh, idleTimeout);
wslog.info(`Will cease cache refresh at ${new Date(Date.now() + idleTimeout)} if no new activity`);
}
// ...
module.exports = Cache;
When I create the object
var Cache = require('./cache.js');
var myCache = Cache(opts);
It works but when I invoke myCache.data(), the invocation of the internal method updateIdle() halts the app because ReferenceError: updateIdle is not defined
Something tells me NONE of my instance methods are going to be "defined" even though they plainly are. And before I made them prototype methods, they worked fine. These would be a valid Java instance method invocations - is there some scope issue with JS?
Should I remove the Cache.prototype. from the functions I don't need exposed and then just use them? Do I have to add this. to any instance method invocations?
What do I need to know to make JS "just work" like normal OOP?

How to store previous result into a var

Pretty new to Javascript..
I have managed to script this simple code here:
var currentstock = 50;
function stockminus(x){
newcurrent = currentstock - x;
return newcurrent;
};
console.log(stockminus(10));
the output of this must be : 40
How can I store that new output into currentstock as the new value or in other words overwrite that var?
so next time I call that function again, output should be : 30
Becasue the new currentstock is 40 from the previous call
Simple, currentstock = stockminus(10)
The let statement declares a block scope local variable, optionally initializing it to a value.
So, every time you are working in the same scope you can do:
let currentstock = 50;
function stockminus(x) {
return currentstock -= x;
};
console.log(stockminus(10));
console.log(stockminus(10));
var stockDetails = (function(initialValue){
var currentStock = initialValue;
return {
getCurrentStock: function() {
return currentStock;
},
stockminus: function(x) {
//add additional logic to check negative cases
currentStock-= x;
return currentStock;
}
}
})(50);
you can use this type of modular patterns to access data using methods and later extend it as per needs.
access it like
stockDetails.getCurrentStock();
stockDetails.stockminus(10);

Loading image in Jquery and bad behavior

I have a little problem with a homemade script, first I'll give you the script
var heighti = $(window).height();
var imageLoading = new Array();
$('.fullHeight').css({'height' : heighti});
var now,hour,minute,second,dateNow = new Array(),countImg=0,i=0,countDateNow = 0;countImg=0,countThis=0,countDateNowAj=0;
/* GET THIS HOUR */
now = new Date();
hour = now.getHours();
minute = now.getMinutes();
second = now.getSeconds();
function date(){
//Function to get date
}
function loadImage(){
countThis = 0;
while(countThis < 6){
date();
var imgOn = 'uploads/original/'+dateNow[countDateNowAj]+'.jpg';
console.log(imgOn);
var img = $("<img />").attr('src', imgOn)
.load(function(){
imageLoading[i] = imgOn ;
i++;
})
.error(function(){
console.log('This is the image now : '+imgOn);
imageLoading[i] = 'images/noimage.jpg';
i++;
});
countThis++;
countDateNowAj++;
}
}
setInterval("dateImg()",1000);
setTimeout("loadImage()",0);
setInterval("loadImage()",5000);
So this is my function, everything works but when I want to do imageLoading[i] = imgOn; the script take always the last value.
This is a log of what I'm talking about : http://minus.com/mpWvBsXkQ
First I check the time
After I check the image who is gonna be checked
And at the end I check the name of imageLoading[i] = imgOn;
And I always get the last time and not every second.
I hope you'll understand my query.
In the load and error handler functions, you are using variables from the outer scope (in this case the scope will be the loadImage function) asynchronously, but they will be changed synchronously as part of the loop. If you want to have them held constant until the handlers are actually called, you will need to use a closure:
function loadImage(){
function imageLoader(i, imgOn) {
console.log(imgOn);
var img = $("<img />").attr('src', imgOn)
.load(function(){
imageLoading[i] = imgOn ;
})
.error(function(){
console.log('This is the image now : '+imgOn);
imageLoading[i] = 'images/noimage.jpg';
});
}
for(countThis = 0; countThis < 6; countThis++, countDateNowAj++) {
date();
imageLoader(i++, 'uploads/original/'+dateNow[countDateNowAj]+'.jpg');
}
}
In this case, the imageLoader inner function becomes the scope that the load and error handlers run in, so the values of i and imgOn are as you would expect rather than always being the last values they had when the loop finished running.
Declare the imageLoading outside the loop like
var imageLoading = [];

listing variables inside a function in javascript

function show_alert(){
var month = oMonthList.value;
var day = oDayField.value;
var gametype = oGameTypeList.value;
var gamenum = oGameNumberField.value;
var gamename = oGameNameField.value;
var modname = oModNameField.value;
var phase = oPhaseList.value;
var phasenum = oPhaseNumberField.value;
var pagenum = oNameNumberField.value;
var repname = oReplacementNameField.value;
var modlink = oModLinkField.value;
alert(phase);
}
Why does this not show the alert when the function is called, but removing all variables except the one in question (var phase) does? I'm guessing it's something to do with syntax, but I cannot pin down the issue.
Did you make sure that your javascript code doesn't throw any exception? If some object is undeclared or undefined, the code may be aborted early thus alert() is not not executed.

How to use javascript class from within document ready

I have this countdown script wrapped as an object located in a separate file
Then when I want to setup a counter, the timeout function in the countdown class can not find the object again that I have setup within the document ready.
I sort of get that everything that is setup in the document ready is convined to that scope,
however it is possible to call functions within other document ready´s.
Does anyone has a solution on how I could setup multiple counters slash objects.
Or do those basic javascript classes have to become plugins
This is the class
function countdown(obj)
{
this.obj = obj;
this.Div = "clock";
this.BackColor = "white";
this.ForeColor = "black";
this.TargetDate = "12/31/2020 5:00 AM";
this.DisplayFormat = "%%D%% Days, %%H%% Hours, %%M%% Minutes, %%S%% Seconds.";
this.CountActive = true;
this.DisplayStr;
this.Calcage = cd_Calcage;
this.CountBack = cd_CountBack;
this.Setup = cd_Setup;
}
function cd_Calcage(secs, num1, num2)
{
s = ((Math.floor(secs/num1))%num2).toString();
if (s.length < 2) s = "0" + s;
return (s);
}
function cd_CountBack(secs)
{
this.DisplayStr = this.DisplayFormat.replace(/%%D%%/g, this.Calcage(secs,86400,100000));
this.DisplayStr = this.DisplayStr.replace(/%%H%%/g, this.Calcage(secs,3600,24));
this.DisplayStr = this.DisplayStr.replace(/%%M%%/g, this.Calcage(secs,60,60));
this.DisplayStr = this.DisplayStr.replace(/%%S%%/g, this.Calcage(secs,1,60));
//document.getElementById(this.Div).innerHTML = this.DisplayStr;
$('#'+this.Div).text(this.DisplayStr);
$('#tel').text(parseInt( $('#tel').text() )+1);
if (this.CountActive) setTimeout(this.obj +".CountBack(" + (secs-1) + ")", 990);
}
function cd_Setup()
{
var dthen = new Date(this.TargetDate);
var dnow = new Date();
ddiff = new Date(dthen-dnow);
gsecs = Math.floor(ddiff.valueOf()/1000);
this.CountBack(gsecs);
}
and setting it up
$(document).ready(function() {
var cd1 = new countdown('cd1');
cd1.Div = "clk";
cd1.TargetDate = "08/15/2010 8:00 PM";
cd1.DisplayFormat = "%%D%% days, %%H%% hours, %%M%% minutes, %%S%% seconds until event AAA happens";
cd1.Setup();
firebug says it errors out with the timeout function
thanks, Richard
cd1 is defined in the local scope. setTimeout will run the function passed as parameter 1 in the window [global] scope, and in your case, window.cd1 is undefined.
The solution for your problem would to make cd1 a global variable. [Remove the "var" in your declaration of cd1]
Off topic: I recommend you look into using anonymous functions, as they can make your code much more pretty/legible at times.

Categories