Tuesday, December 17, 2013

Primefaces: capturing the target list item clicked

First of all, kudos to Hatem Alimam for his answer, who solved this problem.

Here's the problem.

I have a @ViewScoped managed bean with a p:pickList filtered by a p:selectMany component using a p:ajax update event.

Like this

<p:outputLabel for="siteFilter" value="Site Filter:" style="width:100px;"/>
<p:selectOneMenu converter="#{siteTypeConverter}" id="siteFilter" value="#{myMB.selectedSiteType}" style="width:200px;">              
   <f:selectItem itemLabel="Select Site Type" itemValue="#{null}" />
   <f:selectItems value="#{myMB.siteTypeFilterList}" var="st" itemLabel="#{st.name}" itemValue="#{st}" />
   <p:ajax update="sites" listener="#{myMB.handleSiteTypeFilterChange}" oncomplete="rebindClicks()"/>
</p:selectOneMenu>

<p:outputLabel for="sites" value="Sites:" style="width:100px;"/>
<p:pickList
   widgetVar="xyzabc"
   id="sites"
   value="#{myMB.sites}"
   var="site"                 
   converter="#{siteConverter}"
   itemLabel="#{site.siteType.name}.#{site.name}"
   itemValue="#{site}" /> 

The idea here is to trigger a new event when the user clicks on some pickList target list item.

So, as suggested by @Hatem, we have to bind the click event to each one of the target elements. Like this

(...)
   <p:remoteCommand name="updateCommand" action="#{myMB.updateAccounts}" update="accounts"/>
</h:form>
<h:outputScript library="js" name="pickListHack.js" />   
(...)

Notice that I had to add it AFTER the form.

and pickListHack.js is located at WebContent/resources/js/pickListHack.js

function rebindClicks() {
    xyzabc.jq.on('click','.ui-picklist-target li',function(){
        var item = $(this).attr('data-item-value');
        alert(item);
        updateCommand([{name:'param', value:item}]);
   });
};

$(document).ready(function() {
    rebindClicks();
});

The trick here seems to be that, after the update event, the binds are lost, so we have to rebind them after the update. That's  why p:ajax has that oncomplete event.

Finally, when the user clicks on the element from the target list, we call the updateCommand, declared via p:remoteCommand.

Notice that the selected item is passed as a parameter called "param". We get this parameter back in the managed bean like this

public void updateAccounts(){
   String value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("param");
   System.out.println(">"+value);
   this.accounts = value;
}

In this case, the value is just the ID, because that's what my siteConverter does to the object.

@ManagedBean
@RequestScoped
public class SiteConverter implements Converter,Serializable{

    private static final long serialVersionUID = -194442504109002565L;

    @EJB
    private MyEJB myEJB;

    @Override
    public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2)
            throws ConverterException {
        if (arg2 != null){
            Site s = myEJB.getSiteById(Long.parseLong(arg2));
            return s;
        }else{
            return null;
        }
    }

    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2)
            throws ConverterException {
        if (arg2 != null){
            Site s = (Site)arg2;
            return String.valueOf(s.getId());
        }else{
            return null;
        }
    }
}



No comments:

Post a Comment