3
votes

JSF-2.0, Mojarra 2.1.19, PrimeFaces 3.4.1

Summary of the problem: Have a p:inputText inside p:dataTable and inputText action fired by p:remoteCommand which passes the dataTable row index as a parameter with f:setPropertyActionListener. But it always passes the last row of the dataTable, not the index of the row which includes currently clicked p:inputText.


As it can be seen from my previous questions, I am trying to use p:inputText as a comment taker for a status like in Facebook or etc. Implementation includes a p:dataTable. It's rows represents each status. Seems like:

<p:dataTable id="dataTable" value="#{statusBean.statusList}" var="status"
                     rowIndexVar="indexStatusList">
    <p:column>
        <p:panel id="statusRepeatPanel">
            <p:remoteCommand name="test" action="#{statusBean.insertComment}"
                update="statusRepeatPanel">
                <f:setPropertyActionListener 
                    target="#{statusBean.indexStatusList}"
                    value="#{indexStatusList}">
                </f:setPropertyActionListener>
            </p:remoteCommand>
            <p:inputText id="commentInput" value="#{statusBean.newComment}"
                onkeypress="if (event.keyCode == 13) { test(); return false; }">
            </p:inputText>
        </p:panel>
    </p:column>
</p:dataTable>

Upper code says when the press enter key, fire p:remoteCommand which calls the insert method of the managed bean.

@ManagedBean
@ViewScoped
public class StatusBean {
    List<Status> statusList = new ArrayList<Status>();
    public int indexStatusList;
    public String newComment
    //getters and setters
    public void insertComment() {
        long statusID = findStatusID(statusList.get(indexStatusList));
        statusDao.insert(this.newComment,statusID)
    }

Let's debug together; assuming there are three statuses shown in the p:dataTable, click in the p:inputText which in the second status(index of 1), type "relax" and press the enter key.

In the debug console, it correctly shows "relax", but it finds the wrong status because indexStatusList has the value of 2 which belongs the last status in the p:statusList. It must be 1 which is the index of p:inputText that clicked on the dataTable row.

I think problem is about p:remoteCommand which takes the last index on the screen.


How it works?

Let's imagine there is a p:commandLink instead of p:remoteCommand and p:inputText:

<p:commandLink action=#{statusBean.insertComment>
      <f:setPropertyActionListener target="#{statusBean.indexStatusList}"
          value="#{indexStatusList}"></f:setPropertyActionListener>

This component successfully passes the indexStatusList as currently clicked one.

1

1 Answers

1
votes

Conceptual problem in this solution lies in way how p:remoteCommand works. It creates JavaScript function whose name is defined in name attribute of p:remoteCommand. As you putted this in dataTable it will iterate and create JavaScript function called test as many times as there is rows in this table, and at the end last one will be only one. So, solution can be in appending index at the name of the remoteCommand but that is bad, because you will have many unnecessary JavaScript functions. Better approach would be to create one function an pass argument to it. So define remoteCommand outside of datatable:

<p:remoteCommand name="test" action="#{statusBean.insertComment}" update="statusRepeatPanel">

and call test function like this in your onkeypress event:

test([{ name: 'rowNumber', value: #{indexStatusList} }])

This will pass rowNumber parameter in your AJAX request. In backing bean's insertComment() method you can read this parameter and do with it anything you want:

FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
Integer rowNumber = Integer.parseInt(map.get("rowNumber").toString());

NOTE: as you are updating panel in each row, maybe you can change update attribute of remoteCommand to @parent so this will work for all rows.

EDIT: You can update the specific panel in specific row with following code in Java method:

RequestContext.getCurrentinstance().update("form:dataTable:" + rowNumber + ":statusRepeatPanel")