jsf navigation including content pages via ajax - ajax

i have a not resolveable problem, or at least with my limited knowledge about jsf.
I know there are some good solutions to find on stackoverflow, but i can't figure out my error.
i just want to have some commandlinks like a navigationbar and they should change the content of a pre defined div tag which got an include clause. So i guess my Index could be reinterpreted as a kind of template.
my Index:
<h:panelGroup id="navigation" layout="block">
<h:form>
<h:panelGrid columns="4" columnClasses="colDefault,colDefault,colDefault,colDefault">
<f:ajax render=":include">
<h:commandLink value="entry1" action="#{menuController.setPage('login')}" />
<h:commandLink value="entry2" action="#{menuController.setPage('register')}" />
<h:commandLink value="entry3" action="#{menuController.setPage('welcome')}" />
</f:ajax>
</h:panelGrid>
</h:form>
</h:panelGroup>
<h:panelGroup id="center_content" layout="block" class="center_content" >
<h:panelGroup id="include">
<ui:include src="#{menuController.page}.xhtml" />
</h:panelGroup>
</h:panelGroup>
its just like in this post of BalusC
with a small and pretty simple bean:
#ManagedBean
public class MenuController implements Serializable{
private String page;
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
but i got a TagAttributeException #
/index.xhtml #17,92 action="#{menuController.setPage('login')}" Could not Resolve Variable [Overflow]: menuController
i've tryed, but i have no clue what to do.

You need to put the bean in a fixed scope:
#ManagedBean
#ViewScoped
public class MenuController implements Serializable {}
And you need to preinitialize page with a default value:
private String page;
#PostConstruct
public void init() {
page = "login"; // Default value.
}

Related

The <ui-repeat> component disappears after an AJAX request

I use JSF with PrimeFaces framework
I have a <ui-repeat> containing <p:fieldset>, when I filter <p:fieldset> with an AJAX query, the <ui-repeat> disappears from the page.
Here is my code :
<h:form id="myForm1">
<p:panelGrid id="pnlg">
<ui:repeat var="state" value="#{myBean.listState}" varStatus="status">
<p:fieldset id="fieldsetState">
<p:dataGrid id="dataGridState" value="#{myBean.state}">
<p:panel id="pnl">
// some code...
</p:panel>
</p:dataGrid>
</p:fieldset>
</ui:repeat>
</p:panelGrid>
</h:form>
<h:form id="myForm2">
<p:commandButton value="Filter">
// When I run this AJAX query, it is supposed to update 'myForm'. Instead, 'pnlg' disappears
<p:ajax listener="#{ManageState.filterState}" update="myForm1" />
</p:commandButton>
</h:form>
When I run this AJAX query, it is supposed to update 'myForm'. Instead, 'pnlg' disappears. I think it is because of <ui:repeat>.
Here is my backing Bean :
#ManagedBean
#ViewScoped
public class ManageState extends AbstractManagedBean implements Serializable {
public void filterState() {
// Filter the list...
}
}
#ManagedBean
#SessionScoped
public class myBean implements Serializable {
private List<sortedBean> listState;
// getter, setter...
}
I solved the problem, merged the two forms and it works. But I do not know exactly why he behaves this way.

Primefaces AJAX Cannot render nested UIComponent AND actionListener is not working

EDIT 2: Why it is different
#BalusC, this is different from the post you say because I'm asking about an actionListener weird behavior that's not executing a method.
Also, In my test I'm following the Primefaces's documentation, applying fixed id attribute to every NamingContainer and checking the generated HTML (and has the expected id's)
The post you say it's a duplicate from this, was a good help but here we're talking about another problems.
I was working in a webapp's layout and found a problem updating the DOM. I'm working with Primefaces 5.2 and Glassfish 4.1. To isolate the problem I tried to test it in other project but I found another issue in my test. Maybe I'm missing something, so I need to ask in this forum.
I'll go backwards: I'll describe the test and then the real problem so you can see it has the same structure
THE FAILING TEST
index.xhtml
<h:body>
<h:form id="form-render">
<p:commandButton id="btnRender" value="Render" update=":form-rendered"
actionListener="#{renderView.setRender(true)}"/>
</h:form>
<h:form id="form-rendered">
<h:outputText value="Rendered in form-rendered" rendered="#{renderView.render}"/>
<p:panelGrid id="panel-grid" rendered="#{renderView.render}">
<p:outputLabel value="Rendered in form-rendered:panel-grid"/>
</p:panelGrid>
</h:form>
</h:body>
renderView.java
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class RenderView implements Serializable {
private static final long serialVersionUID = -1687524798440117276L;
private boolean render;
public RenderView() {
this.render = false;
System.out.println("Constructor - render=" + this.render);
}
public boolean isRender() {
return render;
}
public void setRender(boolean render) {
this.render = render;
System.out.println("Setter - render=" + this.render);
}
}
But when I run the test only renders the <h:outputText> component. I tried another options:
update=":form-rendered, :form-rendered:panel-grid": same result
update=":form-rendered:panel-grid": doesn't render anything
move rendered=#{...} attribute from <p:panelGrid> to <p:outputLabel> inside it: doesn't change
I don't know how to reference the <p:panelGrid> inside the <h:form>. According to Primefaces's documentation:
Update attribute takes a comma or white-space separated list of JSF component ids to be updated
So the first option should work, but it doesn't. What am I missing here?
THE REAL PROBLEM
The previous test came from a problem I was facing working with a layout. The layout's idea is the following:
In several pages I need to search something and show the results under the search form (with AJAX, of course).
Every page in the layout is a facelet template client (made with <ui:composition>)
This is ONLY the layout, there are not any queries, business logic or anything like that. The #ManagedBean classes I use are just creating dummy objects to populate the Primefaces's components
So I used the same structure of the previous test to solve the problem in every page. The funny thing is that I coded the first one and worked perfectly, but when I coded the second, fails on rendering the second form. Even more, I coded the third and worked perfectly, coded the fourth and fails!!!.
In my first solution attempt I used the following bean:
#ManagedBean // from javax.faces.bean
#ViewScoped // idem
public class SearchView {
private boolean showResults;
public SearchView() {
this.showResults = false;
System.out.println("Constructor-showResults=" + this.showResults);
}
public boolean isShowResults() {
return showResults;
}
public void setShowResults(boolean showResults) {
this.showResults = showResults;
System.out.println("Setter-showResults=" + this.showResults);
}
}
I'll copy-paste from a working example first and then form a failing example, so maybe you can see something I'm missing.
searchPage1.xhtml (working)
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
template="./../templateMenu.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<ui:define name="left">
<ui:include src="include/auMenu.xhtml"/>
</ui:define>
<ui:define name="content">
<h1>Search 1</h1>
<h:form id="form-busq-au">
<p:panelGrid columns="2" styleClass="ui-noborder">
<!--form fields -->
<p:commandButton value="Search" icon="ui-icon-search" style="width: 100%;"
actionListener="#{searchView.setShowResults(true)}"
update=":form-res-au"/>
</p:panelGrid>
</h:form>
<h:form id="form-res-au">
<c:if test="#{searchView.showResults}">
<h1>Search Results</h1>
</c:if>
<p:panelGrid id="panelgrid-res-au" columns="2" rendered="#{searchView.showResults}">
<!-- other fields -->
</p:panelGrid>
</h:form>
</ui:define>
</ui:composition>
searchPage2.xhtml (not working)
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
template="./../templateMenu.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<ui:define name="left">
<ui:include src="include/menu.xhtml"/>
</ui:define>
<ui:define name="content">
<h:form id="form-busq-mt">
<h1>Search 2</h1>
<p:panelGrid columns="4" styleClass="ui-noborder">
<!-- form fields -->
<p:commandButton value="Search" icon="ui-icon-search" style="width: 100%;"
actionListener="#{searchView.setShowResults(true)}"
update=":form-res-mt"/>
</p:panelGrid>
</h:form>
<h:form id="form-res-mt">
<c:if test="#{searchView.showResults}">
<h1>Search Results</h1>
</c:if>
<p:panelGrid columns="2" rendered="#{searchView.showResults}">
<!-- Other fields -->
</p:panelGrid>
</h:form>
</ui:define>
</ui:composition>
As you can see, it's the same structure in the test and the two pages, but the behavior is different. I don't know if this is a bug in primefaces or what.
Debugging the code I realized that in the second page, the setSearchResult(true) method is never called, don't know why. So I tried the following solution:
Failed solution attempt
Thinking that it was a problem with the SearchView Managed Bean, I made a change in the Controller: I made an abstract class with the attribute and methods and a #ManagedBean for each one of the web pages extending the abstract class. In code:
public abstract class SearchView {
private boolean showResults;
public SearchView() {
this.showResults = false;
System.out.println("Constructor-showResults=" + this.showResults);
System.out.println("Class: " + this.getClass().toString());
System.out.println("ID: " + this.getClass().hashCode());
}
public boolean isShowResults() {
return showResults;
}
public void setShowResults(boolean showResults) {
this.showResults = showResults;
System.out.println("Setter-showResults=" + this.showResults);
}
}
And for every search page:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class ConcreteXXXSearchView extends SearchView implements Serializable {
private static final long serialVersionUID = -4717041016001640528L;
}
but the result is the same (setShowResult(true) is never called in the second page). The println() methods in the abstract class SearchView was to test that I'm instantiating different objects (indeed, there are different).
I tried the test's options but the problem is in the <p:commandButton> because actionListener is not working.
Summarizing
I'm facing two problems here:
In the test I need to render a <h:form> containing a UIComponent that implements NamingContainer(<p:panelGrid>)
In the project I need to know why the setShowResults(true) is not called in the failing page
Any help / guide is appreciated. Thanks in advance
EDIT: more info
In both TEST and REAL PROBLEM I checked the DOM with the browser inspector and the id attribute is correct for both <h:form id="form-res-mt"> and <p:panelGrid id="panelgrid-res-mt">
You have used actionListener="#{searchView.setShowResults()}" in your non-working approach.
<p:commandButton value="Search" icon="ui-icon-search" style="width: 100%;"
actionListener="#{searchView.setShowResults()}"
update="form-res-mt"/>
But, searchView.setShowResults() method expects a boolean argument, change your code to:
<p:commandButton value="Search" icon="ui-icon-search" style="width: 100%;"
actionListener="#{searchView.setShowResults(true)}"
update="form-res-mt"/>
Also, use <ui:fragment rendered="yourCondition"> instead of <c:if test="condition"> because if component condition returns false ,it'll not attached to the component tree. And thus can't find the component in the UI Tree.

Render a component only when validation success

In JSF 2.X, can I render a component only when the validation success?
In my application I have many fields that must be filled. These data can be imported from a WebService through a search key.
When the user enter a valid search key the system searches the other fields and render them with the new values. But when the user enter a nonexistent key (or any other validation error) the server generates a validation error but still renders the fields, thus losing any data that there were filled.
What I need is that the user can perform the query and that if the query does not return results, this does not affect any data that he has already entered.
Below is a code example. Thus, if the user has filled in the fields inside updateThisOnSuccess and just after making an attempt to query without success, the value that is filled in is not lost.
<h:inputText value="#{controller.searchWebService}" >
<f:ajax execute="#this" render="updateThisOnSuccess messages" />
</h:inputText>
<h:panelGroup id="updateThisOnSuccess">
<h:inputText value="#{controller.field}" />
<!-- other fields -->
</h:panelGroup>
Submit the field values to run the search also does not seem an option as this will cause need to validate the fields inside updateThisOnSuccess.
Note: I saw the answer given by #BalusC to a similar question, but this is different from what I'm wondering why, in that case, foo-holder is always rendered and foo is conditioning. It's not my case, since this approach would make the controls do not appear when the validation fails.
Try this
<h:panelGroup id="updateThisOnSuccess">
<ui:fragment rendered="#{not facesContext.validationFailed}">
<h:inputText value="#{controller.field}" />
<!-- other fields -->
</ui:fragment>
</h:panelGroup>
Plaase try this. The requirements are that you must implement model validations with Bean Validation and the search field must implement JSF validation if required.
If you write "123456" then data is returned, else nothing is returned and a message is printed.
The backing bean:
#Named
#ViewScoped
public class yourBean implements Serializable{
private static final long serialVersionUID = 1L;
#Size(min=2)
private String field01;
private String searchWebService;
public void saveF(){
System.out.println("save");
}
public void searchWebServiceF(){
Boolean successWS = ("123456").equals(this.searchWebService);
if(successWS){
this.setField01("WS data");
}else{
FacesContext.getCurrentInstance().
addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "WS fails", ""));
}
}
public String getSearchWebService() {
return searchWebService;
}
public void setSearchWebService(String searchWebService) {
this.searchWebService = searchWebService;
}
public String getField01() {
return field01;
}
public void setField01(String field01) {
this.field01 = field01;
}
}
In your page:
<h:form id="form01">
<h:messages id="message"/>
<h:inputText id="wsid" value="#{pruebasBorradorBean.searchWebService}">
<f:validateLength maximum="6"/>
<f:ajax execute="#form" render="#form" listener="#{pruebasBorradorBean.searchWebServiceF()}" />
</h:inputText>
<h:panelGroup id="thedata">
<h:inputText value="#{pruebasBorradorBean.field01}">
<f:validateBean disabled="#{param['javax.faces.source']!='form01:save'}"/>
</h:inputText>
<!-- other fields -->
</h:panelGroup>
<h:commandButton id="save" value="submit">
<f:ajax render="thedata message" execute="#this thedata" listener="#{pruebasBorradorBean.saveF()}"/>
</h:commandButton>
</h:form>
You can change the components that will be processed in render phase changing the Collection at getRenderIds() of PartialViewContext. According to documentation this Collection is mutable.
FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds().remove("formName:updateThisOnSuccess");
To test this solution, I used this controller:
#Named
#ViewScoped
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private final static List<String> LIST_VALID_WEB_SERVICE_SEARCHS =
Arrays.asList(new String[] {"foo", "bar"});
private String webServiceParameter;
private Integer field01;
public void searchWebService() {
if (LIST_VALID_WEB_SERVICE_SEARCHS.contains(getWebServiceParameter())) {
setField01(123);
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getPartialViewContext().getRenderIds().remove("formFields");
FacesMessage facesMessage = new FacesMessage("Search not found in WebService.");
facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
facesContext.addMessage("formName:searchWebService", facesMessage);
}
}
public void submit() {
System.out.println("submitted");
}
// Getters and Setters
}
And used this view:
<h:form id="formSearch">
<h:inputText id="webServiceParameter" value="#{controller.webServiceParameter}">
<f:ajax execute="#this" render="formFields messages" listener="#{controller.searchWebService}" />
</h:inputText><br />
</h:form>
<h:form id="formFields">
<h:inputText id="field01" value="#{controller.field01}" required="true">
<f:validateLongRange minimum="2" maximum="345" />
</h:inputText><br />
<!-- other fields -->
<h:commandButton value="submit" action="#{controller.submit}">
<f:ajax render="#form messages" execute="#form" />
</h:commandButton>
</h:form>
<h:messages id="messages" />
You can do something like that:
<f:ajax execute="#this" render="#{controller.success} message"/>
where success is a String attribute that will be empty if the WS fails and will be "updateThisOnSuccess" if not .
Or you could get rid of the JSF validation mechanism for informing the user the WS has failed. Think of it, it is not really a validation of the Model. You could draw an icon beside the WS Id field in red color or something similar using a boolean flag attribute in the backing bean.

