How to use javascript class from within document ready - javascript

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.

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?

Javascript calling a function in a function not defined classes

I am calling a method and want to have that method get the value of the returned value of the second method, to be able to use the variable in an element.
I always was able to call a function by putting the function in the other function. It seems when using classes I am unable to achieve this.
Do I have to use a callback method of some sort. I am new to classes.
class Bills{
constructor(amount,payment,duedate,apr){
this.amount = amount;
this.payment = payment;
this.duedate = duedate;
this.total = total;
this.apr = apr;
}
amountByMonth(billings){
//This is the function I am calling inside the function to get the value of.
let dueDays = daysLeft(billings);
const items = document.getElementById('bills');
const newitem = document.createElement('ul');
newitem.innerHTML = `
<li>Monthly Amount Due :${billings.amount}</li>
<li>Monthly Amount Due :${dueDays}</li>
<li>Total On Card: ${billings.total}</li>`;
items.appendChild(newitem);
}
daysLeft(billings){
let date1 = new Date();
let dueDate = new Date(billings.duedate);
let timeDiff = Math.abs(dueDate.getTime() - date1.getTime());
let diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
console.log(diffDays);
return diffDays;
}
}// end
document.getElementById('subBtn').addEventListener('click',valueinput);
function valueinput(e){
let amount = document.getElementById('payment').value;
let total = document.getElementById('total').value;
let duedate = document.getElementById('dues').value;
let billings = new Bills();
billings.amount = amount;
billings.duedate = duedate;
billings.total = total;
billings.daysLeft(billings);
billings.amountByMonth(billings);
e.preventDefault();
}
You need to make it clear that you are calling another method of the same class and not a different function by using this:
When you declare a class method without the function keyword, you're basically declaring it as a functional property of the class object. To refer back to the property, you need to put it in the context of the object it's defined in, i.e.
let dueDays = this.daysLeft(billings);
You must use this, for example if you want to call function inside the class function you must use this to your class knows the reference. So your code should looks like:
amountByMonth(billings){
let dueDays = this.daysLeft(billings);
// Rest of your code
}

ReferenceError: count_1 is not defined in a Joomla module

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.

Hangman-Timer speed increasing when creating a new object (JavaScript)

Currently programming Hangman and I have the following problem:
When I create a new HangmanController (choosing a new word, ...) the timer works fine, the only thing is, when I create one more HangmanController, the speed is 2x faster, when I create one more HangmanController 3x, etc.
I create a HangmanController only when
Where's the problem? Or how can I make the timer better?
//Here's where I create a new HangmanController. This happens when the user changes the difficulty (pressing a button in the HTML)
function inithm(difficulty) {
hm = new HangmanController();
hm.hmModel.reset(hm.displayedWord.word, false, difficulty);
UsedLetters();
};
//Constructor
HangmanController = function() {
this.hmModel = new HangmanModel();
//this.hmView = new HangmanView(document.getElementById('hm_view'));
this.displayedWord = new DisplayedWord();
this.userGuessField = document.getElementById('guessfield');
this.userGuessField.focus();
this.guessbutton = document.getElementById('guessbutton');
this.guessbutton.disabled = false;
/*this.updateTime = function(stopwatch) {
var e = stopwatch.getElapsed();
document.getElementById('stopwatch').innerHTML = e.hours * 60 + e.minutes + ' mins' + e.seconds + ' secs';
};*/
this.stopwatch = new Stopwatch();
};
//Timer, it is only called here, nowhere else (at setInterval)
Stopwatch = function() {
this.sek = 0;
setInterval(function() {timer();}, 1000);
};
function timer() {
document.getElementById('stopwatch').innerHTML = this.hm.stopwatch.sek;
this.hm.stopwatch.sek++;
}
Stopwatch.prototype.stop = function() {
document.getElementById('stopwatch').innerHTML = 0;
};
You are creating several instances of Stopwatch with each HangmanController, and everyone of them is calling timer() every second, which results in your #stopwatch element beeing increased more often than just once a second ;-)
edit: You should either dispose of the old HangmanController (especially the Stopwatch functionality) before creating a new one, or instead only create one instance of HangmanController, and make a method for restarting, or difficulty changes, etc..

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 = [];

Categories