Template.destroyed() not called - javascript

I'm displaying a timer showing the elapsed time since a collection item was created. However, when I navigate between Items (switch routes/url) the timer doesn't get destroyed and I end up having a bunch of leaked timers.
I could keep a reference to the timer and kill it in the router but I would prefer a cleaner way and handle it in the template. Any ideas?
<template name="itemDetails">
{{elapsedTime}}
</template>
Template.itemDetails.onRendered = function() {
var startTime = Template.currentData().startTime;
this.timeElapsed = new ReactiveVar;
this.taskTimer = Meteor.setInterval(function() {
var timeElapsedInMS = Date.now() - startTime;
var date = new Date(timeElapsedInMS);
var hours = (date.getUTCHours() < 10 ? '0' :'') + date.getUTCHours();
var minutes = (date.getUTCMinutes() < 10 ? '0' :'') + date.getUTCMinutes();
var seconds = (date.getUTCSeconds() < 10 ? '0' :'') + date.getUTCSeconds();
var timeElapsed = hours + ":" + minutes + ":" + seconds;
this.timeElapsed.set(timeElapsed);
console.log(timeElapsed);
}, 1000);
}
Template.itemDetails.helpers({
elapsedTime: function() {
return Template.timeElapsed.get();
}
});
Template.itemDetails.onDestroyed = function() {
Meteor.clearInterval(this.taskTimer);
}

I would do like this (template level) as well. Here is a quick example of how you could do a timer at template level:
<template name="test">
<p>Count: {{time}}</p>
</template>
Template.test.onCreated(function() {
var self = this;
self.time = new ReactiveVar(0);
self.taskTimer = Meteor.setInterval(function() {
self.time.set(self.time.get() + 1)
}, 1000);
});
Template.test.onDestroyed(function() {
Meteor.clearInterval(this.taskTimer);
});
Template.test.helpers({
time: function() {
var self = Template.instance();
return self.time.get();
}
});
I hope you can continue from here =)

Related

The element will not take a textContent input

When I click the date value I'm having this error: Uncaught TypeError: Cannot read property 'textContent' of undefined
This is my code can you help me in determining the source of the error and how can I correct this?
function Timer(elem) {
var time = 3000;
var interval;
var offset;
function update() {`enter code here`
time += delta();
var formattedTime = timeFormatter(time);
elem.textContent = formattedTime;
}
function delta() {
var now = Date.now();
var timePassed = now - offset;
offset = now;
return timePassed;
}
function timeFormatter(timeInMilliseconds) {
var time = new Date(timeInMilliseconds)
var minutes = time.getMinutes().toString();
var seconds = time.getSeconds().toString();
if (minutes.length < 2) {
minutes = '0' + minutes;
}
if (seconds.length < 2) {
seconds = '0' + seconds;
}
return minutes + ' : ' + seconds;
}
this.isOn = false;
this.start = function() {};
if (!this.isOn) {
interval = setInterval(update, 10);
offset = Date.now();
this.isOn = true;
}
};
this.stop = function() {
if (this.isOn) {
clearInterval(interval);
interval = nul;
this.isOn = false;
}
};
this.reset = function() {};
Edited version for the other errors.
function Timer(elem) {
var time= 0;
var offset;
var interval;
function update() {
if (this.isOn) {
time += delta();
var formattedTime = timeFormatter(time);
}
elem.textContent = formattedTime;
}
function delta() {
var now = Date.now();
var timePassed = now - offset;
offset = "5:00";
return timePassed;
}
function timeFormatter(time) {
time = new Date(time);
var minutes = time.getMinutes().toString();
var seconds = time.getSeconds().toString();
if (minutes.length < 2) {
minutes = '0' + minutes;
}
if (seconds.length < 2) {
seconds = '0' + seconds;
}
return minutes + ' : ' + seconds;
}
this.start = function() {
interval = setInterval(update.bind(this), 10);
time++;
this.isOn = true;
};
this.stop = function() {
clearInterval(interval)
interval = null;
this.isOn = false;
};
this.reset = function() {
time= 300;
update();
};
this.isOn = false;
}

Alert returning as undefined

