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()
);
Related
I would like to know what are the common approach to make this concept works:
function Abc () {
var beforeMethod = function (e) {
console.log(e);
};
this.before('bob ana', beforeMethod);
}
Abc.prototype.ana = function () { console.log('ana'); }
Abc.prototype.bob = function () { console.log('bob'); }
Abc.prototype.maria = function () { console.log('maria'); }
//
var abc = new Abc();
abc.ana();
It's supposed to call beforeMethod before bob or ana is called.
Quickly :
need to be tested and securised, but i think it do the trick !
I haven't understood what your e mean so i put the called method name in it !
var el = document.getElementById('debug');
var $l = function(val) {
console.log(val);
el.innerHTML = el.innerHTML + '<div>' + val + '</div>';
};
//___________________________________________________________________
var Before = function( methods , func , context){
methods.split(' ').map(function(m){
var ori = context[m];
if(ori){
context[m] = function(){
func.call(context , m);
return ori.apply(context , arguments);
};
}
});
};
var Abc = function () {
var beforeMethod = function (e) {
$l('from beforeMethod : ' + e);
};
Before('bob ana ', beforeMethod , this);
};
Abc.prototype.ana = function () { $l('from ana '); };
Abc.prototype.bob = function () { $l('from bob '); };
Abc.prototype.maria = function () { $l('from maria '); };
var abc = new Abc();
abc.ana();
abc.maria();
abc.bob();
<div id='debug'>Debug
<div>
I think the way to do this is to save the old prototype function in a property.
function Abc() {
this.oldana = this.prototype.ana;
this.oldbob = this.prototype.bob;
this.prototype.ana = function(e) {
console.log(e);
this.oldana();
}
this.prototype.bob = function(e) {
console.log(e);
this.oldbob();
}
}
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);
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);
}
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();
I'm having a problem using the module pattern in a very dummy javascript code.
This code is working perfectly:
;
var test = (function () {
var config = {
replacement: 'a'
};
var init = function () {
$(config.replacement).click(function(){
alert("hello world");
});
}
return {
init: init
}
})();
$(document).ready(test.init());
Instead, this code is not working when I click on any link of my website:
;
var test = (function () {
var config = {
replacement: $('a')
};
var init = function () {
config.replacement.click(function(){
alert("hello");
});
}
return {
init: init
}
})();
$(document).ready(test.init());
Anyone could tell me why I can not use a jQuery object as "default" initialization of config variable.
The $(a) is executed before DOM ready, probably when no a elements are accessible.
In your first example, the set was constructed after DOM ready.
You could turn it into a function instead...
var config = {
replacement: function() { return document.links; }
};
Then, Why in this example located in official jQuery website using a jQuery selector is working for the default config vars?
var feature = (function () {
var $items = $("#myFeature li");
var $container = $("<div class='container'></div>");
var $currentItem = null;
var urlBase = "/foo.php?item=";
var createContainer = function () {
var $i = $(this);
var $c = $container.clone().appendTo($i);
$i.data("container", $c);
},
buildUrl = function () {
return urlBase + $currentItem.attr("id");
},
showItem = function () {
$currentItem = $(this);
getContent(showContent);
},
showItemByIndex = function (idx) {
$.proxy(showItem, $items.get(idx));
},
getContent = function (callback) {
$currentItem.data("container").load(buildUrl(), callback);
},
showContent = function () {
$currentItem.data("container").show();
hideContent();
},
hideContent = function () {
$currentItem.siblings().each(function () {
$(this).data("container").hide();
});
};
$items.each(createContainer).click(showItem);
return {
showItemByIndex: showItemByIndex
};
})();
$(document).ready(function () {
feature.showItemByIndex(0);
});
Official jQuery website