a-h / templ

A language for writing HTML user interfaces in Go.
https://templ.guide/
MIT License
8.04k stars 264 forks source link

Proposal: Introduce JsGenericVar for Event and Element Access in element event handlers #850

Closed cornejong closed 1 month ago

cornejong commented 2 months ago

While using temple i came acros the following issue:

When defining a script that will be added to the onclick attribute of an element, there is currently no way to access the event or the target element in the handler. This would have me end up doing additional querySelectors to access the target element and, maybe most important, all event metadata is completely lost in this way.

Solution

Introduce a JsGenericVar string type. This type can be used to set the signature of the function and be replaced by the string value as a JS variable during generation.

// JsGenericVar refers to a generic JS variable name.
// The string value of JsGenericVar will be used as the variable argument in the function call
type JsGenericVar string

This would enable access to any global JS variable in a Templ script block.

// JsGenericVar defines a generic JS variable to be replace with the string value within the Javascript function call on generation
type JsGenericVar string

script OnTheClick(event templ.JsGenericVar, element templ.JsGenericVar) {
    console.log(event, element)
}
templ TheButton() {
    <button onclick={ OnTheClick( templ.JsGenericVar("event"), templ.JsGenericVar("this") ) }>TheButton</button>
}

Since there is no type-checking in the script blocks (because it's JavaScript), this string type should work seamlessly.

Generated HTML/JS Code

The generated HTML/JS code would look something like this:

<script type="text/javascript">
    function __templ_OnTheClick_985f(event, element) {
        console.log(event, element)
    }
</script>
<button onclick="__templ_OnTheClick_985f(event, this)">TheButton</button>

Predefined Constants

Define some constants for the most common use cases: events and target element reference.

const (
    JsEvent         JsGenericVar = "event"
    JsTargetElement JsGenericVar = "this"
)

This adds more explicit declarations, enhancing readability since the inferred JS variable is also stated in the script signature.

script OnTheClick(event templ.JsEvent, element templ.JsTargetElement) {
    console.log(event, element);
}

templ TheButton() {
    <button onclick={ OnTheClick(templ.JsEvent, templ.JsTargetElement) }>TheButton</button>;
}

Feedback and insights on this would be appreciated!

iambpn commented 2 months ago

Same, I also had the same issue. It would be great to access the event and this JS objects on script function.

I am not familiar with the implementation of how script function in templ is transpiled into JS, but it seems like one generic type like templ.JsGenericVar or templ.unsafeJSVar would be enough to cover this issue.

Once cavity with this is, templ would not be able to sanitize this templ.JsGenericVar parameter, but it's on user.

cornejong commented 2 months ago

@iambpn, what do you mean by sanitization?

cornejong commented 2 months ago

Initial implementation in PR #851

iambpn commented 2 months ago

By sanitization, I mean escaping unwanted characters like double quote ". I hope you get it.

This is also mentioned here in the docs. link

cornejong commented 2 months ago

Aah okay. Yeah this applies to values exported from GO to JavaScript. But since the event variable only exists in the JavaScript runtime this does not have much effect I think.

a-h commented 1 month ago

Fixed in #851 - thanks contributing!