Meteor Helpers - DOM Manipulation - javascript

// Works
var counter = 0;
var myInterval = Meteor.setInterval(function(){
counter++;
var time = moment().hour(0).minute(0).second(counter).format('HH:mm:ss');
console.log(time);
}, 1000);
// Inside Helper - Does Not Work
Template.clockRunner.helpers({
start: function () {
var counter = 0;
var time = moment().hour(0).minute(0).second(counter).format('HH:mm:ss');
var myInterval = Meteor.setInterval(function(){
counter++
}, 1000);
return time;
},
})
The first version console logs the time in increments of 1 second. The Helper version displays "00:00:00" in the DOM, but does not increment, if I console log the time in helper it logs "00:00:00" every second.
I'm not sure if I'm misunderstanding the reactive nature of helpers or if I'm not seeing a minor mistake. Thanks in advance!

a helper is meant to provide data to a Blaze template; it won't get called unless invoked from a template.
that said, you should think of a helper as something that only provides data, it shouldn't "do anything." as a template renders, and as reactive data is processed, a helper may get called several times in unexpected ways.
i reckon you want your timer to be started in the onRendered() method; that is called once as a template is put on the screen. (there's a corresponding method that's called when the template is taken off the screen, so the timer can be stopped).
once your timer is started, you can write timer data to a reactive variable, and then a helper that returns a formatted version of that timer data. because it's in a reactive var, that will ensure your helper is re-invoked each time the timer ticks.
the last part is simply ensuring the Blaze template references the helper.

Related

React JS synchronous handling of array.map

I am very new to React JS and in some ways javascript here is the problem I am trying to solve. I have a function in a component that looks like the below that iterates through an array of numbers:
playerSequence: function() {
var game = this;
this.state.game.sequence.map(function(currNum){
console.log(currNum);
switch(currNum){
case 1:
game.handleBlue();
break;
case 2:
game.handleYellow();
break;
case 3:
game.handleGreen();
break;
case 4:
game.handleRed();
break;
}
})
},
Each function call has a setTimeout that waits a period of time and renders a light and then switches off the light after this.props.wait ms. Below is an example:
var RedOn = React.createClass({
mixins: [TimerMixin],
componentDidMount: function () {
this.setTimeout(function(){this.props.handleRed()}, this.props.wait);
},
handleRed: function() {
this.props.handleRed()
},
renderstuff
});
What I would like is for each pass through the map array to wait until the function call is finished and then continue. As it is right now they all go off at the same time. I am sure I am not fully understanding the nature of node, react or a combo of both. Any help would be appreciated.
According to the React docs, componentDidMount is Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.
So it would make sense that they would all fire at once. The other problem is that setTimeout is invoked as soon as its called, which means if you pass some time in milliseconds to each function, map will simply invoke them all at once, not apply them sequentially. If you wanted to keep using map, you should declare a variable to store previous time applied, and add it into each timeout.
var previousTime = 0;
["foo", "bar", "baz"].map( function(e) {
setTimeout( function() { console.log(e); }, 1000 + previousTime);
previousTime += 1000; });
Here's a trivial example of what I'm describing. Try running this in a console to see the result. Every time you call "setTimeout" you add the time to the previousTime variable, so that each element waits an additional second before showing.
At the end of the day, even with all the abstractions offered by React, remember It'sJustJavaScriptâ„¢

Taking actions on inactive page in angular

I'm new to AngularJS, coming from a jQuery background. At the moment I take my first steps and create some sample pages with Angular.
Now I wanted to achieve some thing like this: Think of an app with two "pages". First is the main page with some text etc and on the other theres running a timer. The timer should start from 0 and count up to infinite by every second, right when you started the app. This is the first thing I cannot achieve. My timer only starts when I navigate to the second page.
The second problem: When the timer is running, I want to navigate through all the pages in the app and the timer should still count in the background. Well, at the moment it does run in the background, but every time when I navigate to the page with the timer, it seems like there gets opened another task that count the timer up, resulting in a very infrequent and faster counting.
On my index html I use ng-view to insert the other pages by ngRoute. This works fine.
My timer page looks like this:
<div ng-controller="TimeCtrl">
<p>Counter: {{counter.getValue()}}</p>
</div>
Then I wrote a timer controller for my app:
app.controller("TimeCtrl", function($scope, $interval, Counter){
$scope.counter = Counter;
$interval(function(){
$scope.counter.update();
}, 1000);
});
And there's a counter factory:
app.factory("Counter", function () {
this.counter = 0;
var self = this;
return {
update : function () {
self.counter++;
},
getValue : function () {
return self.counter;
}
}
});
I would appreciate any help as Angular does not come that easy for me in the beginning.
Instead of using the $interval on the controller, use it on the service/factory:
app.factory("Counter", function ($interval) {
this.counter = 0;
var self = this;
$interval(function(){
self.update();
}, 1000);
return {
update : function () {
self.counter++;
},
getValue : function () {
return self.counter;
}
}
});
This way if your TimeCtrl gets destroyed (for whatever reason), the counter will still get incremented.
Note also that every time you re-open a page that creates a new TimeCtrl, a new interval will also be defined. That's why you are getting that "infrequent and faster counting".
Regarding it being loaded only on the second page, make sure that you add the Counter service as dependency to your main controller, so that the service gets instantiated immediately (otherwise the counter will not start). If you do not have a main controller, use a run block:
app.run(function(Counter) {
// just inject the Counter so that it gets instantiated
})

