Event Handling

Listening for events

You can attach event handlers to DOM elements:

doc.body {
    val label = h1()
    label.text("Click Me")
    label.on.click {
        label.text("Clicked!")
    }
}

Most if not all JavaScript event types are supported, and you can read event data like which key was pressed:

doc.body {
    val input = input(type = InputType.text)
    input.on.keypress { keypressEvent ->
        logger.info("Key Pressed: ${keypressEvent.key}")
    }
}

Immediate events

Since the code to respond to events runs on the server, there may be a short but sometimes noticeable delay before the page updates in response to an event.

Fortunately, Kweb has a solution:

doc.body {
    val input = button(type = ButtonType.button)
    val label = span().text("Not clicked")
    input.onImmediate.click {
        label.text("Clicked!")
    }
}

Kweb executes this event handler on page render and records the changes it makes to the DOM. It then "pre-loads" these instructions to the browser such that they are executed immediately without a server round trip.

Warning: Due to this pre-loading mechanism, the event handler for an onImmediate must limit itself to simple DOM modifications. Kweb includes some runtime safeguards against this but they can't catch everything so please use with caution.

Using events and immediate events together

A common pattern is to use both types of event handler on a DOM element. The immediate handler might disable a clicked button, or temporarily display some form of spinner. The normal handler would then do what it needs on the server, and then perhaps re-enable the button and remove the spinner.

Querying the DOM when an event is triggered

Sometimes you need to know the state of the DOM when an event is triggered. You could query it from within the event handler but this would add a server round trip which is inefficient.

Alternatively you can use retrieveJs. This will execute the JavaScript expression you provide when the event fires and return the result in the retrieved property of the event:

inputButton.on(retrieveJs = "(new Date()).getTime()").click { event ->
    label.text("Clicked at ${event.retrieved.jsonPrimitive.content}")
}

For ValueElements such as InputElement there is a convenience property valueJsExpression that you can use to retrieve the current value of the element:

val textInput = input(type = InputType.text)
val inputButton = button(type = ButtonType.button)
val label = span().text("Not clicked")
inputButton.on(retrieveJs = textInput.valueJsExpression).click { event ->
    label.text("Read textInput: ${event.retrieved.jsonPrimitive.content}")
}

Preventing the default event action

You can also prevent the default action of an event from occurring by setting the preventDefault parameter to true - this is the equivalent of JavaScript's Event.preventDefault() function.

val inputButton = button(type = ButtonType.button)
inputButton.on(preventDefault = true).click {
    logger.debug("Clicked!")
}