views:

136

answers:

6

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 = '<a href="#" onclick="this.showScheduler(1);">Show</a>';

    }

   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?

A: 

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 = '<a href="#" onclick="Scheduler.showScheduler(1);">Show</a>';
}
Joe D
This won't work unless you use Scheduler as a static object.
Zoidberg
True. Perhaps a poor assumption on my part.
Joe D
A: 

You can add an event handler to the header object directly:

var me = this;

this.setHeader = function(){
          header.innerHTML = '<a href="#" onclick="this.showScheduler(1);">Show</a>';

header.addHandler("click", function(e) { me.showScheduler(1); });
    }

Insite the passed function, this will refer to the header element.

eulerfx
Is the addListener function from a framework?
Zoidberg
Its a mistake on my part. I am not sure on the exact name, but its a function available without framework, however the call is different for IE and FF.
eulerfx
+1  A: 

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.

Zoidberg
You don't need a framework to set `myAnchorElement.onclick = ...`.
Crescent Fresh
No, but setting onclick directly is a bad idea and always has been. Which is why everyone who knows what they're doing uses the add/attach pair.
annakata
You don't need one... but why make life difficult on yourself handling cross browser issues.
Zoidberg
This may actually be the most useful for me because I am using YUI elsewhere in the script. I'm going to play with this first and see if I can't get it working. Thank you.
Amy
@Amy: You should tag your questions with any frameworks you are using. That way answers don't have to be as widely varying as the ones you've gotten so far.
Crescent Fresh
@crescentfresh Thank you for the tip.
Amy
@annakata - The example she gave was quite trivial and it appears no other events were being added. That was the assumption I went with when I gave my answer (see below), but for more complex widgets or dynamic HTML/AJAX stuff, attaching and detaching events is the way to go.
nickyt
@nickyt - sure, me too, but of course it's always advisable to fix the problem asked *and* show a better way
annakata
+4  A: 

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 = '<a href="#">Show</a>';
          header.firstChild.onclick = function() { that.showScheduler(1); };
    }

   this.showScheduler = function period(){

        ...
   }
};
nickyt
I'm surprised by the lack of clarity around ol' school event handlers and DOM elements in the answers so far. Yours is the first to get it.
Crescent Fresh
@crescentfresh - I like to kick it old school ;)
nickyt
Only thing is incase the html ever gets changed I'd maybe use `header.getElementsByTagName('a')[0].onclick = ...`. This also gets around the ambiguity of how whitespace nodes are treated in different browsers, if ever one day the html gets a ` ` (space) preceding it.
Crescent Fresh
This won't work in Firefox. Only IE
Zoidberg
To all, you can obviously use cross-browser frameworks for attaching the events, but in the spirit of Old School (I drink Diet Pepsi) I thought it was more appropriate, especially since Amy didn't specify she was using a client-side framework.
nickyt
True, but you don't have to include a whole framework to use peices of it. YUI is once such, you include two javascript files and voila, you got a whole robust cross environment solution to event handling.
Zoidberg
@Zoidberg - you can do a check for either click or onclick. Or just go with a client-side framework.
nickyt
@Zoidberg: it works in Firefox just fine. Actually it works in every browser made since 1998.
Crescent Fresh
@nickyt: "check for click"?
Crescent Fresh
@crescentfresh - my bad I was thinking of something else. Please disregard... since 1998 like you said. I think I'm going to go fire up a copy of NCSA Mosaic.
nickyt
I find it hard to believe it works in both firefox and IE. Firefox requires you put a string in there such as 'that.showScheduler(1);' while IE requires the function declaration as you have shown it. I have had this exact problem and I know for certain that it does not work in IE 6, and I am pretty sure it does not in IE 7
Zoidberg
@Zoidberg - If you set the onclick attribute yes, but not the onclick property. They are two different things.header.firstChild.onclick = function() { that.showScheduler(1); };is not the same thing asheader.firstChild.setAttribute("onclick", "function() { that.showScheduler(1); };");
nickyt
@Zoidberg: You're thinking of `setAttribute` and event handlers (which you are right, would fail in all IEs). See http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html. However the `onclick` attribute takes a `function` object as it's value and works in all browsers. See
Crescent Fresh
Okay... NOT withstanding that, how can setting a global variable of your object be a good idea? The framework approach, offered by both JQuery and YUI offer a cleaner, safter, less globalized approach.
Zoidberg
@Zoidberg: `that` is not a global variable. nickyt simply used a closure to capture the instance of `Scheduler`. It's a well known JavaScript idiom.
Crescent Fresh
@Zoidberg: The answer *starts* with "I wouldn't do whatever it is you're doing the way you're doing, but...". In *this case*, setting the handler directly is fine. Since the element is getting constructed and the handler added in the same function, it seems it's not likely to have other event handlers added (although it's impossible to know for certain without seeing the rest of the code).
Daniel Pryden
@Daniel: reminds me of that simpsons episode: "don't do what Donny Don't does". Wait, what?
Crescent Fresh
@crescentfresh Okay, I see that and it makes sense. Its only limitation is the ability to add more listeners to that click. Again, a neat trick I forgot about.
Zoidberg
+1  A: 

Instead of working with innerHTML use the DOM methods.

Try replacing this:

header.innerHTML = '<a href="#" onclick="this.showScheduler(1);">Show</a>';

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.

annakata
Why "use some real event binding from a library"?
Crescent Fresh
Because for a newbie events are one of the hardest things to wrap your head around. I would strongly advise using something which just works rather than spending time getting it right and/or reinventing wheels.
annakata
@annakata: very good point. It also avoids this: http://stackoverflow.com/questions/95731/why-does-an-onclick-property-set-with-setattribute-fail-to-work-in-ie
Crescent Fresh
Well quite, but setAttribute is toxic anyway :)
annakata
A: 
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(){

        ...
   }
};
andres descalzo
`lnk.addEventListener` won't work in IE, and `lnk.innerText=` will *only* work in IE.
Crescent Fresh
ok, is right. would be better as it does @annakata
andres descalzo