How to identify clicked commandButton in my managed bean - jsf

I have an actionListener method in my managed bean which is called by many command buttons.
public void verifyTestDisponibility(ActionEvent actionEvent) {
if (button1 clicked) {
// ...
}
if (button2 clicked) {
// ...
}
}
The part I'm stucking at is identifying the clicked command button. How can I identify it?

You can use it like this
In xhtml page we can use a <h:commandButton> tag with actionListener
<h:commandButton id="btn1" action="#{yourBean.method}" value="ButtonValue"
actionListener="#{yourBean.commandClicked}"></h:commandButton>
In your managed bean
private String buttonId;
/* getters and setters for buttonId goes here */
public void commandClicked(ActionEvent event) {
/* retrieve buttonId which you clicked */
buttonId = event.getComponent().getId();
/*check for which button you clicked*/
if(buttonId.equals("btn1")){
}else{
}
}

You can use the event.getComponent().getClientId();
if (event.getComponent().getClientId().equals("firstButton")).....

This works with ajax listener too. I had used with Primefaces 5 ajax listener. For example:
public void myListener(AjaxBehaviorEvent ev) {
String clientId = ev.getComponent().getClientId();
...
}

Related

How to make a dynamically generated URL redirect to another tab?

I'm using PrimeFaces 6.2
Hi everyone. As mentionned in the title, I need to open a new tab when a user clicks on a link (which is dynamically generated). I tried 2 solutions for now, and none of them works entirely :
1st solution : attributes url and target in PrimeFaces component
Facelet :
<p:contextMenu id="menuMesure" for="treeVArboParents" nodeType="3">
<p:menuitem value="OPL" url="#{arboParObjView.sessionService.lienUrl()}" target="_blank"/>
</p:contextMenu>
View :
#Named(value="arboParObjView")
#ViewScoped
public class ArboParObjView implements Serializable
{
#Inject
SessionService sessionService;
private TreeNode selectedNode //changes everytime a node is selected - both right and left clicks work
...some code here...
public void genererLienBirt() //called everytime the selectedNode value is changed
{
String libelle="";
if (selectedNode != null)
{
//code to find the id of the associated to the selected node.
//I need the id because I want to pass it as a parameter of the link
//And this part of code works well
sessionService.setIdMesure(idMesure);
}
}
}
Session Service :
#Named(value="sessionService")
#SessionScoped
public class SessionService implements Serializable
{
private LienURL lienUrl = new LienURL();
public String lienUrl()
{
String lien = "";
if (idMesure != null)
{
lien = lienUrl.getUrl();
lien += idMesure.toString();
return lien;
}
return "";
}
}
Bean :
public class LienURL
{
private String url;
public LienURL()
{
this.url = "myLink&BirtParameter="; //The base link with a Birt parameter waiting for the idMesure to be passed.
}
}
This solution doesn't work. When the user click on the menu item of the context menu component, it's opening a new tab but the opened page is the same as the one the user just leaved. I think that's because the PF's attribute url loads the url once (and the first time, my url is null because the idMesure isn't filled yet), and it just ignores the good link I try to pass after idMesure is filled.
2nd solution : use the redirect of the FacesContext
Facelet :
<p:contextMenu id="menuMesure" for="treeVArboParents" nodeType="3">
<p:menuitem value="OPL" actionListener="#{arboParObjView.sessionService.lienUrl()}" />
</p:contextMenu>
Service :
#Named(value="sessionService")
#SessionScoped
public class SessionService implements Serializable
{
private LienURL lienUrl = new LienURL();
public void lienUrl() throws IOException
{
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
String url = lienUrl.getUrl()+idMesure.toString();
ec.redirect(url);
}
}
The bean and the view don't change. It's the same as in the 1st solution.
The second solution works better than the first one. It is opening the good page with the good url, but in the same tab as the page where the user was. Is there a way to use the FacesContext redirect, but in another tab, as the target="_blank" do (the target only works with the url attribute) ? Or is there a way to make the url attribute read other urls than the first passed (which is null) ?
Thanks, and excuse my english.
Please use target="_blank" in p:menuitem only in second solution and it should work.
Below is updated code
<p:contextMenu id="menuMesure" for="treeVArboParents" nodeType="3">
<p:menuitem value="OPL" actionListener="#{arboParObjView.sessionService.lienUrl()}" target="_blank" />
</p:contextMenu>
and
public void lienUrl() throws IOException
{
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
String url = lienUrl.getUrl()+idMesure.toString();
ec.redirect(url);
}
Thanks to all the contributors for their help. Solution below :
View :
#Named(value="arboParObjView")
#ViewScoped
public class ArboParObjView implements Serializable
{
#Inject
private TreePodeService treePodeService;
private TreeNode selectedNode;
private Integer idMesure;
private String lienOplBirt;
...
//redirect to the generated link (called by the UI)
public void redirectOpl()
{
try {
FacesContext.getCurrentInstance().getExternalContext.redirect(lienOplBirt);
} catch (IOException e) {
e.printStackTrace();
}
}
//generate the Birt Link
public void genererLienBirt()
{
String libelle = "";
if (selectedNode != null)
{
libelle = selectedNode.getData().toString();
VArboParObjectifsParents mesureSelected = treePodeService.getPodeArboObjParentDao().findByLibelle(libelle);
idMesure = mesureSelected.getIdRoot();
}
lienOplBirt = "https://theLinkToPass"+"&RP_idMesure="+this.idMesure;
}
...
//Execute the genererLienBirt() method everytime selectedNode's value changes
public void setSelectedTreeNode(TreeNode selectedNode) {
if (selectedNode != this.selectedNode)
{
this.selectedNode = selectedNode;
genererLienBirt();
}
this.selectedNode = selectedNode;
}
}
Facelet (UI)
<p:menuitem value="OPL" includeViewParams="true" action="#{arboParObjView.redirectOpl()}" ajax="false" />

Set property of another bean after action method is invoked

Mojarra 2.2
I have two beans`.
public class MyBean1{
private String myProperty1;
//GET, SET, CTOR
public void doAction(){
//assign something to myProperty1
}
}
public class MyBean2{
private String myProperty2;
//GET, SET, CTOR
}
Now, I need to assign the value of the property MyBean1::myProperty1 to MyBean2::myProperty2 after the doAction() method invocation by clicking a button:
<h:commandButton action="#{myBean1.doAction}">
<f:setPropertyActionListener target="#{myBean2.myProperty2}"
value="#{myBean1.myProperty1}" />
</h:commandButton>
But it doesn't work. And I figured out that it doesn't work due to the following reason:
Clicking a button causes ActionEvent to be broadcasted. It performs by this method (javax.faces.component.UICommand):
public void broadcast(FacesEvent event) throws AbortProcessingException {
super.broadcast(event); //1 <-------------------- HERE
if (event instanceof ActionEvent) {
FacesContext context = getFacesContext();
MethodBinding mb = getActionListener();
if (mb != null) {
mb.invoke(context, new Object[] { event });
}
ActionListener listener =
context.getApplication().getActionListener();
if (listener != null) {
listener.processAction((ActionEvent) event);
}
}
}
I've noticed that the ActionEvent broadcasting by clickng the button is being handled by two listeners and one that comes from super.broadcast(event) invokation at //1 is com.sun.faces.facelets.tag.jsf.core.SetPropertyActionListenerHandler.SetPropertyListener.
The handling is performed before invokation of the action method.
Of course, I can embed the action method invokation into the MyBean1:getMyProperty1() getter, so the myProperty1 field will be properly intialized, but it seems quite wierd to me. What is the right way to achieve that?

How to use Primefaces Dialog with #ViewScoped setting Parameters?

I'm facing again problem with Dialog.
What I intend to do is a common dialog that will be used for the whole appication, It has its own managed bean that is inherited by other MBs that need to use it, then some parameters are set by example super.setParam(...) to set some data to be displayed.The problem is that when the dialog is being loaded a getter method is called to retrieve the parameters set and it is no longer there, its just null.
I believe that due to the MB being #ViewScoped the container is creating a new instance when the dialog is beying loaded, but the setter method was called before it, so the new instance return to the default values. Using a #SessionScoped would solve the problem but it is not a good choice.
As a work around I tried to set the parameter in the request and then read it in the getter method but it is no longer there either.
Is there some way to get it working?
//here I put the parameter
public void setParam(MyObject myObject) {
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("params", myObject);
public MyObject getMyObject() {
// now the parameter is no longer there...
Object objet = FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("params");
.... after doing some things
return anotherObject;
}
}
EDIT<<<<
All starts with this button on a "client.xhtml"
<p:commandButton value="Call Dialog" ajax="true"
actionListener="#{subDialogMB.startProcess}"
>
</p:commandButton>
#javax.faces.bean.ManagedBean
#javax.faces.bean.ViewScoped
public class SubDialogMB extends SuperDialogMBean() {
public void starProcess() {
try {
MyObject myObject = service.CreateMyObject....
super.setMyObject();
super.shpwDialog();
}
}
#javax.faces.bean.ManagedBean
public class SuperDialogMBean() {
public void setMyObject(MyObject myObject) {
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("params", myObject);
}
public MyObject getMyObject(){
public MyObject getMyObject() {
// now the parameter is no longer there...
Object objet = FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("params");
.... after doing some things
return anotherObject;
}
}
public void showDialog() {
Map<String,Object> options = new HashMap<String, Object>();
options.put("modal", true);
options.put("draggable", false);
options.put("resizable", false);
options.put("contentHeight", 900);
options.put("contentWidth", 1100);
RequestContext.getCurrentInstance().openDialog("myDialog", options, null);
}
}
and finally in the Dialog xhtml
<p:outputText value="#{superDialogMBean.someValue}" />

When using lazy dataTable another component does not get updated / 2nd component data is one request behind

I have a PrimeFaces p:dataTable and enabled lazy loading by implementing a LazyDataModel.
The dataTable holds search results, so when doing a search request the search service only retrieves the required (paginating) data. That works fine.
When doing a ajax request with p:commandButton:
<p:commandButton id="searchCmdBtn" value="Search" action="#{searchBean.search}"
update=":resultForm:resultList :filterForm:filterMenu :resultForm:messages"
ajax="true" />
the dataTable gets updated properly, but not the filterMenu in the filterForm (differnt forms, bcz using p:layout).
The filterMenu is one request behind. Which means when I hit search button again, the filterMenu gets updated with t only gets updated after the 2nd ajax request
Bean
#ManagedBean
#ViewScoped
public class SearchBean implements Serializable {
private LazyDataModel<Entity> lazyDataModel;
private MenuModel filterMenuModel = new DefaultMenuModel();
private SearchResult searchResult = null;
public void search() {
// lazy call
getLazyDataModel();
if (searchResult != null) {
buildFilterMenu(searchResult);
}
}
private void initializeDataModel() {
lazyDataModel = new LazyDataModel<Entity>() {
private static final long serialVersionUID = 1L;
#Override
public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String> filters) {
// handling sorting and filtering
// get search results
try {
setSearchResult(searchService.getEntities(queryText, selectedQueryOperand, getFilterOptions(), first, (first + pageSize), multiSortMeta));
} catch (Exception e) {
// handle exception
}
if (searchResult == null) {
return null;
}
List<Entity> resultEntities = searchResult.getResultEntities();
// total count
this.setRowCount((int) searchResult.getTotalSize());
return resultEntities;
}
// other override-methods
};
}
public void buildFilterMenu() {
// builds the filterMenu depending on searchResults
}
// getters and setters
public LazyDataModel<Entity> getLazyDataModel() {
if (lazyDataModel == null) {
initializeDataModel();
}
return lazyDataModel;
}
}
filters.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<p:panelMenu id="filterMenu" model="#{searchBean.filterMenuModel}" />
</ui:composition>
After searching the PF forum I found the root cause:
The dataTable Lazy load() method is invoked during render response phase
To know about the phases, read this tutorial on JSF lifecycle from BalusC
Solutions for displaying messages (e.g: p:messages or p:growl):
Update message component with PrimeFaces RequestContext
RequestContext.getCurrentInstance().update(":growlOrMsgID");
This will not work because at that time it's too late to add additional components to update.
use dataTable attribute errorMessage
No attribute found with this name for dataTable
Put the p:messages or p:growl below the p:dataTable
Worked for me
Use PF execute method of RequestContext
The RequestContext#execute() executes a javascript after current ajax request is completed.
Worked for me
See also:
Request update of component with ajax from LazyDataModel.load?
How to handle error in Primefaces lazy load?
PF Issue: DataTable with LazyDataModel updates model during render
http://itaffinity.wordpress.com/2013/06/08/jsf-displaying-facesmessages-during-render-response-phase/

submitting form with p:commandButton jsf

I have a question regarding submitting form content with p:commandbutton that tends to work in the ajax way.
If I have a code like this:
<f:verbatim rendered="#{myBean.constructor}"></f:verbatim >
<h:form prependId="false">
....
.....
<p:commandButton value="#{msg.Add_Parameter_Set}" update="addParameterSetPnl,msgs" action="#{myBean.initNewParametersSet}"/>
</h:form>
When submitting the form with the command button, will the method getContructor from f:verbatim be called (I update different parts of the form)? How can I prevent it from being called?
I thought that submitting a form, only renders the content of the form / the content that was specified by update parameter..
It shouldn't harm. If you're doing expensive stuff in there, then you should move that to the constructor, #PostConstruct or action method of the bean in question, or introduce lazy loading or phase sniffing.
// In Constructor..
public Bean() {
constructed = getItSomehow();
}
// ..or #PostConstruct..
#PostConstruct
public void init() {
constructed = getItSomehow();
}
// ..or action method..
public String submit() {
constructed = getItSomehow();
return "outcome";
}
// ..or lazy loading..
public boolean getConstructed() {
if (constructed == null) constructed = getItSomehow();
return constructed;
}
// ..or phase sniffing (this one updates during render response only).
public boolean getConstructed() {
if (FacesContext.getCurrentInstance().getRenderResponse()) constructed = getItSomehow();
return constructed;
}
See also
Why JSF calls getters multiple times?

Resources