ilyes kooli
ilyes kooli

Reputation: 12053

How to get JavaScript event source element?

Is there a way to retrieve the element source of an inline JavaScript call?

I have a button like this:

<button onclick="doSomething('param')" id="id_button">action</button>

Note:

What I have tried:

function doSomething(param) {
    var source = event.target || event.srcElement;
    console.log(source);
}

On Firebug I get

event is not defined


Edit

After some answers, an override of the event handling using jQuery is very acceptable. My issue is how to call the original onClick function with its original parameters, and without knowing the function name.

Code:

<button onclick="doSomething('param')" id="id_button1">action1</button>
<button onclick="doAnotherSomething('param1', 'param2')" id="id_button1">action2</button>.
<button onclick="doDifferentThing()" id="id_button3">action3</button>
// and so on..

So the override would be:

$(document).on('click', 'button', function(e) {
  e.preventDefault();
  var action = $(this).attr('onclick');
  /**
   * What to do here to call
   * - doSomething(this, 'param'); if button1 is clicked
   * - doAnotherSomething(this, 'param1', 'param2'); if button2 is clicked
   * - doDifferentThing(this); if button3 is clicked
   * there are many buttons with many functions..
   */
});

Upvotes: 53

Views: 168976

Answers (7)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48693

Here is an updated version of David Taubmann's response that uses a more modern approach.

function doSomething(param) {
  let event = window.event;
  let element = event.target || event.srcElement;
  
  const { id, tagName, textContent } = element;

  console.log(JSON.stringify({
    source: { id, tagName, textContent },
    param
  }, null, 2));
}
<button onclick="doSomething('param')" id="id_button">action</button>

Here is the output:

{
  "source": {
    "id": "id_button",
    "tagName": "BUTTON",
    "textContent": "action"
  },
  "param": "param"
}

Upvotes: 0

srini
srini

Reputation: 884

Try something like this:

<html>
  <body>

    <script type="text/javascript">
        function doSomething(event) {
          var source = event.target || event.srcElement;
          console.log(source);
          alert('test');
          if(window.event) {
            // IE8 and earlier
            // doSomething
           } else if(event.which) {
            // IE9/Firefox/Chrome/Opera/Safari
            // doSomething
           }
        }
     </script>

    <button onclick="doSomething('param')" id="id_button">
      action
    </button>

  </body>      
</html>

Upvotes: 2

slipset
slipset

Reputation: 3078

Your HTML should be like this:

<button onclick="doSomething" id="id_button">action</button>

And renaming your input parameter to event like this:

function doSomething(event){
    const source = event.target || event.srcElement;
    console.log(source);
}

would solve your problem.

As a side note, I'd suggest taking a look at jQuery and unobtrusive JavaScript.

Upvotes: 42

DavidTaubmann
DavidTaubmann

Reputation: 3360

Cross-Browser solution

I believe the solution by @slipset was correct, and it doesn't need jQuery, BUT it wasn't cross-browser ready.

According to Javascript.info, events (when referenced outside markup events) are cross-browser ready once you assure it's defined with this simple line: event = event || window.event.

So the complete cross-browser ready function would look like this:

function logMySource(param){
  event = event || window.event;
  var source = event.target || event.srcElement;
  console.log("sourceID= "+source.id,"\nsourceTagName= "+source.tagName,"\nparam= "+param);
}
<button onclick="logMySource('myVariable')" id="myID">action</button>

Try it! I've included returns of useful information of the source.

Upvotes: 2

adeneo
adeneo

Reputation: 318302

You should change the generated HTML to not use inline javascript, and use addEventListener instead.

If you can not in any way change the HTML, you could get the onclick attributes, the functions and arguments used, and "convert" it to unobtrusive javascript instead by removing the onclick handlers, and using event listeners.

We'd start by getting the values from the attributes

$('button').each(function(i, el) {
    var funcs = [];

	$(el).attr('onclick').split(';').map(function(item) {
    	var fn     = item.split('(').shift(),
        	params = item.match(/\(([^)]+)\)/), 
            args;
            
        if (params && params.length) {
        	args = params[1].split(',');
            if (args && args.length) {
                args = args.map(function(par) {
            		return par.trim().replace(/('")/g,"");
            	});
            }
        }
        funcs.push([fn, args||[]]);
    });
  
    $(el).data('args', funcs); // store in jQuery's $.data
  
    console.log( $(el).data('args') );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="doSomething('param')" id="id_button1">action1</button>
<button onclick="doAnotherSomething('param1', 'param2')" id="id_button1">action2</button>.
<button onclick="doDifferentThing()" id="id_button3">action3</button>

That gives us an array of all and any global methods called by the onclick attribute, and the arguments passed, so we can replicate it.

Then we'd just remove all the inline javascript handlers

$('button').removeAttr('onclick')

and attach our own handlers

$('button').on('click', function() {...}

Inside those handlers we'd get the stored original function calls and their arguments, and call them.
As we know any function called by inline javascript are global, we can call them with window[functionName].apply(this-value, argumentsArray), so

$('button').on('click', function() {
    var element = this;
    $.each(($(this).data('args') || []), function(_,fn) {
        if (fn[0] in window) window[fn[0]].apply(element, fn[1]);
    });
});

And inside that click handler we can add anything we want before or after the original functions are called.

A working example

$('button').each(function(i, el) {
    var funcs = [];

	$(el).attr('onclick').split(';').map(function(item) {
    	var fn     = item.split('(').shift(),
        	params = item.match(/\(([^)]+)\)/), 
            args;
            
        if (params && params.length) {
        	args = params[1].split(',');
            if (args && args.length) {
                args = args.map(function(par) {
            		return par.trim().replace(/('")/g,"");
            	});
            }
        }
        funcs.push([fn, args||[]]);
    });
    $(el).data('args', funcs);
}).removeAttr('onclick').on('click', function() {
	console.log('click handler for : ' + this.id);
  
	var element = this;
	$.each(($(this).data('args') || []), function(_,fn) {
    	if (fn[0] in window) window[fn[0]].apply(element, fn[1]);
    });
  
    console.log('after function call --------');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button onclick="doSomething('param');" id="id_button1">action1</button>
<button onclick="doAnotherSomething('param1', 'param2')" id="id_button2">action2</button>.
<button onclick="doDifferentThing()" id="id_button3">action3</button>

<script>
	function doSomething(arg) { console.log('doSomething', arg) }
    function doAnotherSomething(arg1, arg2) { console.log('doAnotherSomething', arg1, arg2) }
    function doDifferentThing() { console.log('doDifferentThing','no arguments') }
</script>

Upvotes: 14

Sethunath K M
Sethunath K M

Reputation: 4761

You can pass this when you call the function

<button onclick="doSomething('param',this)" id="id_button">action</button>

<script>
    function doSomething(param,me){

    var source = me
    console.log(source);
}
</script>

Upvotes: 4

Pranav
Pranav

Reputation: 8871

USE .live()

 $(selector).live(events, data, handler); 

As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers.

$(document).on(events, selector, data, handler);  

Upvotes: -1

Related Questions