How to unbind Primefaces Hotkey

Goal

You need to be able to activate one keyboard key to perform an action in your Webp age, depending on what is currently being rendered on your page, using Primefaces hotkey component

Description

When rendering one hotkey with Primefaces, conditionally, depending on a given page section, anytime that section is re-rendered, the hotkey is processed once again, resulting in 2 (or more, depending on the number of times one goes to that section and leave from it) events anytime we click that key later.

The situation I faced here was with a page that had several view panels that, when clicked, would present themselves (actually, a different panel in edit mode for the same data) into edit mode, making it possible to leave the editing mode either by clicking in the cancel button or by pressing the esc key. This means that the esc key should cancel the edit mode for all panels in that page, but only one panel is controlled by that key at one time.

However, because the rendering of the key was conditional and the processing of Primefaces does not clean previous key bindings, and we never left the full page, the ‘esc’ key was being added and added to that document, leading us to the situation where several equal events were being triggered on any ‘esc’ key press, instead of only one (the last one, as wanted).

How to

Basically, the solution I took for my problem was to make sure that after a given Ajax request is started (something like a cleanup before presenting the next page), any key is unbound from the document, making it possible for the hotkey component to register once and only once (because none were already associated to the current document, to tell the truth) the key to handle a given behaviour. The following snipped shows the most relevant parts of my XHTML template:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:p="http://primefaces.org/ui">
   ...
<h:body>
   ...
   <h:outputScript name="js/application.js" />
   ...
</h:body>

where the javascript file would contain the following relevant lines:

$(document).ajaxStart(function() {
  $(document).off('keydown');
});

then, in the target page, we only need to add our hotkey component as usual (Note: if you have a component that uses the property global set to false, the unbind won’t work as there will be no Ajax start, which means that our “cleanup” function will not be triggered):

<p:hotkey bind="esc" action="#{bean.cancel}" immediate="true"
  process="@this" update="@form" />

Explanations

The call to $(document).off('keydown') after each ajax call is complete makes sure the page is “clean” by the time the hotkey component is processed, making sure that that hotkey will be the only one “active” at any given time (assuming, of course, that only one editing panel is shown at one time).

2 comments

    1. You’re welcome. I’m glad it helped and also that you were able to “improve” my suggestion (they seem to be equivalent in terms of result but I guess it’s prettier to attach the unbind call to the ajaxStatus component) 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s