Skip to content

Commit

Permalink
docs: demonstrate adding event handlers without on-* attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
a-h committed Jun 2, 2024
1 parent aaa0049 commit 108500b
Showing 1 changed file with 88 additions and 1 deletion.
89 changes: 88 additions & 1 deletion docs/docs/03-syntax-and-usage/12-script-templates.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Using JavaScript with templ

## Scripts
## Script tags

Use standard `<script>` tags, and standard HTML attributes to run JavaScript on the client.

Expand All @@ -15,6 +15,93 @@ templ body() {
}
```

To pass data from the server to client-side scripts, see [Passing server-side data to scripts](#passing-server-side-data-to-scripts).

## Adding client side behaviours to components

To ensure that a `<script>` tag within a templ component is only rendered once per HTTP response, use a [templ.OnceHandle](18-render-once.md).

Using a `templ.OnceHandle` allows a component to define global client-side scripts that it needs to run without including the scripts multiple times in the response.

The example below also demonstrates applying behaviour that's defined in a multiline script to its sibling element.

```templ title="component.templ"
package main
import "net/http"
var helloHandle = templ.NewOnceHandle()
templ hello(label, name string) {
// This script is only rendered once per HTTP request.
@helloHandle.Once() {
<script type="text/javascript">
function hello(name) {
alert('Hello, ' + name + '!');
}
</script>
}
<div>
<input type="button" value={ label } data-name={ name }/>
<script type="text/javascript">
// To prevent the variables from leaking into the global scope,
// this script is wrapped in an IIFE (Immediately Invoked Function Expression).
(() => {
let scriptElement = document.currentScript;
let parent = scriptElement.closest('div');
let nearestButtonWithName = parent.querySelector('input[data-name]');
nearestButtonWithName.addEventListener('click', function() {
let name = nearestButtonWithName.getAttribute('data-name');
hello(name);
})
})()
</script>
</div>
}
templ page() {
@hello("Hello User", "user")
@hello("Hello World", "world")
}
func main() {
http.Handle("/", templ.Handler(page()))
http.ListenAndServe("127.0.0.1:8080", nil)
}
```

:::tip
You might find libraries like [surreal](https://github.com/gnat/surreal) useful for reducing boilerplate.

```templ
var helloHandle = templ.NewOnceHandle()
var surrealHandle = templ.NewOnceHandle()
templ hello(label, name string) {
@helloHandle.Once() {
<script type="text/javascript">
function hello(name) {
alert('Hello, ' + name + '!');
}
</script>
}
@surrealHandle.Once() {
<script src="https://cdn.jsdelivr.net/gh/gnat/surreal@3b4572dd0938ce975225ee598a1e7381cb64ffd8/surreal.js"></script>
}
<div>
<input type="button" value={ label } data-name={ name }/>
<script type="text/javascript">
// me("-") returns the previous sibling element.
me("-").addEventListener('click', function() {
let name = this.getAttribute('data-name');
hello(name);
})
</script>
</div>
}
```
:::

## Importing scripts

Use standard `<script>` tags to load JavaScript from a URL.
Expand Down

0 comments on commit 108500b

Please sign in to comment.