Passing Params to a New Window with JSF

Here's what I wanted to accomplish:

A user performs a search. The user sees a list of results. The user clicks on a "details" link for a single record in the list of results. The action of clicking on the details link launches a popup window that displays the details of the record selected.

Here's how I thought it should work:

The page with the list of results and the details popup page would share the same backing bean. Each "details" link (commandLink, commandButton, outputLink...doesn't matter) in the list of results would use f:setPropertyActionListener to set the "selectedRecordId" on the backing bean. An onclick event on the details link would launch a popup window. The popup window would get the "selectedRecordId" from the shared backing bean along with other data relating to the selected record.

Sounds pretty straight forward, right? Wrong. The problem is that any javascript events are executed before the form is submitted. So in the situation described above, the popup launches first and THEN the setProperty ActionListener sets selectedRecordId on the backing bean. When the popup window loads, it can't retrieve selectedRecordId because it hasn't been set yet.

A Solution!

Here's a high level overview of how it works. The javascript on the details link passes the recordId on the URL. When the details popup page accesses the "selectedRecordId" on the backing bean, the getter for this field calls a method which retrieves the value of "recordId" that was passed on the URL. This value can then be set to "selectedRecordId" on the backing bean. Both the page with the dataTable results and the details popup page now have access to "selectedRecordId".

The Code!

I used icefaces in the example code below.

The dataTable with details popup link:

<ice:dataTable id="searchResults" value="#{basicSearch.records}" var="item">
    <ice:column>
        <f:facet name="header">
            <ice:commandSortHeader
                    columnName="#{basicSearch.labelColumnName}"
                    arrow="true">
                <ice:outputText value="#{basicSearch.labelColumnName}"/>
            </ice:commandSortHeader>
        </f:facet>
        <ice:outputText value="#{item.label}"/>
    </ice:column>

    <ice:column>
        <f:facet name="header">
            <ice:outputText value="Details"/>
        </f:facet>

        <ice:commandButton image="/resources/images/icon_small_info.gif"
                           onclick="doPopup('#{request.contextPath}/recordDetails/details.jspx?recordId=#{item.recordId}'); ">
        </ice:commandButton>
    </ice:column>
</ice:dataTable>

The important stuff from the backing bean:

    private String selectedRecordId;

    public String getSelectedRecordId() {
        selectedRecordId = (String) getParamValue("#{param.recordId}");
        return selectedRecordId;
    }

    public void setSelectedRecordId(String selectedRecordId) {
        this.selectedRecordId = selectedRecordId;
    }

    public Object getParamValue(String s) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Object value = facesContext.getApplication().createValueBinding(s).getValue(facesContext);
        return value;
    }

The javascript:

function doPopup(source) {
    popup = window.open(source, "popup", "height=600,width=900)");
    popup.focus();
}

Accessing the recordId from the popup window:

<ice:outputText  value="#{metadataView.selectedRecordId}"/>

Concurrent DOM Access so both windows can access the same backing bean: (web.xml)

    <context-param>
        <param-name>com.icesoft.faces.concurrentDOMViews</param-name>
        <param-value>true</param-value>
    </context-param>

Tags:

Comments

  1. David:

    Hi,one question, what about if you dont have a commandbutton in the column, just an outputText. Will you be able to show that popup window, using onclick (javascript) for instance???thanks

  2. Waheeb:

    How do I get this value in the processAction method of Faces Servlet.

New Comment