How do I call a Javascript function outside of another Javascript function? - javascript

I have a javascript function that's supposed to toggle an animation when clicked by calling another function outside of it.
function MyFunction(id) {
var target = document.getElementById(id);
var on = true;
this.startMe = function() {
//animation code
on = true;
}
this.stopMe = function() {
//animation code
on = false;
}
this.toggleMe = function() {
if (on) this.stopMe();
else this.startMe();
}
target.addEventListener('click', function() {
this.toggleMe();
}, false);
}
The problem lies in the toggleMe and addEventListener functions. "this" refers to the function itself and not the one containing it, which is what I need it to reference. How can I work around this?

The easy fix is to use a closure variable as given below
function MyFunction(id) {
var self = this;
var target = document.getElementById(id);
var on = true;
this.startMe = function () {
//animation code
on = true;
}
this.stopMe = function () {
/animation code
on = false;
}
this.toggleMe = function() {
if (on) this.stopMe();
else this.startMe();
}
target.addEventListener('click', function() {
//this refers to the element here not the instance of MyFunction
//use a closure variable
self.toggleMe();
}, false);
}
Another solution is to pass a custom execution context to the callback using $.proxy() - you can use Function.bind() also but not supported in IE < 9
function MyFunction(id) {
var target = document.getElementById(id);
var on = true;
this.startMe = function () {
//animation code
on = true;
}
this.stopMe = function () {
//animation code
on = false;
}
this.toggleMe = function () {
if (on) this.stopMe();
else this.startMe();
}
//use Function.bind() to pass a custom execution context to
target.addEventListener('click', jQuery.proxy(function () {
// this refers to the element here not the instance of MyFunction
//use a closure variable
this.toggleMe();
}, this), false);
}
Also use .click()/on('click') to register the click handler instead of addEventListener
$(target).on('click', jQuery.proxy(function () {
// this refers to the element here not the instance of MyFunction
//use a closure variable
this.toggleMe();
}, this), false);

Simply add another variable with a reference to this but with a different name; then you can use that in your functions.
function MyFunction(id) {
var self = this;
var target = document.getElementById(id);
var on = true;
this.startMe = function() {
on = true;
}
this.stopMe = function() {
on = false;
}
this.toggleMe = function() {
if (on) self.stopMe();
else self.startMe();
}
target.addEventListener('click', function() {
self.toggleMe();
}, false);
}
My personal preference is to take it even one step further and continue to use self everywhere that makes sense:
function MyFunction(id) {
var self = this;
var target = document.getElementById(id);
var on = true;
self.startMe = function() {
on = true;
}
self.stopMe = function() {
on = false;
}
self.toggleMe = function() {
if (on) self.stopMe();
else self.startMe();
}
target.addEventListener('click', function() {
self.toggleMe();
}, false);
}

Related

Javascript, Calling functions from another onclick in object constructor

I need help calling the this.load function from inside the thediv.onclick. I stripped out most of the code so its really basic, but I really can't find a way to do it. Here is what I currently have:
function CreatePizza(Name, Toppings) {
this.n = Name;
this.t = Toppings;
this.load = function loadpizza() {
//function that i want to be called
}
this.create = function button() {
var thediv = document.createElement("div");
thediv.onclick = function() {
// Call this.load function here
}
}
}
The problem is that inside the onclick handler, this will refer to the <div>, not the other this which you refer to repeatedly.
Two possible solutions:
Save a reference to your desired this:
that = this;
thediv.onclick = function () {
that.load()
};
Bind this to your function:
thediv.onclick = function () {
this.load();
}.bind(this);
Or, if that's the only thing you're doing in that function anyway:
thediv.onclick = this.load.bind(this);
Because of closures, you can simply assign this to a variable and call it from that!
function CreatePizza(Name, Toppings) {
var self = this;
this.n = Name;
this.t = Toppings;
this.load = function loadpizza() {
//function that i want to be called
}
this.create = function button() {
var thediv = document.createElement("div");
thediv.onclick = function() {
self.load();
}
}
}
I would like to mention that a nicer - and not necessarily better, before anyone starts a flamewar - way to attach events to your div (and more elegant in my opinion) is to use thediv.addEventListener('click', self.load, false). Just a side-note, though.
Backup the this object before binding the event.
this.create = function button() {
var that = this,
thediv = document.createElement("div");
thediv.onclick = function() {
// Call this.load function here
that.load();
}
}
function CreatePizza(Name, Toppings) {
this.n = Name;
this.t = Toppings;
var foo = function loadpizza() {
//function that i want to be called
};
this.load = foo;
this.create = function button() {
var thediv = document.createElement("div");
thediv.onclick = function() {
foo();
}
}
}
function CreatePizza(Name, Toppings) {
this.n = Name;
this.t = Toppings;
this.load = function loadpizza() {
//function that i want to be called
}
var self = this;
this.create = function button() {
var thediv = document.createElement("div");
thediv.onclick = function() {
self.load()
}
}
}