KnockoutJS - Recalculate computed values with a set time interval

I have this code here
self.timestamp = ko.observable(data.timestamp);
self.dateFromNow = ko.computed(function ()
{
return moment(self.timestamp()).fromNow();
}, self);
self.timestamp is simply a unix timestamp
self.dateFromNow looks something like 44 years ago or 1 minute ago
My goal is for self.dateFromNow to recompute every set time interval.
These properties are bound to HTML <time> elements but I don't want to do the recomputation by using JS/jQuery to go over the elements and recompute.
I think a better way would be just to simply recalculate the values in KnockoutJS every set time interval and let KO update the markup.
Is there a way to do this in KnockoutJS?
UPDATE: What I did was something like this in lieu of the poster's answer
setInterval(function() {
$.each(self.foo(), function(index, item) {
item.timestamp.notifySubscribers();
});
}, 60 * 1000); // 60 * 1000 milsec
Another way to handle this would be to re-evaluate the computeds whenever another observable changes value, which changes on an interval. Sound crazy?
var fireEvaluations = ko.observable(0);
// Somewhere after the DOM is ready
setInterval(function () {
fireEvaluations(fireEvaluations() + 1);
}, 6000);
var someOtherObservable = ko.computed(function () {
// Subscribe to the triggering observable
if (fireEvaluations()) { }
// Do your real code
});
Now all computeds which have something like if (fireEvaluations()) { } will re-evaluate once that value changes.
Not built into knockout, no (at least, not as far as I know). It has a mechanism (throttling) that limits how often view model changes are propagated through, but obviously that's not what you're after. Arguably you should have a member on your view model that you bind through to your element, and then it's your responsibility to update your view model periodically.

Backbonejs: check server periodically

I'm trying to have my backbone application check the server as often as possible for updates to a model, similar to how twitter's site has new tweets that are automatically added.
My current setup is checking an external application through their api so I have no access to their server which leaves me to rely on the client side to do the checking without being too memory hungry, how can I achieve this?
In Javascript the only way you can really control timing is through setTimeout/setInterval; there is no "more sophisticated" mechanism, unless you count helper functions (eg. 'delay') which just wrap setTimeout/setInterval.
So, dmi3y's answer was correct. However, since you mentioned Backbone in both the tags and in the description, here's a more Backbone-ish version...
var YourModelClass = Backbone.Model.extend({url: remoteUrl});
var instance = new YourModelClass();
var seconds = 5;
window.setInterval(_.bind(instance.fetch, instance), 1000 * seconds);
or, if you wanted to build it in to your class ...
var YourModelClass = Backbone.Model.extend({
url: remoteUrl,
initialize: function() {
var seconds = 5;
window.setInterval(_.bind(this.fetch, this), 1000 * seconds);
}
});
var instance = new YourModelClass();
It's also worth mentioning that setInterval returns an object which you can pass to clearInterval if you want to stop "polling".
P.S. Just in case you're not familiar with _.bind, it comes from the Underscore library, which Backbone depends on so you already have it. All it does is fix this in place, so that when your timeout/interval function resolves, the this inside it will be the second argument to _.bind (and not window, which is what it would normally be).
possible solution
(function IcallTheShoots(){
console.log('am I?'); // any way you able communicate with server
window.setTimeout(IcallTheShoots, 1500);
})();
why setTimeout instead of setInterval, cause it makes sure next cycle will be called only when current is finished

How can I run some code on all the nodes in a tree?

I want to run some code on all my treeView nodes depending on a value returned from the database and repeat this until a certain value is returned.
I was thinking that:
Give all my tree nodes the same css class so I can access them from JQuery
have a timer in my JQuery function that used ajax to go to the database, when a certain value is returned then stop the timer
Two questions here. How can I make my function run for each of the nodes and how do I do a timer in JavaScript, so:
$(function(){
$('cssClassOfAllMyNodes').WhatFunctionToCallHere?((){
//How do I do Timer functionality in JavaScript?
ForEachTimeInterval
{
//use Ajax to go to database and retrieve a value
AjaxCallBackFunction(result)
{
if (result = 1)
//How to stop the timer here?
}
}
});
});
Hope i'm clear. Thanks a lot
thanks a lot for the answer. And i would like you to comment on the design.
Bascially what i'm trying to acheive is a Windows Wokflow type functionality where each node in my tree updates its image depending on its status, where its status is got from querying the database with a key unique to the tree node. I'm open to ideas on other ways to implement this if you have any. thanks again
Without commenting on your design you can refer to these
$.each()
setTimeout() or setInterval()
You can do:
$(function(){
$('cssClassOfAllMyNodes').each(function (){
// Do something with "this" - "this" refers to current node.
});
});
Te proper way to handle timers in JS is to have a reference to each timeout or interval and then clearing them out.
The difference between them is:
The timeout will only run once, unless stopped before;
The interval will run indefinitely, until stopped.
So you can do something like:
var delay = 2000; // miliseconds
var timer = setTimeout("functionToBeCalled", delay);
clearTimeout(timer); // whenever you need.
Please note you can pass a string to setTimeout (same with setInterval) with the name of the function to be called. Or you could pass a reference to the function itself:
var callback = function () { alert(1); };
var timer = setTimeout(callback, delay);
Be sure not to set an Interval for AJAX requests, because you response might be delayed and successive calls to the server could eventually overlap.
Instead, you should call setTimeout and when the answer arrives then call setTimeout again.

Categories

Resources