Primefaces p:picklist - how I capture the event of selecting an item in the target list?

7k views Asked by At

I'd like to re-render a component when a item from the picklist target list is selected by the user.

How do I do that?


UPDATE (December 17th, 2013)

I've described the full solution for this problem here - http://leonotepad.blogspot.com.br/2013/12/primefaces-capturing-target-list-item.html

Thanks @Hatem I could not solve this without your answer.

Basically, it was this:

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;
        }
    }
}
1

There are 1 answers

10
Hatem Alimam On BEST ANSWER

This way should do it.

remoteCommand

<p:remoteCommand name="updateCommand" update="componentId" />  

p:pickList

<p:pickList id="pickList" widgetVar="pickListVar" value="#{pickListBean.cities}" 
 var="city" itemLabel="#{city}" itemValue="#{city}" />

JS

$(document).ready(function() {
   PF('pickListVar').jq.on('click','.ui-picklist-target li',function(){
       updateCommand();//remoteCommand to update
       //and you can get the item value and lable
       $(this).attr('data-item-value');
       $(this).attr('data-item-lable');
   });
});

EDIT:

And if your pickList is updated regularly by another component, you would lose the click event after all.

In this case you might want to bind the click on the parent container component of the pickList.

For example:

 $('#formId').on('click','.ui-picklist-target li',function(){
       updateCommand();//remoteCommand to update
       //and you can get the item value and lable
       $(this).attr('data-item-value');
       $(this).attr('data-item-lable');
   });

But again if any other component has updated the whole form, you would lose the event binding..