Is it possible to unit-test this javascript structure?

Given the following JavaScript structure:
addClickEvent: function() {
element.addEventListener('click', function() {
self.a();
self.b();
});
},
Is it possible to assert that a() and b() have been called without refactoring out the anonymous function or editing it's contents?
Assuming the self in your code is the window.self property.
You could do something like this:
function element_onclick_callsAandB() {
// Arrange
var aCalled = false;
var bCalled = false;
var element = ...;
var origA = self.a;
var origB = self.b;
self.a = function() {
aCalled = true;
origA();
};
self.b = function() {
bCalled = true;
origB();
};
try {
// Act
element.click();
// Assert
assertTrue(aCalled);
assertTrue(bCalled);
}
finally {
self.a = origA;
self.b = origB;
}
}

JavaScript's setTimeout doesn't work

I have a simple JS object which emulates traffic lights:
function TrafficLight(redTime, yellowTime, greenTime) {
var self = this;
this.__timer = null;
this.__state = null;
this.__redTime = redTime;
this.__yellowTime = yellowTime;
this.__greenTime = greenTime;
var setnewtimer = function (delay, func) {
console.log('SET!');
if (self.__timer) {
clearTimeout(this.__timer);
}
self.__timer = setTimeout(delay, func);
};
TrafficLight.prototype.toRed = function () {
this.__state = 'red';
setnewtimer(this.__redTime, function () {
console.log('RED!');
self.toGreen();
});
};
TrafficLight.prototype.toGreen = function () {
this.__state = 'green';
setnewtimer(this.__greenTime, function () {
console.log('GREEN');
self.toYellow();
});
};
TrafficLight.prototype.toYellow = function () {
this.__state = 'yellow';
setnewtimer(this.__yellowTime, function () {
console.log('YELLOW');
self.toRed();
});
};
TrafficLight.prototype.state = function () {
return this.__state;
};
this.toGreen();
}
But when I make a TrafficLight object (like var a = new TrafficLight(1000, 1000, 1000);), every a.state() call returns green (so traffic light doesn't change its state by timer. What's wrong with my code?
You don't call setTimeout correctly.
Change
setTimeout(delay, func);
to
setTimeout(func, delay);

Accessing a function within a function from outside in javascript

I have a nested function that I want to call from outside.
var _Config = "";
var tourvar;
function runtour() {
if (_Config.length != 0) {
tourvar = $(function () {
var config = _Config,
autoplay = false,
showtime,
step = 0,
total_steps = config.length;
showControls();
$('#activatetour').live('click', startTour);
function startTour() {
}
function showTooltip() {
}
});
}
}
function proceed() {
tourvar.showTooltip();
}
$(document).ready(function () {
runtour();
});
I was hoping to call it by tourvar.showTooltip(); but I seem to be wrong :) How can I make showTooltip() available from outside the function?
since my previous answer was really a hot headed one, I decided to delete it and provide you with another one:
var _Config = "";
var tourvar;
// Module pattern
(function() {
// private variables
var _config, autoplay, showtime, step, total_steps;
var startTour = function() { };
var showTooltip = function() { };
// Tour object constructor
function Tour(config) {
_config = config;
autoplay = false;
step = 0;
total_steps = _config.length;
// Provide the user with the object methods
this.startTour = startTour;
this.showTooltip = showTooltip;
}
// now you create your tour
if (_Config.length != 0) {
tourvar = new Tour(_Config);
}
})();
function proceed() {
tourvar.showTooltip();
}
$(document).ready(function () {
runtour();
});
function outerFunction() {
window.mynestedfunction = function() {
}
}
mynestedfunction();

Change an image and change it back with JavaScript click events

I have the following code:
window.onload = function () {
'use strict';
var alcohol = document.getElementById('alcohol');
var changeImage = function (event) {
alcohol.src = "image/alcohol3.jpg";
};
var changeBack = function (event) {
alcohol.src = "image/alcohol.jpg";
};
addHandler(alcohol, "click", changeImage);
// addHandler(alcohol, "mouseout", changeBack);
How can I change the image back with a second click event? At the moment, it's not working.
Change your changeImage function to:
var changeImage = function (event) {
if (alcohol.src != "image/alcohol3.jpg"){
alcohol.src = "image/alcohol3.jpg";
}
else
{
alcohol.src = "image/alcohol.jpg";
}
};
You could use a closure like that to do so :
var changeImage = function() {
function a(event) {
alcohol.src = "image/alcohol3.jpg";
event.srcElement.onclick = b;
}
function b(event) {
alcohol.src = "image/alcohol.jpg";
event.srcElement.onclick = a;
}
return a;
}
addHandleaddHandler(alcohol, "click", changeImage());
First it is the a function that is assigned as the handler and each the event is raised the handler is toggled between a and b.
You can use toggle:
$("#alcohol").toggle(
changeImage() ,
changeBack()
);

Categories

Resources