Javascript element.style.opacity is undefined. Why? - javascript

I am trying to make a JS function that flickers an element. I use a setInterval() for timing, but it gives the error message Uncaught TypeError: Cannot read property 'opacity' of undefined.
When I try to modify the opacity not with a timer, but "by hand", that works...
What am I doing wrong?
Usage:
document.getElementById('idOfTheElement').startFlicker();
The function:
Element.prototype.startFlicker = function() {
var blinkInterval = setInterval(function() {
if (parseInt(this.style.opacity) === 0) {
this.style.opacity = 1;
} else {
this.style.opacity = 0;
}
}, 50);
};

Try this
Element.prototype.startFlicker = function() {
var self = this;
var blinkInterval = setInterval(function() {
if (parseInt(self.style.opacity) === 0) {
self.style.opacity = 1;
} else {
self.style.opacity = 0;
}
}, 50);
};
In setInterval this refers to window, you need store context (this - current element) in variable and use in setInterval

Because of the context. this.style inside the setInterval refers to the global window object.

You could always make a reference to the element itself, because inside the setInterval function, the window object is passed as this.
Instead, you should give .bind() a try. So this will be a reference to the argument of the method.
Element.prototype.startFlicker = function() {
var blinkInterval = setInterval(function() {
if (parseInt(this.style.opacity) === 0) {
this.style.opacity = 1;
} else {
this.style.opacity = 0;
}
}.bind(this), 50);
};

Related

How to run number statements as sequence with javascript?

I am trying to running some statements as sequence with javascript and wrote this codes but did not work.Please advice
var repeat = true;
var bootstrap = false;
function fifteen() {
document.getElementsByClassName("progress-bar")[0].setAttribute("style", "width:50%");
//document.getElementsByClassName("progress-bar")[0].style.width = "width:50%";
}
function sixteen() {
if ( bootstrap != true) {
document.getElementsByClassName("progress-bar")[0].setAttribute("style", "width:70%");
}
}
var i = 0;
function onehundred() {
if (bootstrap === true) {
document.getElementsByClassName("progress-bar")[0].setAttribute("style", "width:100%");
console.log(++i);
}
};
function clear() {
if (document.getElementsByClassName("progress-bar")[0].style.width === "100%") {
clearInterval(r1);
clearInterval(r2);
clearInterval(r3).done(function() {
document.getElementsByClassName("progress-bar")[0].style.display = "none";
document.getElementById("content").className = "";
});
}
}
//repeet this work
var r1= setInterval(function () { sixteen(); }, 100);
var r2= setInterval(function () { onehundred(); }, 100);
var r3 = setInterval(function () { clear(); }, 100);
Error in console:
Uncaught TypeError: Cannot read property 'done' of undefined
clearInterval returns undefined. You can't just chain .done methods off of anything in JavaScript.
clearInterval is synchronous, regardless. Just place those statements after it.
clearInterval(r3);
document.getElementsByClassName("progress-bar")[0].style.display = "none";
document.getElementById("content").className = "";
If you really wanted this functionality, you would need to override the existing clearInterval, but this is borderline stupid, creating confusing looking code that implies asynchronous flow where there is none.
(function () {
var old = clearInterval;
clearInterval = function (id) {
old(id);
return {
done: function (fn) {
fn();
}
};
};
}());

how to execute second method only after first method is executed

