3

I am having trouble adding a p:remoteCommand to a form. It looks something like:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:util="http://java.sun.com/jsf/composite/components/util"
    xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions"
    xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Reset Test</title>
        <link type="text/css" rel="stylesheet" href="/treetable-sscce/css/example.css" />
        <h:outputScript library="primefaces" name="jquery/jquery.js"/>
    </h:head>

    <div class="box">
        <h2>Box</h2>
        <h:panelGroup id="mypanel">
            Headline: <h:outputText value="#{resetBean.headline}" />
            <br/>
            Message : <h:outputText value="#{resetBean.message}" />
            <br/>
        </h:panelGroup>
    </div>

    <div class="box">
        <h2>Form</h2>
        <h:form id="myform" acceptcharset="utf-8">

            <p:growl id="growl" showDetail="true" sticky="false" severity="info, warn" />       

            <!--  register custom validate event -->
            <f:event listener="#{resetBean.validateForm}" type="postValidate" />

            <p:remoteCommand name="resetByEscape" action="#{resetBean.resetAction}" 
                immediate="true" update=":myform :mypanel" />

            <h:outputLabel for="headline">Meldungsüberschrift</h:outputLabel>
            <h:inputText id="headline" value="#{resetBean.headline}" />
            <br/>

            <h:outputLabel for="message">Meldungsüberschrift</h:outputLabel>
            <h:inputTextarea id="message" value="#{resetBean.message}" />
            <br/>

            <h:commandButton action="#{resetBean.resetAction}"  
                        value="Reset" immediate="true" onclick="resetForm()"/>

            <h:commandButton action="#{resetBean.submitAction}" value="Submit"  immediate="false"/>

        </h:form>
    </div>

    <script type="text/javascript">
        <!--//--><![CDATA[//><!--

        var resetForm = function()
        {
            $("[id$='headline']").val(null)
            $("[id$='message']").val(null)
        }

        var escapePressed = function()
        {
            resetForm();
            resetByEscape();
        } 

        $(document).keyup(function(e) {if (e.keyCode == 27) escapePressed();});

        //--><!]]>
    </script>
</html>

Here is the bean code:

package de.example.beans;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.validator.ValidatorException;

import org.apache.log4j.Logger;

@ViewScoped
@ManagedBean
public class ResetBean implements Serializable 
{
    private static final long serialVersionUID = 7282752623428425109L;
    private static final Logger log = Logger.getLogger(ResetBean.class);

    protected String headline = null;
    protected String message = null;

    public ResetBean() {
        log.error("ResetBean");
    }

    @PostConstruct
    public void postConstruct() {
        log.error("postConstruct");
    }

    @PreDestroy
    public void preDestroy() {
        log.error("preDestroy");
    }

    public void resetAction() {
        log.error("resetAction");
        headline = null;
        message = null;
    }

    public void submitAction() {
        log.error("submitAction headline="+headline+" message="+message);
    }

    public void validateForm(ComponentSystemEvent event) throws ValidatorException {
        log.error("validateForm");
    }

    public String getHeadline() {
        return headline;
    }

    public void setHeadline(String headline) {
        this.headline = headline;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

Both the h:command button and the p:remoteCommand execute the same action in the same fashion. The difference is, that the h:command button responds to a mouse click, while the ESC key triggers the p:remoteCommand via javascript on using ESC key.

The problem is, that the route via p:remoteCommand seems to destroy the backing bean somehow (the bean is @ViewScoped). The @PreDestroy annotated method is never called, however: the next action on the page after using the p:remoteCommand forces the component to be created from scratch! Default constructor and @PostConstruct are called. Naturally some important parameters are missing now and the whole view gets shot to hell.

Any idea what is happening? Why the difference between p:remoteCommmand and h:commandButton in this instance? Any chance of working around the problem?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Jürgen Simon
  • 876
  • 1
  • 12
  • 35
  • Can you post your bean code? – Aritz Jan 31 '14 at 17:37
  • Sorry, I was out of the office for a while. I'm afraid I can not post the full code because it's simply too big. I'll post an excerpt that contains the action methods involved. – Jürgen Simon Feb 05 '14 at 12:34
  • Try to reproduce the error in smaller context. If you can do it it'll be fine. Posting an excerpt will probably make so difficult to get a clear answer. – Aritz Feb 05 '14 at 12:38
  • I have reproduced the problem in a demo project. I am editing the problem description accordingly in a minute. – Jürgen Simon Feb 05 '14 at 13:51
  • That's the cool way of doing things ;-) – Aritz Feb 05 '14 at 14:05
  • Can you provide more info about the issue? JSF impl version, browser you're using... I've tried it with Chrome and works as expected, although firefox is bringing unexpected behaviour. However, unrelated to your problem, you don't need to clear your form using JS. Just clear their model values at java code and you'll get inputs cleared when coming back from the post. – Aritz Feb 05 '14 at 14:25
  • Primefaces: 3.5, JSF(mojarra) 2.2.3, Chrome (32.0.1700.77) and Firefox (26.0) on Ubuntu. The problem is consistent on those two browsers. – Jürgen Simon Feb 05 '14 at 14:34
  • I get the feeling something goes wrong in the restore view stage. Could it be related to having javax.faces.PARTIAL_STATE_SAVING set to true? – Jürgen Simon Feb 06 '14 at 13:58
  • The problem is view state parameter (the one used by JSF implementations for keeping the view stateful) is removed when clicking on ESC. Just have a look at the generated form at client side. I would bet it actually is a problem related with `p:remoteCommand`, since the problem seems to be related with all the keys and not only ESC. Maybe you should open a thread in PF forum... – Aritz Feb 06 '14 at 14:36
  • Hm ... so this is a PF bug? – Jürgen Simon Feb 07 '14 at 09:37
  • 1
    Not sure at all, it could be Mojarra related. You should notify it at PrimeFaces forum to Cagatay's team. They will help you with the issue. – Aritz Feb 07 '14 at 09:46
  • 1
    Thank you. I'll post the answer here once I have it. – Jürgen Simon Feb 07 '14 at 11:37
  • Does it happen, if you remove f:event? – Danubian Sailor Feb 10 '14 at 11:11

1 Answers1

1

I could reproduce the problem. In my case and maybe the same case here (question provides only 'sample' code, not real one) it was caused by nested forms template->page.

If you have a ui:composition template or something similar to that, at the end of the generated HTML on client side it may creates nested forms like this:

<h:form>
...
  <h:form>
   ...
  </h:form>
...
</h:form>

which is invalid HTML code.

Remove unnecessary forms or reorganize code and test again. It should not call @postConstruct method when p:remoteCommand is called through JavaScript