Multiple DefaultCommand in a form using different scopes in PrimeFaces

Multiple DefaultCommand in a form using different scopes in PrimeFaces

DefaultCommand in PrimeFaces is for specifying which clickable command in a form to trigger when ENTER key is pressed on an input in the form. It is especially useful when there are multiple commands in the form. Suppose that we have two Dialog in a form, and each has some inputs and a command button. Then two DefaultCommand can be defined so that when ENTER key is pressed on the inputs of either Dialog, the corresponding command button is triggered. If no DefaultCommand were defined, the first button with the type submit would always be triggered in most browsers.

The key to implement multiple DefaultCommand is to set different scopes for each of them. For example,

  1. <h:form>
  2.   <p:dialog id="entityAdd" header="Add" modal="true" resizable="false">
  3.     <p:panelGrid columns="2">
  4.       <h:outputText value="Name: *" />
  5.       <h:inputText value="#{entity.name}" size="30" />
  6.     </p:panelGrid>
  7.     <p:commandButton value="Save" action="#{bean.add}" id="btnAdd" />
  8.   </p:dialog>
  9.   <p:dialog id="entityEdit" header="Edit" modal="true" resizable="false">
  10.     <p:panelGrid columns="2">
  11.       <h:outputText value="Name: *" />
  12.       <h:inputText value="#{entity.name}" size="30" />
  13.     </p:panelGrid>
  14.     <p:commandButton value="Save" action="#{bean.edit}" id="btnEdit" />
  15.   </p:dialog>
  16.   <p:defaultCommand target="btnAdd" scope="entityAdd" />
  17.   <p:defaultCommand target="btnEdit" scope="entityEdit" />
  18. </h:form>

The scopes are the ids of the enclosing components of the inputs. Pay attention not to include clickable commands like buttons in the scope, because the default behavior of ENTER key press on these commands are being overridden. However, there is one more gotcha related to the choices of enclosing components when ajax is used, which can be revealed from the DefaultCommand source code:

  1. PrimeFaces.widget.DefaultCommand = PrimeFaces.widget.BaseWidget.extend({
  2.     init: function(cfg) {
  3.         this.cfg = cfg;
  4.         this.id = this.cfg.id;
  5.         this.jqId = PrimeFaces.escapeClientId(this.id);
  6.         this.jqTarget = $(PrimeFaces.escapeClientId(this.cfg.target));
  7.         this.scope = this.cfg.scope
  8.                 ? $(PrimeFaces.escapeClientId(this.cfg.scope)) : null;
  9.         var $this = this;
  10.         this.jqTarget.closest('form').off('keydown.' + this.id)
  11.                 .on('keydown.' + this.id, function(e) {
  12.            var keyCode = $.ui.keyCode;
  13.            if(e.which == keyCode.ENTER || e.which == keyCode.NUMPAD_ENTER) {
  14.                 if(($this.scope && $this.scope.find(e.target).length == 0)
  15.                         ||$(e.target).is('textarea')) {
  16.                     return true;
  17.                 }
  18.                $this.jqTarget.click();
  19.                e.preventDefault();
  20.            }
  21.         });
  22.         $(this.jqId + '_s').remove();
  23.     }
  24. });

Line 7-8 initializes the this.scope variable to a JQuerized DOM element, and there is no update to the variable thereafter. If ajax changes the DOM of the page later, the variable may refer to an invalid DOM element, and nothing will happen if ENTER key is pressed.

We just need to make sure that the enclosing component is valid and is not changed over time by ajax updates across the whole lifecycle of the page. For example,

  1. <h:form>
  2.   <p:commandButton value="Add"
  3.       update=":form:entityAddPanel" oncomplete="entityAdd.show()"/>
  4.   <p:dialog widgetVar="entityAdd" modal="true" resizable="false">
  5.     <h:panelGroup id="entityAddScope" layout="block">
  6.       <p:panelGrid columns="2" id="entityAddPanel">
  7.         <h:outputText value="Name: *" />
  8.         <h:inputText value="#{entity.name}" size="30" />
  9.       </p:panelGrid>
  10.     </h:panelGroup>
  11.     <p:commandButton value="Save" action="#{bean.add}" id="btnAdd" />
  12.     <p:commandButton value="Cancel" onclick="entityAdd.hide();" type="button" />
  13.   </p:dialog>
  14.   <p:defaultCommand target="btnAdd" scope="entityAddScope" />
  15. </h:form>

The <h:panelGroup/> is added intentionally to be used as the scope which isolates the buttons and encloses the <p:panelGrid/>, which in turn is being updated by ajax every time the "Add" button is clicked.

Comments

This worked..!!!!:) Thnak by Anonymous (not verified)

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

More information about formatting options

To prevent automated spam submissions leave this field empty.