JSF page only loads data when backing bean is on session scoped

This is my admin_order_search.xhtml page and it has a <p:dataTable>
and I'm trying to call a admin_view_order.xhtml page with the particulate
order object
<p:column>
<f:facet name="header">
<h:outputText value="View" />
</f:facet>
<p:commandButton action="admin_view_order?faces-redirect=true" id="view" value="View Info" update="dataTable" actionListener="#{viewOrderController.loadOrder(order)}" />
</p:column>
and this is my "admin_view_order.xhtml"
<h:form id="orderViewForm">
<p:growl id="growl" showDetail="true" autoUpdate="true" sticky="false" />
<p:outputLabel value="#{viewOrderController.order.orderId}"></p:outputLabel>
<p:outputLabel value="#{viewOrderController.order.customerName}"> </p:outputLabel>
</h:form>
and hear is my "ViewOrderController.java" page
#Component
#ManagedBean
#ViewScoped
public class ViewOrderController implements Serializable{
private static final long serialVersionUID = 1L;
private Order order;
public void loadOrder(Order order){
System.out.println("ID : "+order.getOrderId());
System.out.println("Name : "+order.getCustomerName());
this.order = order;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
the problem is admin_view_order.xhtml shows the order details, only if my ViewOrderController is on #SessionScoped but I want it to be on ViewScoped
Please let me knows how to do that?
Why do you want the Controller to be ViewScoped?
After leaving the view (navigate to admin_view_order.xhtml) a new instance of your controller is used. So the changes you made before (setting the order in loadOrder) are gone.
There is another way to do that , is to passing parameter through the GET request ( for example you can pass the id of the order object in admin_order_search.xhtml to , and then recover this id and use it in your backing bean by searching the object with this id ).
This is possible by using view parameters
1-pass the id of the object (add the folowing tag inside your button )
<f:param name="id" value="#{viewOrderController.order.orderId}" />
2-After that, in your admin_view_order.xhtml page, catch the view param and load the info for that order:
<f:metadata>
<f:viewParam name="id" value="#{viewOrderController.newOrderId}" />
<f:event type="preRenderView" listener="#{viewOrderController.loadOrder}"/>
</f:metadata>
note that i added an attribut ( newOrderId ) to put the order.orderId into it

JSF2 - what scope for f:ajax elements?

I have this form:
<h:form>
<h:outputText value="Tag:" />
<h:inputText value="#{entryRecorder.tag}">
<f:ajax render="category" />
</h:inputText>
<h:outputText value="Category:" />
<h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>
What I'm trying to achieve: When you type in the "tag" field, the entryRecorder.tag field is updated with what was typed. By some logic upon this action the bean also updates its category field. This change should be reflected in the form.
Questions:
What scope shall I use for EntryRecorder? Request may not be satisfactory for multiple AJAX requests, while session will not work with multiple browser windows per one session.
How can I register my updateCategory() action in EntryRecorder so that it is triggered when the bean is updated?
Answering point 2:
<h:inputText styleClass="id_tag" value="#{entryRecorder.tag}"
valueChangeListener="#{entryRecorder.tagUpdated}">
<f:ajax render="category" event="blur" />
</h:inputText>
Bean:
#ManagedBean
#ViewScoped
public class EntryRecorder {
private String tag;
private String category;
#EJB
private ExpenseService expenseService;
public void tagUpdated(ValueChangeEvent e) {
String value = (String) e.getNewValue();
setCategory(expenseService.getCategory(value));
}
}
Number 1, anybody?
To point 1, I'll use Request since there is no need to use View and Session is, as you well pointed, completely unnecessary.
For point 2, since you are using <f:ajax/> I suggest making full use of it. Here is my proposal:
xhtml:
<h:form>
<h:outputText value="Tag:" />
<h:inputText value="#{entryRecorder.tag}">
<f:ajax render="category" event="valueChange"/>
</h:inputText>
<h:outputText value="Category:" />
<h:inputText value="#{entryRecorder.category}" id="category" />
</h:form>
Note the use of valueChange event instead of blur (not that blur doesn't work but I find valueChange more 'proper' for a value holder component).
bean:
#ManagedBean
#RequestScoped
public class EntryRecorder {
private String tag;
private String category;
public String getCategory() {
return category;
}
public String getTag() {
return tag;
}
public void setCategory(String category) {
this.category = category;
}
public void setTag(String tag) {
this.tag = tag;
tagUpdated();
}
private void tagUpdated() {
category = tag;
}
}
Unless you really want the tagUpdated method executed only when tag is updated through the view, my proposal looks more clear. You don't have to deal with the events (nor casting) and the tagUpdated method can be private hiding it's functionality from possible misuses.

Resources