views:

271

answers:

1

I have a composite control which emits HTML that looks like this

<span id="myControl">
   <select id="myControl_select">
      <option value=""></option>
      <option value="1">Item 1</option>
      <option value="2">Item 2</option>
   </select>
</span>

I would like the parent span control to fire an event when the contained drop down list onchange event fires. Since this is a composite control, I have to allow a consumer of this control to be able to assign the event handler (I was hoping via an html attribute called onvaluechanged or something)


Editted to incorporate bobince's suggestion. The only problem is the argument parameter is not being passed. It's currently 'undefined'.

<script>
    window.onload = function() {
        var objSelect = document.getElementById('myControl_select')

        if (objSelect.attachEvent)
            objSelect.attachEvent("onchange", myControl_ddlOnChange);
        else if (objSelect.addEventListener)
            objSelect.addEventListener("onchange", myControl_ddlOnChange, false);
    }   

    function myControl_ddlOnChange()   
    {
        //fire span on value changed event   
        var target= document.getElementById('mycontrol');
        var handler= target.getAttribute('onvaluechanged');

        var args = { text : 'Hi!', index : 0 } 

        if (handler)    
            new Function(handler).call(target, args);
    }

    function myControl_ValueChanged()
    {
        alert(arguments[0]);
    }
</script>

<span id="myControl" onvaluechanged="myControl_ValueChanged();">
   <select id="myControl_select">
      <option value=""></option>
      <option value="1">Item 1</option>
      <option value="2">Item 2</option>
   </select>
</span>
+2  A: 

Don't use attachEvent, it's IE-only. You can hack up solutions that use either attachEvent on IE or addEventListener on other browsers, or use a framework that already does that for you, but for your purposes, plain event handler properties should be enough:

document.getElementById('myControl_select').onchange= myControl_ddlOnChange;

It's not really a good idea to start adding your own custom HTML onsomething attributes. Apart from being invalid, the browser won't do that magic it does to turn an onclick HTML attribute into an onclick JavaScript property. You'd have to do that manually, firing like:

var target= document.getElementById('myControl');
var handler= target.getAttribute('onvaluechanged');
if (handler)
    new Function(handler).call(target);

It's generally better to have the caller write to 'onclick' with a JavaScript function themselves. HTML event handler attributes pretty much suck and should generally be avoided.

ETA re comment:

The reason no arguments are being passed is because your event handler:

onvaluechanged="myControl_ValueChanged();"

doesn't pass on any arguments. You could say:

onvaluechanged="myControl_ValueChanged(arguments[0]);"

or, to pass on any number of arguments:

onvaluechanged="myControl_ValueChanged.apply(this, arguments);"

But really this is getting away from how event handlers normally work, since they don't have arguments(*). Much easier to just stick with JavaScript and say:

var control= document.getElementById('myControl');

// to register
//
control.onvaluechanged= myControl_ddlOnChange;

// to call
//
control.onvaluechanged(/* any arguments; 'this' inside ddlOnChange is the control */);

rather than this curious Function stuff.

Other minor nits: addEventListener takes 'change' rather than 'onchange'; capital C in getElementById('myControl').

(*: except for the ‘event’ argument, in non-IE)

bobince
Your solution works exactly how I wanted it too, except I'm having one further complication. I'm trying to pass eventargs into the event handler. var args = { text : 'Hi!', index=0 } new Function(handler).call( target, args ); //args are not passed valueChanged.call(target, args); //args are passed }
What's the difference, where's ‘valueChanged’ coming from? Any function.call(target, argument) should work, although note that the syntax of your object literal is wrong (it should be ‘index: 0’ rather than ‘=’).
bobince
Could you check my original post? I've updated it to include your suggestions, however the argument parameter isn't being passed to the function.
added...
bobince
Thanks for your help