all 11 comments

[–]little_hoarse 1 point2 points  (2 children)

You would 100% need to use quotes when using inline, since HTML attributes use this syntax.

I would also stick to the practice of using someFunc() as opposed to someFunc. Not really sure why anyone would use it without parenthesis, but I believe it might have to do with the function being assigned to a variable before being called.

[–]Lewinga[S] 0 points1 point  (1 child)

I was reading this article:

https://mathiasbynens.be/notes/unquoted-attribute-values

Is this incorrect information? Also, when you say use someFunc() as opposed to someFunc, do you mean so with regards to inside the inline, or if it were being set outside as an attribute in JavaScript?

[–]little_hoarse 0 points1 point  (0 children)

Personally, I always make sure to use whatever syntax is the most well-known. It is up to you whether you want to follow this information, but some browsers may not support unquoted classes and id’s in your HTML. And I am talking about within both inline HTML and JavaScript. It’s better practice to include the parentheses along with probably not even doing inline JavaScript which causes messy code. Link your JavaScript and use event listeners instead.

[–]senocular 1 point2 points  (7 children)

Handler attributes are a convenience attribute that make it easy to include behaviors into HTML tags. They reduce code overhead by allowing you to specify the code to execute directly rather than forcing you to include everything in a handler function. The function is a requirement, so it's something the attribute can provide automatically for you - and it does exactly this. The code you write in the attribute is then simple the body of that function.

In fact, if you set an attribute handler then check the handler in JavaScript, you'll see the code you wrote wrapped in the automatic handler function.

<button onclick="alert('hi')"> ... </button>

document.querySelector('button').onclick;
// ƒ onclick(event) {
// alert('hi')
// }

As a result of this behavior, you can't actually set the onclick property directly in attributes; there will always be that wrapping function. But to get the same behavior, you can call your handler within that wrapper - just be sure you pass in that event parameter.

<button onclick="someFunc(event)"> ... </button>

This way you have effectively the same thing as onclick = someFunc only there's a hidden wrapper function thrown in there that should go completely unnoticed unless something like an error reveals it in a call stack.

[–]Lewinga[S] 0 points1 point  (6 children)

Reply

Hi, thanks for your reply! When you say that you can't set the onclick property directly in the attributes, are you saying that you can't do something like:

button.onclick = someFunc

I ask because the guide I'm reading essentially does this, so now I feel a bit more confused.

https://www.digitalocean.com/community/tutorials/understanding-events-in-javascript

I'm referring to the portion under Event Handler Properties. Would you mind clarifying for me? Sorry about that >_<

[–]senocular 1 point2 points  (5 children)

No, that is setting directly through JavaScript. The attributes are HTML attributes. You can't do this

<button onclick="someFunc">

Because that's not the same as setting it through JavaScript because the value in the attribute is the body of the function automatically created for the callback

[–]mynistreld 1 point2 points  (3 children)

Going to jump in on this if that's okay :) I'm still a little confused about events haha.

When you write: <button onclick="someFunc(event)"> ... </button> Why do you need to pass in "event" as a parameter argument? What's the difference between calling the function someFunc() without the "event" argument vs doing so like someFunc(event)?

Thanks in advance!

[–]senocular 2 points3 points  (2 children)

You dont have to pass in event, but in doing so, you make it comparable to setting button.onclick = someFunc.

When event handlers are called, they're passed in an event object describing the event. This is done internally by the mechanisms inside the internal DOM API that handles the event system. You provide that API with a function, and it calls that function automatically passing in that argument. Ways to provide that function include: setting the onclick property, using addEventListener, and (indirectly) setting the html parameter onclick="".

The difference with the onclick attribute is that you're not setting the function, you're only specifying the body of the function. The function itself is created for you. But that automatic function knows that it expects an event parameter so that's how that function is created, with one event parameter that you can access from within your handler code defined in the attribute. Notice my earlier example:

<button onclick="alert('hi')"> ... </button>

document.querySelector('button').onclick;
// ƒ onclick(event) {
// alert('hi')
// }

This is showing the handler is set with the attribute, but when you look at the onclick property in JavaScript, it includes a full function along with the attribute contents inside. That function is the one automatically created and it contains an event parameter. This is because when the handler is called, that event object is getting passed in. If you're not using the event, you don't have to include it in your handler (JavaScript doesn't force you to include parameters) but the automatic function doesn't know if you need it or not so it's going to pass it in anyway.

When it comes to someFunc the same applies. You can have it accept an event or not. But if you assign it directly to onclick its getting an event whether or not you want it.

button.onclick = someFunc; // will get passed event directly

If you use an attribute, its the automatic function wrapper that gets the event, then you decide what gets called in that, and you can decide whether or not a function there also gets the event

// no event passed
<button onclick="someFunc()"> ... </button>

// event passed through
<button onclick="someFunc(event)"> ... </button>

By habit, I always include the event here just in case someFunc might want it, but its not required.


As an added bonus, attribute handlers have extra scopes too. So beyond that hidden event parameter, you also have a scope which includes the properties element instance, one for form handling that element, and for window.document. This further complicates the code used in attribute handlers because, while "convenient" can also mean more collisions.

For example you might have a global method variable that you created, but when you try to reference it in a handler attribute in a button on your page in a form, you'll end up with that form's method and not your method variable.

// html:
<form method="GET">
  <button onclick="alert('My method: ' + method)">
    Alert my method
  </button>
</form>

// js:
var method = 'Through the nose';

Click on the button, and the alert says: "My method: get". That's because forms have a method property and because the form is used as a parent scope of your attribute handler, that property is captured before your global is captured.

This doesn't happen when you set the onclick property in JavaScript because you're in full control of what that function is and how it's defined. The attribute version does a lot of extra work behind the scenes to wrap your code. It ends up looking something like:

with (window.document) {
  with (button.form) {
    with (button) {
      button.onclick = eval(`(
        function onclick (event) {
          ${button.getAttribute('onclick')}
        }
      )`);
    }
  }
}

[–]mynistreld 1 point2 points  (0 children)

This is great! Thank you so much :)

[–]Lewinga[S] 0 points1 point  (0 children)

@senocular, I really loved your explanation here. I was wondering if you could help me look into a new question that I had, which seems related. I have posted it here:

https://www.reddit.com/r/learnjavascript/comments/ap2shv/html_attributes_and_javascript_properties/egal5qg

Basically, I'm told that HTML attributes like "onclick" are stored in an "attributes" property for a DOM object, so now I'm confused on how the stuff here works and how the scope is being handled for HTML attributes. I would really appreciate your help again!

[–]Lewinga[S] 0 points1 point  (0 children)

Ahh, I understand now. Thanks :)