I need to write functions on the fly while avoiding the use of global variables. They'll be 'connected' to event listener.
I currently have a function to create a connection. They receive:
The object I want to connect
Two variables: IDX and id I have to identify some element that I want to use.
This is my code so far:
create_fun = function (obj, IDX,id) {
var f = function () {document.getElementById(IDX+"_"+id).display = "block";}
obj.addEventListener('click', f,false);
}
This code runs OK. I see in the Chrome Event Listeners Panel the click event connected to the objected that I wanted.
The Problem: IDX and id are variables, and as they are not globals, they are undefined.
At chrome Eventlistener inspection I see:
handler = function ()
{document.getElementById(IDX+"_"+id).display = "block";}
But, being IDX = "sec1" and id="3", I'd like to see :
handler = function ()
{document.getElementById("sec1+"_"+"3").display = "block";}
Is this possible? How would I do this?
The fix is given by Function constructor
var f = new Function ( "document.getElementById('"+IDX+"_"+id+"').style.display = 'block';" );
obj.addEventListener('click', f,false);
}
Related
I was going through the source of waypoints.js and came across the following function ::
NoFrameworkAdapter = function(event, handler) {
var eventParts = event.split('.')
var eventType = eventParts[0]
var namespace = eventParts[1] || '__default'
var nsHandlers = this.handlers[namespace] = this.handlers[namespace] || {}
var nsTypeList = nsHandlers[eventType] = nsHandlers[eventType] || []
nsTypeList.push(handler)
this.element.addEventListener(eventType, handler)
}
To understand this function, I wanted to console.log events so I wrote the below code:
var elem = document.getElementById('a');
handler = function(){console.log('test')};
elem.addEventListener(event , handler); // error is throw here .
Since I am passing event instead of event type to the add event listener, an error is thrown, but all I really want to do is to print the event to the console, so I can see the contents of it.
How can I do that? I know that I am missing something but I cannot find it.
The function concerned can be seen HERE ,
var fbToggle = document.getElementById("fbToggle");
and later in the script
fbToggle.addEventListener("click", toggle("fbContainer"));
Console tells me that fbToggle is NULL
This is in the document though.
<input type="checkbox" id="fbToggle">
I wasnt using eventListener before, so maybe there is a special order of declaration i'm missing ?
EDIT :
entire js :
function toggle(target) {
var obj = document.getElementById(target);
display = obj.style.display;
if (display == "none") {display = "block"}
else {display = "none"}
}
function init() {
var fbToggle = document.getElementById("fbToggle");
var twitToggle = document.getElementById("twitToggle");
var pinToggle = document.getElementById("pinToggle");
console.log(fbToggle); // NULL
fbToggle.addEventListener("click", toggle("fbContainer"));
twitToggle.addEventListener("click", toggle("twitContainer"));
pinToggle.addEventListener("click", toggle("pinContainer"));
}
window.onload = init();
HTML is way too long.but JS is in head, called from external file. Also i'm not in quirk mode.
It is not clear where "later in the script" is. If it is in different scope definitely it is not going to work. Suggesting you to keep everything in a global object if possible so that you can access from different places in the script.
window.globals = {};
window.globals.fbToggle = document.getElementById("fbToggle");
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
http://jsfiddle.net/ST938/
Another point is addEventListener expects a function or function idenitifier, NOT a function call.
addEventListener("click", toggle("fbContainer")); // wrong
addEventListener("click", toggle); // correct
So if you want to pass a parameter
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
In JavaScript, putting brackets after a function name causes it to be called. If you want to reference a function without calling it you must not put brackets after the name:
window.onload = init(); // this calls init() immediately
window.onload = init; // this correctly stores init in window.onload
The same applies to toggle(). If you need to pre-specify some of the arguments you can wrap it in an anonymous function:
fbToggle.addEventListener("click", function() { toggle("fbContainer"); });
or you can use bind:
fbToggle.addEventListener("click", toggle.bind(null, "fbContainer"));
I would like to assign document elements to global variables so that I am able to use these elements everywhere in my code.
My code:
// document elements
var drop = null;
var status = null;
var show = null;
function process (drop, status, show) {
if (document.readyState == 'complete') {
// init elements
drop = document.getElementById(drop);
status = document.getElementById(status);
show = document.getElementById(show);
}
// init event handlers
drop.addEventListener('drop', handleDrop, false);
}
function handleDrop (evt) {
// do something
}
The problem is I can't do anything with the document elements using the global variables in the function handleDrop while in the function process everything works as it should...
EDIT: For example, I can read the content of the element show (show.innerHTML) in the function process but not in the function handleDrop.
The problem is that all these drop, status... variables within process function are the local ones - they refer to its arguments, and not the variables defined earlier.
If these were defined at the outer-most level (i.e., not within any function's body), you can access (and alter) them like this:
window.drop = document.getElementById(drop);
window.status = document.getElementById(status);
window.show = document.getElementById(show);
But I'd actually suggest another way: using separate names for params and 'closured-over' variables. Like this:
function process(dropId, statusId, showId) {
if (document.readyState == 'complete') {
// init elements
drop = document.getElementById(dropId);
status = document.getElementById(statusId);
show = document.getElementById(showId);
}
}
Both ways allow you to address these variables within handleDrop function; the latter one is obviously superior, because you are not restricted with what scope to choose.
How can I pass parameters to a function declared like something = function(){};
window.prototype.initInterface = function(){
this.mainPane = document.createElement('div');
this.mainPane.style.border="5px solid grey";
this.mainPane.style.margin="0px";
this.mainPane.style.width="420px";
this.mainPane.style.height="600px";
this.exitButton = document.createElement('input');
this.exitButton.setAttribute("type", "button");
this.exitButton.setAttribute("value", "exit");
this.exitButton.onclick = function(){
document.body.removeChild(this.mainPane);
};
this.mainPane.appendChild(this.exitButton);
document.body.appendChild(this.mainPane);
}
When the user presses the exit button I want to remove the mainPane from the body of the html page.
this.exitButton.onclick = function(this.mainPage){
document.body.removeChild(this.mainPane);
};
Does not work
How can I do this?
For your exitButton.onclick function to have access to variables you create in the enveloping initInterface function you want a to create a closure in the exitButton.onclick function by returning a function that performs the action you want and passing that the variable.
exitButton.onclick = function () {
return (function() {
document.body.removeChild(mainPane);
})(mainPane);
};
Read more on how closures work here and here and see a working example fiddle.
Alternatively, you forget about closures and walk up the DOM from the button which triggers the event to your mainPane
exitButton.onclick = function() {
// in here "this" is the object that triggered the event, exitButton
document.body.removeChild(this.parentNode);
}
As an aside, window.prototype does not exist if you are doing this in a browser; window is the object at the top of prototype chain in browser scripting. You want just window.initInterface = function () {} which is the exact same thing as function initInterface() {} because everything you do in javascript in the browser becomes a property of window.
This function is the function w/o function name. It could only be used once and you may not easy to find out what parameters should be passed.
You can create another function like :
function go(a1){}
And call it like window.prototype.initInterface = go(a1);
Or you can get some DOM parameters in this unnamed function by using functions like getDocumentById("DOM ID") etc.
Javascript is pretty shaky for me, and I can't seem to find the answer to this. I have some code along the lines of
var Scheduler = function(divid,startDate,mode){
this.setHeader = function(){
header.innerHTML = 'Show';
}
this.showScheduler = function period(){
...
}
};
My problem is, how do I put the onclick into the HTML so that it properly calls the showScheduler function for the appropriate instance of the current scheduler object that I'm working with?
I wouldn't do whatever it is you're doing the way you're doing it, but with the code the way you have it, I would do this (lots ofdo and doing :) ):
var Scheduler = function(divid, startDate, mode){
var that = this;
this.setHeader = function(){
header.innerHTML = 'Show';
header.firstChild.onclick = function() { that.showScheduler(1); };
}
this.showScheduler = function period(){
...
}
};
You should use a framework for this type of thing. If you don't use one then you gotta declare each instance of schedular as a global object, and you will need the name of the instance in order to call it from the link. Look at the following link
http://developer.yahoo.com/yui/examples/event/eventsimple.html
They only show a function being applied, but you can also do something like this
YAHOO.util.Event.addListener(myAnchorDom, "click", this.showScheduler,this,true);
Where myAnchorDom is the achor tag dom object. This will have showScheduler function execute within the scope of your scheduler object.
Instead of working with innerHTML use the DOM methods.
Try replacing this:
header.innerHTML = 'Show';
with this:
var x = this; // create a closure reference
var anchor = document.createElement('a');
anchor.href= '#';
anchor.innerHTML = 'Show';
anchor.onclick = function() { x.showScheduler(1); }; //don't use onclick in real life, use some real event binding from a library
header.appendChild(anchor);
Explanation:
The "this" in the original code refers to the element which fired the event, i.e. the anchor ("this' is notoriously problematic for things like, well, like this). The solution is to create a closure on the correct method (which is why you have to create something like the var x above) which then only leaves the problem of passing in the parameter which is accomplished by wrapping the method in another function.
Strictly speaking it would be much preferable to bind eventhandlers with the addEventListener/attachEvent pair (because direct event assignment precludes the ability to assign multiple handlers to one event) but it's best handled using a library like jquery if you're new to JS anyway.
You can add an event handler to the header object directly:
var me = this;
this.setHeader = function(){
header.innerHTML = 'Show';
header.addHandler("click", function(e) { me.showScheduler(1); });
}
Insite the passed function, this will refer to the header element.
var Scheduler = function(divid, startDate, mode)
{
var xthis = this;
this.setHeader = function()
{
var lnk = document.createElement("a");
lnk.addEventListener("click", xthis.showScheduler, false);
lnk.innerText = "Show";
lnk.setAttribute('href', "#");
header.appendChild(lnk);
}
this.showScheduler = function period(){
...
}
};
When using "this" inside the onclick attribute, you're actually referring to the anchor tag object. Try this and see if it works:
this.setHeader = function(){
header.innerHTML = 'Show';
}