I want to print a heading tag only after a paragraph tag is loaded. Below is my Javascript code. See the plunker for more clarification: http://embed.plnkr.co/aheHkSQUBft5A4Z3wkie/preview
function changeText(cont1, cont2, speed){
var Otext = cont1.text();
var Ocontent = Otext.split("");
var i = 0;
function show() {
if (i < Ocontent.length) {
cont2.append(Ocontent[i]);
i = i + 1;
};
};
var Otimer = setInterval(show, speed);
};
$(document).ready(function() {
changeText($("p"), $(".p2"), 30);
clearInterval(Otimer);
});
$(document).ready(function() {
changeText($("h2"), $(".h2"), 30);
clearInterval(Otimer);
});
I would do something like this (please not that ES6 Promises aren't supported by Internet Explorer, but there are shims to use Promises with old browsers too).
You'll have to fill out the parts commented to get it to work though:
var Otimer;
/*#TODO: refactor show() function to use ES6 Promises (eventually with shims) */
function show(Ocontent) {
var i = 0;
if (i < Ocontent.length) {
cont2.append(Ocontent[i]);
i = i + 1;
};
if (Otimer === undefined) {
Otimer = setInterval(show, speed); // Remember to fulfill the promise and remove the interval once it's finished
}
// return the promise
};
function changeText(p1, p2, speed) {
var Otext = p1.text();
var Ocontent = Otext.split("");
return show(Ocontent);
};
$(function () {
changeText($("p"), $(".p2"), 30).then(function() { // We call changeText the second time after the promise return by changeText() is fulfilled and the show() function has finished
Otimer = undefined;
changeText($("h2"), $(".h2"), 30);
});
});
first of all, variable declaring inside of function is scoped variable, which You cannot access from outside of the function.
so the line clearInterval(Otimer); never works.
the code below is fixed code of the scope issue and using callback to implement what you want.
function changeText(cont1, cont2, speed, cb) {
var Otext = cont1.text();
var Ocontent = Otext.split("");
var i = 0;
function show() {
if (i < Ocontent.length) {
cont2.append(Ocontent[i]);
i++;
}else{
clearInterval(Otimer)
if(cb) cb()
}
};
var Otimer = setInterval(show, speed);
};
$(document).ready(function() {
changeText($("p"), $(".p2"), 30, function(){
changeText($("h2"), $(".h2"), 30);
});
});
http://plnkr.co/edit/xowItFUWqI79obi4ZVNV?p=preview

unbind/turn off a function in jquery

Good day all, I'm trying to make a jquery game where a group of enemy will spawn after a group of enemy gets destroyed. I'm calling alien_cruiser() function & unbinding minion_roulette() function after minion_roulette_counter gets 0. But every time I run, function does not get unbind & after counter gets 0 both type of enemies show. I want to run them one by one. Here are the codes:
var sound = new Audio("sounds//dishoom.ogg");
var score = 0;
var minion_roulette_life = 10;
var cruiser_life = 20;
var minion_roulette_counter = 3;
var cruiser_counter = 3;
function processBullet() {
$(".projectile").each(function() {
var maxTop = $(this).offset().top;
var breakable1 = $(this).collision("#minion-roulette");
var breakable2 = $(this).collision("#cruiser");
$(this).css("top", maxTop - 25);
if (breakable1.length != 0 || breakable2.length != 0) {
$(this).remove();
}
if (maxTop <= 35) {
$(this).remove();
}
if (breakable1.length != 0) {
--minion_roulette_life;
if (minion_roulette_life == 0) {
sound.play();
breakable1.remove();
minion_roulette(true);
minion_roulette_counter--;
$("#score").html(++score);
minion_roulette_life = 10;
}
}
//This is the place where it checks if counter is 0 or not
if (minion_roulette_counter == 0) {
$('#content').unbind(function() {
minion_roulette(false)
});
alien_cruiser(false);
minion_roulette_counter = -1;
}
if (breakable2.length != 0) {
--cruiser_life;
if (cruiser_life == 0) {
sound.play();
breakable2.remove();
alien_cruiser(true);
$("#score").html(++score);
cruiser_life = 20;
}
}
});
}
Am I doing any wrong here? Please I need a solution badly. Tnx.
In this situation, you could use a conditional statement to determine which function to call.
For example:
if (minion_roulette_counter == 0) {
alien_cruiser();
}
else {
minion_roulette();
}
Binding and unbinding doesn't 'turn off' a function, unfortunately. To quote MDN:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
– MDN: 'Bind'

setInterval() with a count

If possible I'd like to use to remove count and use an argument in self.addOrbitTrap(). At the moment for testing my code does something like this:
Bbrot.prototype.findMSet = function() {
//...code
var self = this;
canvasInterval = setInterval(function() {
self.addOrbitTrap();
}, 0);
}
var count = 0;
Bbrot.prototype.addOrbitTrap = function() {
//...code
if (count === 100) {
// Call a different function. That's why I use count
}
count++;
}
Edit: To be more specific, count is used in my code to count how many times addOrbitTrap() successfully runs (it does not add an orbit trap if a randomly selected pixel is a part of the Mandelbrot Set). After it runs some number of times, I call a different function (from within addOrbitTrap()). I would rather not use a global variable because count is not used anywhere else.
You could introduce count as a local variable inside findMSet that you pass to addOrbitTrap(); at each interval the value will be increased:
Bbrot.prototype.findMSet = function() {
//...code
var self = this,
count = 0;
canvasInterval = setInterval(function() {
self.addOrbitTrap(++count);
}, 0);
}
Handling the value is simple:
Bbrot.prototype.addOrbitTrap = function(count) {
//...code
if (count === 100) {
// Call a different function. That's why I use count
}
}
just make the variable on the object and use it.
Bbrot.prototype.count = 0;
Bbrot.prototype.findMSet = function() {
//...code
var self = this;
canvasInterval = setInterval(function() {
self.addOrbitTrap();
}, 0);
}
Bbrot.prototype.addOrbitTrap = function() {
if(ranSuccessful)
this.count++;
}
Bbrot.prototype.someOtherFunc = function() {
return this.count;
}

Namespacing in Javascript Classes

I'm trying to create a timer in Javascript and I have a specific issue with how I'm implementing it.
Right now it's like this
function CountUpTimer(seconds,name,targetId,submitButtonId){
this.time = seconds;
this.currentTime = 0;
this.minutes = Math.floor(seconds/60);
this.submitButtonId = submitButtonId;
this.seconds = seconds - this.minutes*60;
this.currentSeconds = 0;
this.currentMinutes = 0;
this.targetId = targetId;
this.name = name;
this.isPaused = false;
this.init = function(){
setInterval(this.name + ".tick()",1000);
}
this.pause = function(){
this.isPaused = true;
}
this.unpause = function(){
this.isPaused = false;
}
this.tick = function(){
if(this.isPaused == false){
if(this.currentTime <= this.time){
if(this.currentSeconds == 59){
this.currentSeconds = 0;
this.currentMinutes++;
}
this.updateTimer();
this.currentTime++;
this.currentSeconds++;
} else{
this.endTiming();
}
}
}
Now, the problem with this is that I can't dynamically create CountUpTimer objects, because I need to know the name of the variable that I am assigning to that object. Is there some way I can work around this - so let's say something like
setInterval(this.tick(),1000);
?
When using callback, you lose the context at execution.
You should use bind to keep the context.
setInterval(this.tick.bind(this),1000);
More details here
this.init = function(){
var self = this;
setInterval(self.tick(),1000);
}
Keep the reference to original object, because using this in setInterval will be in the wrong object context (document).
You can do:
var self = this;
setInterval(function() {
self.tick()
}, 1000);
Or use Function.bind if you are fine with non-legacy support.

Categories

Resources