I am trying to have my alert show up with the time that my timer shows.
function Stopwatch(elem) {
var time = 0;
var offset;
var interval;
function update() {
if (this.isOn) {
time += delta();
}
elem.textContent = timeFormatter(time);
}
function delta() {
var now = Date.now();
var timePassed = now - offset;
offset = now;
return timePassed;
}
function timeFormatter(time) {
time = new Date(time);
var minutes = time.getMinutes().toString();
var seconds = time.getSeconds().toString();
var milliseconds = time.getMilliseconds().toString();
if (minutes.length < 2) {
minutes = '0' + minutes;
}
if (seconds.length < 2) {
seconds = '0' + seconds;
}
while (milliseconds.length < 3) {
milliseconds = '0' + milliseconds;
}
return minutes + ' : ' + seconds + ' . ' + milliseconds;
}
this.start = function() {
interval = setInterval(update.bind(this), 10);
offset = Date.now();
this.isOn = true;
};
this.stop = function() {
clearInterval(interval);
interval = null;
this.isOn = false;
};
this.reset = function() {
time = 0;
update();
};
this.isOn = false;
}
var timer = document.getElementById('timer');
var toggleBtn = document.getElementById('toggle');
var resetBtn = document.getElementById('reset');
var watch = new Stopwatch(timer);
function start() {
toggleBtn.textContent = 'Stop';
watch.start();
}
function stop() {
toggleBtn.textContent = 'Start';
watch.stop();
}
toggleBtn.addEventListener('click', function() {
watch.isOn ? stop() : start();
});
resetBtn.addEventListener('click', function() {
watch.reset();
});
function alertSystem(){
var timer = document.getElementById('timer')
alert(timer);
}
<h1 id="timer">00 : 00 . 000</h1>
<div>
<button class=button id="toggle">Start</button>
<button class=button id="reset">Reset</button>
<button onclick='alertSystem()'>get number</button>
</div>
It's a lot of code, but it is mostly to get the timer working. The last function called alertSystem() is on the bottom and is the one that triggers the alert call. For me the alert shows up as [object HTMLHeadingElement] or as undefined. The former comes up when I have alert(timer); but if I do alert(timer.value); or alert(timer.length); I get the latter.
Does anyone know how I can just get the value of the timer in the alert?
To get the timer's value, you should do something like:
document.querySelector('#timer').innerHTML
Otherwise , document.getElementById returns a full element as a js object.

Angular 2+ timer function is not working in one of the components

This is very very very strange. I got an timer function which works on all my components except 1. But I just don't know why, I also don't get any errors or something.
What am I missing? The code that I use looks like this:
The HTML
<p>Time in miliseconds: <b id="tick">{{time}}</b></p>
and in my protected.component.ts
timeBegin = new Date();
starts = null;
time = '00:00:00.000';
GetUser(): void {
this.startTime();
this.dataService.getUser().subscribe(res => {
if (res !== undefined) {
this.dataIsReady = true;
this.imgSrc = 'data:image/png;base64,' + res['image'];
}
});
this.stopTime();
}
public clockRun() {
const currentTime = new Date();
const timeElapsed = new Date(currentTime.getTime() - this.timeBegin.getTime());
const hour = timeElapsed.getUTCHours();
const min = timeElapsed.getUTCMinutes();
const sec = timeElapsed.getUTCSeconds();
const ms = timeElapsed.getUTCMilliseconds();
this.time =
(hour > 9 ? hour : '0' + hour) + ':' +
(min > 9 ? min : '0' + min) + ':' +
(sec > 9 ? sec : '0' + sec) + '.' +
(ms > 99 ? ms : ms > 9 ? '0' + ms : '0' + ms);
}
startTime() {
this.timeBegin = new Date();
this.starts = setInterval(this.clockRun.bind(this), 10);
}
stopTime() {
clearInterval(this.starts);
}
I guess you could simplify it a bit. For example:
In HTML better to use DatePipe, like:
{{ interval | date:'HH:mm:ss SSS':'+0000'}}
In Component:
timeBegin: Date;
interval: Date;
ngOnInit() {
this.timeBegin = new Date();
setInterval(this.tick.bind(this), 100);
}
tick() {
let currentTime = new Date();
this.interval = new Date(currentTime.valueOf() - this.timeBegin.valueOf());
}
Also in your example, you immediate stop the time and as result don't see progress. Try to execute stopTime within subscribe block, for example:
GetUser(): void {
this.startTime();
this.dataService.getUser().subscribe(res => {
if (res !== undefined) {
this.dataIsReady = true;
this.imgSrc = 'data:image/png;base64,' + res['image'];
}
this.stopTime();
});
}

localStorage how to save countdown value so it wont reset when I reload the page

