0

In JavaScript I'm attempting to set an onchange callback that accepts a parameter. However, how I'm currently doing it overrides the event object that is created. I don't actually need the event for my purposes, but I would like to know how I can capture both the event and any passed in parameters in case my needs change.

EDIT: For clarity, this onchange event could be called both programatically and by a user. There may be an instance where I'm creating an empty select element so the user can pick what they want, or creating a populated one based on some other interaction.

EDIT: Also, the below is a simplified example of a much larger code base. Assume that the scoping is not global of any of the variables. I'm really looking for an answer of how to specifically be able to capture both and event object (when called via user interaction) and another object (when called via code). It feels like having the atr parameter mean different things in different contexts is hacky - but I come more from a strongly typed background so it might be just me.

function update(atr) {
    ...
}

document.getElementById("myelement").onchange = update;

var atr = {"id":1,"param":"val1"};

// This gives me atr in the function as defined above
document.getElementById("myelement").onchange(atr);

// This way, however, gives me atr in the function as the event
document.getElementById("myelement").onchange();

What I would really like is something like this:

function update(e, atr) {
    // Now I have e as the event and atr as the value I've passed in
}

document.getElementById("myelement").onchange = update;

var atr = {"id":1,"param":"val1"};

// This gives me atr in the function as defined above
document.getElementById("myelement").onchange(atr);

However the above code doesn't work. I suspect that I have to do something with bind() but as far as I can understand that I would simply be overriding the event's (this) object in the function like I'm doing now implicitly.

The accepted answer in this question Similar Question is basically what I want to do, but that is with React JS and I would like to do this without any frameworks. I've been trying to search for multiple parameters and onchange events and primarily getting React or unrelated responses. Either this is a harder question than I think, or I'm searching for the answer in completely the wrong way.

syntheticgio
  • 588
  • 6
  • 25
  • you don't override anything, there isn't any event since you invoked it manually – pwolaq Feb 17 '18 at 14:46
  • I think this might help https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget – Robert Feb 17 '18 at 14:46
  • `var atr = {"id":1,"param":"val1"}; document.getElementById("myelement").onchange = function() { console.log(atr); }` – mplungjan Feb 17 '18 at 14:47
  • if this is a realistic representation of your actual problem you don't need to pass the object into into the function at all because they're in the same scope. – I wrestled a bear once. Feb 17 '18 at 14:50
  • @Occam'sRazor - this is just a simplified illustration, in reality they are in different scopes. But good catch. – syntheticgio Feb 17 '18 at 14:57
  • @pwolaq this function also needs to be able to be invoked via actual user change. I'll update the question to be more clear. – syntheticgio Feb 17 '18 at 15:03
  • @RobertRocha Thanks. In this instance its a single element being used for multiple related purposes. In the example you posted no variables aside from the event are being passed to hide(), so not quite what I'm looking for. – syntheticgio Feb 17 '18 at 15:27
  • @SyntheticGio - yes i know, my point is that no one can give you a realistic solution unless you give a realistic example of the problem... where is the parameter coming from? – I wrestled a bear once. Feb 17 '18 at 15:43

2 Answers2

3

I will explain what happens in the linked answer as you mentioned that you want to achieve the same behaviour.

So:

<fieldset onChange={(e) => this.props.handleChange("tags", e)}>

This React code attaches anonymous function with one parameter e to the fieldset as onChange listener. This function in its body invokes another function, passing e with additional parameters.

Translating this into your code, you would like to achieve something like this:

function update(e, attr) {
    // e is instance of Event
    // attr is additional parameter
}
document.getElementById("myelement").onchange((e) => update(e, attr));
// or without ES6 arrow function:
document.getElementById("myelement").onchange(function(e){ update(e, attr); });

Also, be advised that proper way of attaching event listeners is by addEventListner API.

pwolaq
  • 6,343
  • 19
  • 45
  • This is exactly what I was looking for, and +1 since it was one of those 'oh duh' moments when I saw your answer :). Thanks also for the link, I'll read into the API you suggested also. My guess is that there is a better structural way to have approached the problem, although it was a little more out of curiosity than anything. – syntheticgio Feb 17 '18 at 20:48
1

I'm not sure I understand exactly what you're trying to do, but first you need to distinguish between the case that the event is triggered by the user and the case that you call the event programatically, when you call it programatically there is no event.

you can do something like this: You mentioned that you use select, the logic is that when a change in the select occurs the event is thrown and you get the selected value, in your case the value can be the content of the atr var:

HTML

<select id="myelement" onchange="update(event)">
    <option value='{"id":1,"param":"val1"}'>val1
    <option value='{"id":2,"param":"val2"}'>val2
</select>

JavaScript

function update(e) {
    var atr = JSON.parse(document.getElementById("myelement").value);
    //now you have access both to the event and the 'parameter'
}

This covers the case when the event is triggered by the user, when you want to trigger the event programatically, since there is no event, use a different function that take the atr parameter.

Yossi S
  • 11
  • 2
  • For anyone else stumbling upon this question, this is also a good answer. I was looking for some built-in way (similar to how self is handled in python) to address this, but looks like that is not how JS works. +1 for the sample code, I think it will be useful to others too. – syntheticgio Feb 17 '18 at 20:52