I have a web application which uses a4j:commandButton like this:
<h:form>
<a4j:region id="search_form">
<a4j:commandButton render="ListOfPerson" action="personBean.search" value="search" execute="#form" status="ajaxStatus"/>
</a4j:region>
<a4j:outputPanel id="ListOfPerson" ajaxRendered="true">
<rich:datatable>...</rich:datatable>
</a4j:outputPanel>
</form>
The bean ist annotated with #ManagedBean(faces package) and #ViewScope. When i change the scope to #SessionScope, everything works like expected. Any ideas?
I'm using the following imports:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
Solved, i removed the a4j:region around the a4j:commandButton and it works.
Related
I have a common task to choose one or more 'LocalizacaoTO' before doing anything else on the page.
Currently the logic of data retrieval/process/ajax events and so on are maintained on a ViewScoped bean called "SeletorLocalizacaoMB" and I’d like to use multiple instances of the same bean on the same page.
Firstly I used composite component but when I chose a node, it were stored on the last bean on the page.
If I had 3 instances declared on TesteSeletorMB:
#Named
#ViewScoped
public class TesteSeletorMB implements Serializable {
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceOne;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceTwo;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB instanceThree;
}
No matter which component on page I used, instanceThree always hold the values.
Based on some research I understood that composite component is not the ideal solution for this problem.
So I changed the UI implementation and used Facelets to create a 'template' named seletor.xhtml.
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:o="http://omnifaces.org/ui">
<p:dialog header="Busca Hierarquica"
id="#{id}ModalTree"
widgetVar="dlgSelecaoHierarquica"
showEffect="fade"
hideEffect="fade"
closeOnEscape="true"
modal="#{bloqueiaModal}"
height="400px"
width="500px">
<h:panelGrid columns="2">
<p:commandButton id="#{id}btnSelecao"
value="Selecionar e Voltar"
action="#{mb['selecionarLocalHierarquico']}"
update="#(.#{id}-auto-complete)"
oncomplete="bloqueiaAutoMulti();"/>
<p:commandButton value="Voltar"
type="button"
onclick="PF('dlgSelecaoHierarquica').hide();" />
</h:panelGrid>
<p:scrollPanel style="width:100%;height:350;" mode="native">
<p:tree id="#{id}Tree"
style="width:100%;height:100%;"
styleClass="estilo-arvore"
value="#{mb.arvoreHierarquica}"
var="local"
selectionMode="multiple"
dynamic="true"
animate="true">
<p:ajax event="select" listener="#{mb['onNodeSelect']}" update="#this"/>
<p:treeNode >
<h:outputText value="#{local.cdClasseLocal}: #{local.cdLocalizacao} #{local.niveis}" />
</p:treeNode>
</p:tree>
</p:scrollPanel>
</p:dialog>
</ui:composition>
Test page using <ui:include>
<f:subview id="seletorAlpha">
<ui:include src="/template/seletor.xhtml">
<ui:param name="mb" value="#{testeSeletorMB.seletorAlpha}" />
<ui:param name="id" value="alpha" />
</ui:include>
</f:subview>
<f:subview id="seletorBravo">
<ui:include src="/template/seletor.xhtml">
<ui:param name="mb" value="#{testeSeletorMB.seletorBravo}" />
<ui:param name="id" value="bravo" />
</ui:include>
</f:subview>
Test Bean holding multiple instances:
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class TesteSeletorMB implements Serializable {
#Inject
#Getter #Setter
private SeletorLocalizacaoMB seletorAlpha;
#Inject
#Getter #Setter
private SeletorLocalizacaoMB seletorBravo;
}
CDI Bean used on 'seletor.xhtml'
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class SeletorLocalizacaoMB implements Serializable {
private List<LocalizacaoTO> locaisHierarquicosSelecionados;
private TreeNode arvoreHierarquica;
//PostConstruct, Ajax events and things :)
}
In my example, I want that TesteSeletorMB variables (seletorAlpha and seletorBravo) hold different values on their lists. Is it possible?
I tried to change SeletorLocalizacaoMB scoped to #Dependent but it didn't work neither. Here is where the things got confused. Reading CDI API, the first state says:
Beans declared with scope #Dependent behave differently to beans with other >built-in scope types. When a bean is declared to have scope #Dependent:
No injected instance of the bean is ever shared between multiple injection >points.
It should't hold the same instance, right?!
Environment
WebSphere Application Server 8.5.5.2
Apache MyFaces 2.0.2
PrimeFaces 5.0
OmniFaces 1.7
I can provide additional data if necessary. I didn't paste all 'SeletorLocalizacaoMB' code because it has many dependencies and I had the feeling that the problem is not related to how the class handles actions.
I am in need of some assistance in getting my Composite Component to behave. I am still learning the ropes in JSF, so please excuse any ignorance that might be displayed in this post.
So, I am working with JSF 2.0 and decided to build a composite component to make this particular code snippet reusable. The component displays everything perfectly, but will not behave at all when trying to add the actionListener.
Here is the code for my component
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface displayName="columnUpdate">
<composite:attribute name="id"
required="true"
displayName="id"
shortDescription="Id to apply to this control and its child components">
</composite:attribute>
<composite:attribute
name="value"
displayName="value"
required="true"
shortDescription="Field that will hold the new updated value.">
</composite:attribute>
<composite:attribute
name="columnName"
displayName="columnName"
required="true"
shortDescription="Value that will be applied as the column header">
</composite:attribute>
<composite:attribute
name="text"
displayName="text"
shortDescription="Text to be displayed above the field">
</composite:attribute>
<composite:actionSource name="actionEvent" targets="saveEvent"></composite:actionSource>
</composite:interface>
<composite:implementation>
<h:outputLabel value="#{cc.attrs.columnName}" onclick="showWindow('#{cc.attrs.id}')"></h:outputLabel>
<div id="#{cc.attrs.id}" class="ccColumnUpdate">
<div id="windowClose" onclick="closeWindow('#{cc.attrs.id}');" style="top: -10px;" title="Close this window">CLOSE</div>
<div>
<h:outputLabel id="lblTitle" value="#{cc.attrs.text}"></h:outputLabel>
</div>
<div>
<h:inputText id="txtValue" value="#{cc.attrs.value}"></h:inputText>
</div>
<div style="text-align:right;">
<h:commandButton id="saveEvent" value="Save"></h:commandButton>
</div>
</div>
</composite:implementation>
</ui:composition>
Here is the code in my page that uses the component:
<al:columnUpdate id="cuExpenseAmount" value="#{expense.columnValue}" columnName="Expense Amount" text="Set Expense Amount to:">
<f:actionListener for="actionEvent" binding="#{expense.updateColumnValue}">
<f:ajax execute="#form"></f:ajax>
</f:actionListener>
</al:columnUpdate>
and here is my code on the Backing Bean:
public void updateColumnValue(ActionEvent event) throws ParseException{
//Got HERE
}
I am not receiving any errors or hit any breakpoints I set on the backing bean. Any help, or pointers in the right direction would be appreciated.
Regards,
Mike
I found the answer after playing around a little bit and more searching.
Changes to the composite component:
FROM:
<composite:actionSource name="actionEvent" targets="saveEvent"></composite:actionSource>
<h:commandButton id="saveEvent" value="Save"></h:commandButton>
TO:
<composite:attribute name="registerButtonActionListener" method-signature="void actionListener(javax.faces.event.ActionEvent)" />
<h:commandButton id="saveEvent" value="Save" actionListener="#{cc.attrs.registerButtonActionListener}">
<f:ajax execute="#this" event="click"></f:ajax>
</h:commandButton>
Changes to the page using the composite component:
<al:columnUpdate id="cuExpenseAmount" value="#{expense.columnValue}" registerButtonActionListener="#{expense.updateColumnValue}" columnName="Expense Amount">
</al:columnUpdate>
The big change was defining the method signature in the composite attribute.
Regards,
Mike
I found an alternative solution to yours. A drawback of your solution is that you can only register one listener: the actionListener attribute can only point to one method.
The way to add listeners is as follows (you almost had it right in the first piece of code you wrote):
<al:columnUpdate id="cuExpenseAmount" value="#{expense.columnValue}" columnName="Expense Amount" text="Set Expense Amount to:">
<f:actionListener for="actionEvent" binding="#{expense.updateColumnValue(ActionEvent)}">
<f:ajax execute="#form"></f:ajax>
</f:actionListener> </al:columnUpdate>
Notice how the method pointed to by binding takes an ActionEvent parameter. This is a requirement of using <f:actionlistener/>.
Using this method, multiple listeners can be registered to the action source made available by the composite component.
OK, I'm guessing that this might be a bug but I'm not totally sure. Can anyone see what I'm doing wrong?
Here's the situation. I have a composite component that seems to work perfectly when it's alone on the page. The problem comes when the component is nested inside of a ui:repeat. Here are the two places I am calling the component (just for a test):
<q:case aCase="#{userSummaryBackingBean.userCases.get(0)}">
<f:setPropertyActionListener for="clickEvent" target="#{userSummaryBackingBean.value}" value="single"/>
<f:ajax execute="#this" render="#this :westPaneForm"/>
</q:case>
<ui:repeat value="#{userSummaryBackingBean.userCases}" var="aCase">
<li>
<q:case aCase="#{aCase}">
<f:setPropertyActionListener for="clickEvent" target="#{userSummaryBackingBean.value}" value="repeat"/>
<f:ajax execute="#this" render="#this :westPaneForm"/>
</q:case>
</li>
</ui:repeat>
and the component is defined as follows:
<cc:interface>
<cc:attribute name="aCase" type="com.autonomy.calltrack.data.dto.Case"/>
<cc:actionSource name="clickEvent" targets="caseCommandLink"/>
<cc:attribute name="action" targets="caseCommandLink" />
<cc:attribute name="actionSource" targets="caseCommandLink" />
<cc:clientBehavior name="click" event="action" targets="caseCommandLink" default="true"/>
</cc:interface>
<cc:implementation>
<h:commandLink id="caseCommandLink" styleClass="case ui-state-default" title="#{cc.clientId}">
--- more code ---
</h:commandLink>
</cc:implementation>
As you can see, the calls are exactly the same but the single item works and the items in the ui:repeat do not. Now, it makes sense to me that things will be problematic when the component itself has a ui:repeat. I mean, how would you retarget your actionSource, etc without knowing the ID of the items you need (which, inside of the repeat, is basically impossible).
HOWEVER, when I put the ui:repeat outside of the component I can't wrap my head around why things wouldn't work. The REALLY odd thing is that the f:ajax seems to work totally fine. VERY odd.
I've tried prefixing the targets attributes with :#{cc.clientId} and that doesn't help either (even though the "path" to the components is correct). Am I doing something wrong? Does anyone have a solution?
Alright, something must be wrong because even this doesn't work:
<ui:repeat value="#{userSummaryBackingBean.userCases}" var="aCase">
<h:commandLink id="caseCommandLink" value="test" styleClass="case ui-state-default">
<f:setPropertyActionListener target="#{userSummaryBackingBean.value}" value="REPEAT"/>
<f:ajax execute="#this" render="#this :westPaneForm"/>
</h:commandLink>
</ui:repeat>
What the heck could I be missing?
My page was using view params but they weren't a child of f:view so they were causing problems.
When I moved them everything started to work normally. I'm not sure why but it seems that things break when you have something like the following outside of an f:view:
<f:metadata>
<f:viewParam name="caseId" value="#{caseBackingBean.viewingCaseNumber}" />
</f:metadata>
<f:event type="preRenderView" listener="#{caseBackingBean.loadCase}" />
Thanks for the help BalusC.
What I'm trying to achieve is very similar to the one posted in the following link.
How to save an array in JSF with ui:repeat + h:inputText + managed bean?
I'm particularly fascinated with the answer provided by Arjan Tijms in the link above however what I want to achieve is slightly different. Consider the following code snippets.
The bean
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
#RequestScoped
#Named
public class MyBean {
List<String> choices;
public List<String> getChoices() {
return choices;
}
#PostConstruct
public void initChoices() {
choices= new ArrayList<String>();
}
public String save() {
// should save all the choices into some repository
return "";
}
}
and the facelet page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:commandButton value="Save" action="#{myBean.save}" />
</h:form>
</h:body>
</html>
The thing is, this will work if we have some initial data in the list at the beginning. What about situations where the initial list will be empty?
The ideal solution which I'm looking for is to have 1 h:inputText for each choice and when save button is clicked, all choices in each h:inputText is then added to the choices list. I've searched high and low but can't seem to find any hints on how this can be done.
If JSF 2 really doesn't support this, I guess I'll have to use the ugly way with just one h:inputText and use a converter to convert to and from a list but I'm still hoping that an ideal solution can be found.
Hopefully someone from stackoverflow can shed a light in the right direction for me.
Just add an "add" button which adds a new String to the list.
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:inputText value="#{myBean.newChoice}" />
<h:commandButton value="Add" action="#{myBean.add}" />
<h:commandButton value="Save" action="#{myBean.save}" />
with
private String newChoice;
public void add() {
choices.add(newChoice);
newChoice = null;
}
// ...
Note that this only works if bean is put in view scope. A request scoped one would be constructed on every request and hereby recreate the list everytime.
I seem to be having a problem where I have an a4j:commandLink on a rich:popupPanel but the action is not firing. The xhtml looks as follows:
<rich:popupPanel id="rate-panel" modal="true" height="444" width="780" top="60" show="false" onmaskclick="#{rich:component('rate-panel')}.hide()" styleClass="cs-modal">
/**Some html here**/
<a4j:commandLink immediate="false" action="#{venueScore.up}" render="rate-panel" styleClass="rate love">
<span>Love it</span>
</a4j:commandLink>
/**Some more html here**/
</rich:popupPanel>
And the managed bean looks as follows:
#Named("venueScore")
#ViewScoped
public class VenueScoreManager extends BaseManager implements Serializable {
public void up() {
System.out.println("TEST");
//Do something
}
}
I have made the managed bean #ViewScoped.
I have also tried adding an <h:form> around the commandLink however, this does even less than without it. I actually think that is because the commandLink is inside the <h:form> in which the link that opened the popupPanel sits.
Anyway, can someone please point me in the direction of why the action not fire?
Ok, so I fixed it myself. After screwing around I worked out that I just need to add an <a4j:region> around the content in the <rich:popupPanel>. So now the xhtml looks something like this:
<rich:popupPanel id="rate-panel" modal="true" height="444" width="780" top="60" show="false" onmaskclick="#{rich:component('rate-panel')}.hide()" styleClass="cs-modal">
<a4j:region id="panel-region">
/**Some html here**/
<a4j:commandLink immediate="false" action="#{venueScore.up}" render="panel-region" styleClass="rate love">
<span>Love it</span>
</a4j:commandLink>
/**Some more html here**/
</a4j:region>
</rich:popupPanel>
I had the same problem, a4j:commandLink only worked after first click.... put the poppanel inside a form and add domElementAttachment...
<h:form id="myform">
<rich:popupPanel id="pop" domElementAttachment="form">
...
<a4j:commandLink />
...
</rich:popupPanel>
</h:form>
I know that it's an old question but as I had exactly the same problem, I spent a lot of time before fixing it, maybe it will help someone else.
First, I tried the solution proposed above but it did not worked.
Finally, I found this thread:
Issues closing rich:popupPanel via show condition, RF 4.0
And I added the domElement attribute to my popup:
<rich:popupPanel
id="newMailPopup"
**domElementAttachment="form"**
...>
And now, my a4j:commandLink works perfectly :-)