I have a session variable that I want to update with a fixed periodicity. Say, I want this variable to be increased by 1 every 60 seconds.
It seems to me that the best place for doing this is inside the helpers section of the relevant template. I first tried to do this using setInterval as described here, but that didn't work (the function just didn't seem to repeat).
I then tried what I thought would be a straightforward solution, but this also doesn't work. See below. The helper variable 'currentPosition' is supposed to return the current minute of the day (plus an offset). However, it only does this when the template is first called and when the session variable 'offset' is changed in a function that's defined in the 'events' section, which responds to a click on a particular div (a 'next' button).
currentPosition: function () {
var d = new Date();
var h = d.getHours();
var m = d.getMinutes();
var w = h * 60 + m;
Session.set("position", w + Session.get("offset"));
return Session.get("position");
},
I would think that the above helper would actively update the value for 'currentPosition' every minute. Yet it does not.
So, my question is, how can I have a session variable change every, say, 60 seconds, increasing it by, say, 1, while the new value of the session variable is reflected within the app, when the variable is adjusted.
(If there's a straightforward and completely different solution which works in meteor, I'm not aware of it, so do point it out to me if I'm missing something obvious.)
Although you are using a reactive variable, it only gets set once - when the helper is first called. Therefore it doesn't run again. You need a function outside of the helper to set variable for you. Remember one important rule - helpers should never have side effects.
Here's a complete working example of how to create a timer:
html
<body>
{{> timer}}
</body>
<template name="timer">
<p>Total Seconds: {{seconds}}</p>
</template>
js
Template.timer.helpers({
seconds: function() {
return Template.instance().seconds.get();
}
});
Template.timer.created = function() {
var self = this;
this.seconds = new ReactiveVar(0);
this.handle = Meteor.setInterval((function() {
self.seconds.set(self.seconds.get() + 1);
}), 1000);
};
Template.timer.destroyed = function() {
Meteor.clearInterval(this.handle);
};
Related
Yes, I know that this is probably a very stupid question, but this has been bugging me for a while.
Ok, so I have been learning JavaScript for a while now and have understood everything perfectly. . .except for function "parameters" (I believe they are called).
I was taught that they work like so:
function test(number) {
document.write(number);
};
test(1);
test(12);
This makes perfect sense to me. However, recently, I've come across some that were a little different.
var counterDays = document.getElementById('days');
var counterHours = document.getElementById('hours');
var counterMinutes = document.getElementById('minutes');
var counterSeconds = document.getElementById('seconds');
var date = new Date('December 28, 2016 00:00:00');
function updateTimer(date) {
var time = date - new Date();
return {
'days': Math.floor(time / (1000 * 60 * 60 * 24)),
'hours': Math.floor((time/(1000 * 60 * 60)) % 24),
'minutes': Math.floor((time / 1000 / 60) % 60),
'seconds': Math.floor((time / 1000) % 60),
'total': time
};
};
function startTimer(counterDays, counterHours, counterMinutes, counterSeconds, date) {
var timerInterval = setInterval(function() {
var timer = updateTimer(date);
//Changes the text of the 'counter'
counterDays.innerHTML = timer.days;
counterHours.innerHTML = timer.hours;
counterMinutes.innerHTML = timer.minutes;
counterSeconds.innerHTML = timer.seconds;
window.onload = function() {
startTimer(counterDays, counterHours, counterMinutes, counterSeconds, date);
};
<span id="days"> </span>
<span id="hours"> </span>
<span id="minutes"> </span>
<span id="seconds"> </span>
What I seriously do not understand is why the updateTimer always needs date within the parentheses, when the variable date is an already existing variable within the global scope. Same with startTimer. I don't understand why I need to pass that in. Why not just access the variable within the function, as they do have a global scope, and be done with it. Instead I need to pass in the variable as a parameter, for the function to work.
I've tried and tried, but the only way to make the function work is by passing in the variables. Why is that???
As I am still learning, I've searched the internet for more information on functions and their parameters, but all show me something similar to my first example. I know this is all probably just going over my head, but for the life of me, I just do not understand.
Note: I am still learning, so sorry if this whole question is plain stupid.
Also, the the code for the JS that I am having a problem with won't actually run. This is due to me not wanting to put in all of my code, but rather just the code I am having trouble with.
Instead I need to pass in the variable as a parameter, for the
function to work.
You dont need to define your functions with parameters. You can invoke them leveraging higher scope variables
https://developer.mozilla.org/en-US/docs/Glossary/Scope
This:
var x = 'baz';
function foo(x) {
return x;
}
foo(x);
will do the same thing as:
var x = 'baz';
function foo() {
return x;
}
foo();
Writing functions that take parameters as input helps keep your code modular and side effect free among many other benefits...
1.) The second example will always throw an error if x is not accessible at a higher scope
2.) If another function mutated the value of x it would affect the output of the second example and would lead to unexpected and potentially hard to debug behavior in your application. Whereas I can always be sure of the output of the first example
3.) It is much easier to read through and maintain code that is written in the style of the first example
As I see see your code
var timer = updateTimer(date);
Kindly remove date parameter here as well as in the called function. Now the date variable will work as in global scope.
So it will be
function updateTimer()
{
//date variable will be present here as global variable
}
var timer = updateTimer();
Say I have a function that logs "Hello" every 500 ms.
var logHello = function() {
setInterval(function(){
console.log("Hello");
}, 500);
};
Is there a way to write another function that will check if logHello gets called more than or equal to 1 time every second(without modifying the original logHello function).
In this case it will return true because Hello will get logged 2 times in 1 seconds.
I am assuming you want to do this for debug reasons, so I must warn you not to include this code in any production application, as it's really just meant for debugging. It's very cool that our solution works however it overwrites native javascript functionality which is typically frowned upon because it can cause code to behave differently than expected if you alter a native functions behaviour.
If it's a condition that you are not allowed to modify your code, you can simply overwrite javascript's setInterval, and use it as a "hook" into your function. We will modify setInterval to now track the time difference (seconds) inbetween calls to your method. We will then invoke and return the original setInterval method so that your code still works exactly as expected:
// keep a pointer to the original setInterval function
var oldSetInterval = window.setInterval;
// we will create our own setInterval function and put logging in it
window.setInterval = function(block, interval) {
var lastRunAt;
return oldSetInterval(function() {
// here is where we print how long it's been since the method last ran
if(lastRunAt) {
console.log("the interval last ran " + (Date.now()-lastRunAt)/1000 + " seconds ago");
}
lastRunAt = Date.now();
block();
}, interval);
}
And now running logHello() yields:
Hello
the interval last ran 0.504 seconds ago
Hello
the interval last ran 0.504 seconds ago
Hello
the interval last ran 0.505 seconds ago
This assumes you're running on the web. If you're in node, replace references to window with globals.
I'm pretty sure I know the answer to this (and that it is no), but is it possible to create a variable that always returns the value of a function without "calling" the variable?
I'm sick of an inactivity warning on a website I use. I look at it a few times a day, but I keep it open in case there's an update I need to look at. It automatically signs me out after 15 minutes using some javascript--the token isn't invalidated by a cookie expiring, nor is my session removed server-side--and the variable it checks is called last_user_action.
I'd like to make last_user_action always point to new Date().getTime();.
last_user_action = function() { new Date().getTime(); }
would work if I could easily change all the references to last_user_action to instead belast_user_action(), but I can't.
last_user_action = (function() { return new Date().getTime(); })();
only sets the value once.
So like I said, I doubt there's a way to do this, but if it is possible, how would I do it?
EDIT
It occurs to me now, it'd be easier to just run
window.setInterval(function() { last_user_action = new Date().getTime(); }, 1000 * 60 * 10);
in Chrome's javascript console.
Well, if you are sure it works that way, you could use setInterval every minute to set the value:
setInterval(function(){
last_user_action = new Date().getTime();
},60000)
Not that directly, but it would be trivial to just update the variable periodically.
function updateLastUserAction() {
last_user_action = new Date().getTime(); // or Date.now();
setTimeout(updateLastUserAction, 10000); // run again in 10 seconds
}
updateLastUserAction();
You can change the update period to suit you - since the update function is extremely lightweight, you can run it pretty often and it won't matter.
Assuming last_user_action is a global variable, that means it's actually a property of window and you can define a getter for that property.
Object.defineProperty(window, 'last_user_action', {
get: function() {
return new Date().getTime();
}
});
last_user_action; // 1412882205169
last_user_action; // 1412882206490
This would normally be a bad idea, but given you are hacking here, it doesn't seem so bad.
AFAIK you can't do that with a variable.
But you can do it with a property, using a getter:
var obj = {};
Object.defineProperty(obj, 'last_user_action', {
get: function() { return new Date().getTime(); }
});
obj.last_user_action; // Current date time
I saved some data returned from ajax in javascript variable. I would like to invalidate this variable after some time period, say one hour.
I can potentially write some setTimeout functions to handle this, but I just feel this is not optimal.
Another way is to save in cookie and set expiration, but the overhead may be unnecessary.
Is there other way that can handle this situation more elegantly?
Assuming the actual variable actually exists that long (the page stays open), just do what every cache does: save a timestamp and check for it.
var cache = { timestamp : null, data : null };
function setData(data) {
cache.data = data;
cache.timestamp = new Date;
}
function getData(maxAge) {
if (/* compare cache.timestamp to now - maxAge */) {
return null;
}
return cache.data;
}
Keep a variable that indicates when the value expires.
var foo = "bar";
var foo_expires_on = new Date(new Date().getTime() + 60 * 60 * 5); // +5 hours
deceze's answer is a more formal (monad) implementation.
I have a snippet of JQuery code that do some bar scrolling.
Since I have three, four, ... n bar to slide into my PHP page, I assign them dinamically an id and pass it to JQuery for be sure that my snippet slide the correct bar on a mouseOver event.
That's the snippet of code that do the "inizialization" of my scrolls
(function($){
$.fn.horizontalScroll = function(options) {
var rid = arguments[0];
var oid = arguments[1];
var defaults = { };
var options = $.extend(defaults, options);
return this.each(function() {
var horiz_scroll = new dw_scrollObj($(this).attr('id'), $(this).children().attr('id'), $(this).children().children().attr('id'));
horiz_scroll.setUpScrollbar("dragBar_"+rid+"_offer_"+oid, "track_"+rid+"_offer_"+oid, "h", 1, 1);
horiz_scroll.setUpScrollControls('scrollbar_'+rid+'_offer_'+oid);
As you can see, "dragBar_"+rid+"_offer_"+oid dinamically concatenates my id(s) to other string part.
That's fine and all goin' well, except when my oid became something like -1
In that case I have an error that says
identifier starts immediately after numeric literal
That's confuse me, because i've read on StackOverflow some questions like this (just a random one) and I expect that behaviour for all concatenation that involves number.
That the snippet of code where all "breaks"
this.timerId = setInterval(this.animString + ".scroll()", 10);
Where this.animString is "dw_scrollObj.col.horiz_container_outer_55_offer_-1" while in other case (where it works) is "dw_scrollObj.col.horiz_container_outer_62_offer_234"
Anyone can explain me why this happen?
You are trying to access a global variable named dw_scrollObj.col.horiz_container_outer_55_offer_-1. Some browsers will make all elements accessible by their ID like that, but it's not recommended.
The reason it doesn't work in your specific case is that what you've written is not a valid javascript variable name. Your attempt to access a variable will be interpreted as
dw_scrollObj.col.horiz_container_outer_55_offer_ - 1
If you would instead access your object by
document.getElementById('dw_scrollObj.col.horiz_container_outer_55_offer_-1')
or
$('#dw_scrollObj.col.horiz_container_outer_55_offer_-1')
you would not have this same problem.
For your setInterval code, that would mean
this.timerId = setInterval("$('#" + this.animString + "').scroll()", 10);
or preferably
this.timerId = setInterval(function() {
$('#' + this.animString).scroll();
}, 10);
If your code is in a loop, where animString will change over time, inside the context, you will need to create a new closure:
this.timerId = setInterval((function(x) {
return function() {
$('#'+x).scroll();
};
})(this.animString), 10);
Your setInterval snippet breaks because the string you pass to setInterval is evaluated as JavaScript. It becomes
dw_scrollObj.col.horiz_container_outer_55_offer_-1.scroll()
but a hyphen (-) is not valid in identifiers.
E.g. this throws an error
var some-name = 'foo';