2

I have now been banging my head for a while over a seemingly simple case. I have a Primefaces <p:inputText> (as a cell inside a <p:dataTable>) for which, when the value changes, I would like to get the value in my controller. I cannot reveal the real code, only showing the vital excerpts of it:

<p:column headerText="Ratkaisu">
  <p:inputText name="inpres" id="inpres" value="#{entity.resolution}">
    <p:ajax event="change" immediate="true" execute="@this inpres" render="@this"  listener="#{mainViewController.updateEntity}"/>
    <f:param value="#{entity}" name="entity"/>
  </p:inputText> 
</p:column>

The "backing bean" is my mainViewController that is @ViewScoped The method receiving the ajax data inside the controller:

public void updateEntity(AjaxBehaviorEvent e) {

    // I can get the entity via the parameter list
    Entity entity = (Entity)FacesContext.getCurrentInstance()
        .getExternalContext().getRequestMap().get(entity);

    // The value below is always null
    Object value = ((UIInput)e.getSource()).getValue();
    ....
}

Every time the text changes (enter of focus out of the text field), I get an ajax request to my method. Every time, I find the correct Entity from the request map, so the <f:param>-part seems to work.

So my question (or maybe questions) is, that is it possible for me to get read the newly entered value of the InputText in the controller, via the AjaxBehaviorEvent or do I have to try something else (maybe setting the value of the inputText to the f:param)? Also checked that I did not find any values in the requestMap at the server side either...

I also checked what Chrome inspector is posting via ajax requests. I did not find any evidence that the text that I enter in the <p:inputText> would be sent to the server.

Could anyone enlight or give me some pointers on this issue?

EDIT:

As @melloware pointed out, I made the client side example as minimal as possible, still fully running:

<!DOCTYPE html>
<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:p="http://primefaces.org/ui">

<f:view>
    <h:head>
    </h:head>

    <h:body>
        <h:form id="someid">
        </h:form>

        <p:inputText id="inpresx">
            <p:ajax event="change" process="@this"
                listener="#{mainViewController.doStuff}" />
        </p:inputText>

    </h:body>
</f:view>
</html>

for the MainViewController, the doStuff part:

public void doStuff(AjaxBehaviorEvent e) {
    Object val = ((UIInput)e.getSource()).getValue();
    // val is still null!
}

Even if the program now is very minimal, the value for the inputtext does not seem to be sent over to the server side. A strange thing IMO, is that i need those h:form-tags in order for the example to fire ajax requests.

Here is what the xhr POST request params look like when i feed TestingTesting to the inputtext and press enter (using Chrome Inspector):

javax.faces.partial.ajax: true
javax.faces.source: inpresx
javax.faces.partial.execute: inpresx
javax.faces.behavior.event: change
javax.faces.partial.event: change
someid: someid
javax.faces.ViewState: -4351418361364308383:4652862949343904732

From the above data being sent, there seems like no text data from the inputtext is communicated over to the server side. What may I have done wrong?

EDIT 2:

tldr; The actual solution to the problem for me was to wrap my table inside a form. The ajax tag won't work if there is no form tag that WRAPS it at some level.