When I reload the page, my 1 minute countdown also reloads.
I tried to use localStorage but it seems to me failed.
Please have a look, I do not know where I should fix.
Thank you
My script
/* for countdown */
var countDown = (function ($) {
// Length ms
var timeOut = 10000;
// Interval ms
var timeGap = 1000;
var currentTime = (new Date()).getTime();
var endTime = (new Date()).getTime() + timeOut;
var guiTimer = $("#clock");
var running = true;
var timeOutAlert = $("#timeout-alert");
timeOutAlert.hide();
var updateTimer = function() {
// Run till timeout
if(currentTime + timeGap < endTime) {
setTimeout( updateTimer, timeGap );
}
// Countdown if running
if(running) {
currentTime += timeGap;
if(currentTime >= endTime) { // if its over
guiTimer.css("color","red");
}
}
// Update Gui
var time = new Date();
time.setTime(endTime - currentTime);
var minutes = time.getMinutes();
var seconds = time.getSeconds();
guiTimer.html((minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
if (parseInt(guiTimer.html().substr(3)) <= 10){ // alert the user that he is running out of time
guiTimer.css('color','red');
timeOutAlert.show();
}
};
var pause = function() {
running = false;
};
var resume = function() {
running = true;
};
var start = function(timeout) {
timeOut = timeout;
currentTime = (new Date()).getTime();
endTime = (new Date()).getTime() + timeOut;
updateTimer();
};
return {
pause: pause,
resume: resume,
start: start
};
})(jQuery);
jQuery('#break').on('click',countDown.pause);
jQuery('#continue').on('click',countDown.resume);
var seconds = 60; // seconds we want to count down
countDown.start(seconds*1000);
I tried to fix it but I dont know where/how to put localStorage.
This may help you.
HTML Code:
<div id="divCounter"></div>
JS Code
var test = 60;
if (localStorage.getItem("counter")) {
if (localStorage.getItem("counter") <= 0) {
var value = test;
alert(value);
} else {
var value = localStorage.getItem("counter");
}
} else {
var value = test;
}
document.getElementById('divCounter').innerHTML = value;
var counter = function() {
if (value <= 0) {
localStorage.setItem("counter", test);
value = test;
} else {
value = parseInt(value) - 1;
localStorage.setItem("counter", value);
}
document.getElementById('divCounter').innerHTML = value;
};
var interval = setInterval(function() { counter(); }, 1000);

Trying to display and update map markers using Leaflet JS

I'm trying to display countdown timers until each of my markers disappear on my map. The markers disappear when their respective timers run out, but the timers themselves are not displaying below the markers themselves as they should. I checked the Developer Console and noticed there are a couple errors:
Uncaught TypeError: Cannot read property 'innerHTML' of null
Uncaught ReferenceError: component is not defined
This error count keeps increasing until it stops at a high number. I'm guessing this is when the particular timer runs out because after that number stops climbing the same error is logged again and the number starts from 1 and continues to climb.
L.HtmlIcon = L.Icon.extend({options: {},
initialize: function(options) {
L.Util.setOptions(this, options);
},
createIcon: function() {
//console.log("Adding pokemon");
var div = document.createElement('div');
div.innerHTML =
'<div class="displaypokemon" data-pokeid="' + this.options.pokemonid + '">' +
'<div class="pokeimg">' +
'<img src="data:image/png;base64,' + pokemonPNG[this.options.pokemonid] + '" />' +
'</div>' +
'<div class="remainingtext" data-expire="' + this.options.expire + '"></div>' +
'</div>';
return div;
},
createShadow: function() {
return null;
}
});
var map;
function deleteDespawnedPokemon() {
var j;
for (j in shownMarker) {
var active = shownMarker[j].active;
var expire = shownMarker[j].expire;
var now = Date.now();
if (active == true && expire <= now) {
map.removeLayer(shownMarker[j].marker);
shownMarker[j].active = false;
}
}
}
function createPokeIcon(pokemonid, timestamp) {
return new L.HtmlIcon({
pokemonid: pokemonid,
expire: timestamp,
});
}
function addPokemonToMap(spawn) {
var j;
var toAdd = true;
if (spawn.expiration_timestamp_ms <= 0){
spawn.expiration_timestamp_ms = Date.now() + 930000;
}
for (j in shownMarker) {
if (shownMarker[j].id == spawn.encounter_id) {
toAdd = false;
break
}
}
if (toAdd) {
var cp = new L.LatLng(spawn.latitude, spawn.longitude);
var pokeid = PokemonIdList[spawn.pokemon_id];
var pokeMarker = new L.marker(cp, {
icon: createPokeIcon(pokeid, spawn.expiration_timestamp_ms)
});
shownMarker.push({
marker: pokeMarker,
expire: spawn.expiration_timestamp_ms,
id: spawn.encounter_id,
active: true
});
map.addLayer(pokeMarker);
pokeMarker.setLatLng(cp);
}
}
//TODO:<--Timer Functions-->//
function calculateRemainingTime(element) {
var $element = $(element);
var ts = ($element.data("expire") / 1000 | 0) - (Date.now() / 1000 | 0);
var minutes = component(ts, 60) % 60,
seconds = component(ts, 1) % 60;
if (seconds < 10)
seconds = '0' + seconds;
$element.html(minutes + ":" + seconds);
}
function updateTime() {
deleteDespawnedPokemon();
$(".remainingtext, .remainingtext-tooltip").each(function() {
calculateRemainingTime(this);
});
}
setInterval(updateTime, 1000);
//<--End of timer functions-->//
Here is my JSFiddle for a full view of the situation.
Any idea what I'm doing wrong?
SolutionThanks to user T Kambi for pointing out the issue!
I forgot to include the component() function.
function component(x, v) {
return Math.floor(x / v);
}
After including this all works as intended.

Categories