Johan Ånäs
  • 145
  • 8
  • I updated my answer below with a fully working sample woirking for me on PF 6.2 – Melloware Jul 06 '18 at 16:36
  • Also it looks like you didn't wrap your someId around the – Melloware Jul 06 '18 at 16:42
  • Well, looks it does not matter if I wrap the form around or not. Besides, in the more complicated example, I cannot add any extra forms around my tables – Johan Ånäs Jul 06 '18 at 17:02
  • Possible duplicate of [How to send form input values and invoke a method in JSF bean](https://stackoverflow.com/questions/3681123/how-to-send-form-input-values-and-invoke-a-method-in-jsf-bean) – Kukeltje Jul 06 '18 at 18:39
  • This is (probably) not a duplicate. Actually, I try to avoid the use of a form as far as I can, but it seems like it must be included in a way or another, in order for ajax to become enabled (I may be wrong here). In the real life app, my inputs live inside a table (as cells) and the page must not be refreshed in any circumstances. And also, I do not(?) want to map directly to a backing bean because of this purpose. I just find it very strange that the changed value is not communicated over to the server side... – Johan Ånäs Jul 09 '18 at 09:39
  • That's an html thing... and why are forms bad? And it IS a duplicate... – Kukeltje Jul 09 '18 at 15:22
  • I beg to disagree a little. To be able to use XMLHttpRequest (ajax), you SHOULD not be forced to use forms (as JSF seems to require). Of course, I'm may be a bit biased when I have been using the Vaadin framework in the past. The form is bad in my example, as I demonstrated that they are needed in order for the ajax calls to even be fired from the client side. What I actually did NOT know, was that you needed to wrap your data inside them :). The real accepted answer would maybe be something like "Please, always wrap your ajax tags within forms, otherwise JSF won't work as expected" – Johan Ånäs Jul 10 '18 at 06:21

1 Answers1

1

Here is my fully working example. Whatever I type in the inputtext like "hello" comes out the in System.out.println.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.org/ui"
      xmlns:h="http://java.sun.com/jsf/html">

    <h:head>   
        <title>PrimeFaces Test</title>
    </h:head>
    <h:body>

        <h:form id="frmTest">

        <p:inputText id="inpresx" value="#{testView.testString}" >
            <p:ajax event="change" process="@this" listener="#{testView.doStuff}" />
        </p:inputText>

        </h:form>

    </h:body>
</html>

Java:

package org.primefaces.test;

import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.component.UIInput;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name = "testView")
@ViewScoped
public class TestView implements Serializable {

    private String testString;

    public void doStuff(AjaxBehaviorEvent e) {
        Object val = ((UIInput)e.getSource()).getValue();
        System.out.println("Value = " + val);
    }

    public String getTestString() {
        return testString;
    }

    public void setTestString(String testString) {
        this.testString = testString;
    }
}

And my Chrome Output:

javax.faces.partial.ajax: true
javax.faces.source: frmTest:inpresx
javax.faces.partial.execute: frmTest:inpresx
javax.faces.behavior.event: change
javax.faces.partial.event: change
frmTest: frmTest
frmTest:inpresx: stackoverflow
javax.faces.ViewState: 9209410033241115450:-5298602114910206430
Melloware
  • 10,435
  • 2
  • 32
  • 62
  • I believe `@this` is the default, so it's not required at all. – Evan Knowles Jul 06 '18 at 06:52
  • Actually, at the beginning, the ajax only contained _event_ and _listener_. Several of the attributes in my question are relics from trial and errors. I have tried so many different solutions now that I have begun to think that the problem may be elsewhere. My code is inside a p:tab inside a p:tabView inside a p:dialog. I haven't written the code originally, just adding this feature. Could the problem be, that there are Html-DIVs wrapping some stuff along? Would that break the JSF tree somehow? My ajax calls DO reach the server, but the the value of the source at the server side yields null – Johan Ånäs Jul 06 '18 at 09:48
  • About the option 3., My entity is detached and I want to persist the data when the data changes for the input (not by pressing a "save" button). I'm still puzzled over how hard it is to just read the value of an input for an ajax event. As I said in the original post, using Chrome Inspector, I could not find evidence that the data was sent to the server side upon the ajax request. – Johan Ånäs Jul 06 '18 at 11:08
  • 2
    OK if your entity is detached I see why you want the listener to save the data. To me it tells me the JSF bind stage is somehow failing validation and not actually sending the value. Maybe try and create a simple page with a much smaller example taking the rest of that page out of the equation. I like to keep narrowing things down until I have the smallest reproducible sample. That might help you figure it out. – Melloware Jul 06 '18 at 11:27
  • Yes, a [mcve] should always be made for debugging. For ypurself and for us – Kukeltje Jul 06 '18 at 18:40