Please see the image below.
image
Those images show how things work with my current code. When I delete the last panel and push the update button, all the panels disappear somehow.
It works well when I do the same with the rest of the panels.
If anyone knows how to solve this problems, it would be a great help.
Thanks in advance.
I've attatched the code below (just in case):
【xhtml】
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<h:body>
<h:form>
<ui:repeat value="#{newapp001.list}" var="item" >
<p:panel header="#{item}" closable="true" >
<p>my information</p>
</p:panel>
</ui:repeat>
<p:commandButton value="Update" update="#form" />
</h:form>
</h:body>
</html>
【ManagedBean】
package sample;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named("newapp001")
#SessionScoped
public class NewApp001 implements Serializable
{
private static final long serialVersionUID = 2610647621325923945L;
private List<String> list;
public NewApp001()
{
this.list = new ArrayList<>();
this.list.add("aaa");
this.list.add("bbb");
this.list.add("ccc");
this.list.add("ddd");
return;
}
public List<String> getList()
{
return this.list;
}
}
When you press the button, the panels' visibility state gets submitted. It's definitely a PF bug, that the last rendered panel's state affects all panels.
Since you don't seem to be interested in tracking the visibility state, the easiest fix would be to not process the panels, thus not storing the visibility state on the server:
<p:commandButton value="Update" process="#this" update="#form" />
Related
When I manually change the selected value of selectOneMenu:
selectOneMenu's selected value gets changed to '2'
I get '2' on the console which means that the 'selectOneMenuAjaxEvent' is WELL being invoked.
I get one XHR request on the Network tab of Firebug.
BUT when I try to change the selected value by clicking on the commandLink:
selectOneMenu's selected value gets changed to '2'
I get nothing in the editor console which means that the 'selectOneMenuAjaxEvent' is NOT being invoked.
I get also no any XHR requests on the Network tab of Firebug which means this ajax event even not being sent.
There is no any error shows up on the Firebug console.
Why is the selectOneMenu's ajax change event not being sent when the value changes by the commandLink?
index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head></h:head>
<h:body>
<h:form id="mainForm">
<h:selectOneMenu id="selectMenu" value="#{indexBean.selectedValue}">
<f:selectItem itemLabel="1" itemValue="1" />
<f:selectItem itemLabel="2" itemValue="2" />
<f:ajax listener="#{indexBean.selectOneMenuAjaxEvent}" />
</h:selectOneMenu>
<h:commandLink value="Change Selected Value"
action="#{indexBean.changeSelectedValue}"/>
</h:form>
</h:body>
</html>
IndexBean
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import java.io.Serializable;
#ManagedBean
#ViewScoped
public class IndexBean implements Serializable {
private String selectedValue = "1";
public void changeSelectedValue(){
selectedValue = "2";
}
public void selectOneMenuAjaxEvent(){
System.out.println(selectedValue);
}
public String getSelectedValue() {
return selectedValue;
}
public void setSelectedValue(String selectedValue) {
this.selectedValue = selectedValue;
}
}
The technical Context
We are developing a J2E application with JSF 2.2 and IBM WAS 8.5.5.
The problem
We have developed a screen in order to load different forms (12 differents forms which include Ajax and other subform...). We want to be able to load dynamically the form in a modal box in Ajax using "ui:include" tag.
Unfortunately, the actions associated to those forms generated dynamically are not executed.
The questions
Do somebody had this problem earlier ?
Do you have some clue to solve the problem ?
Do you know an alternative to load dynamic forms in the same page ?
The code
We built a simple example showing the problem we have.
The main page (fragment)
<ui:composition template="/WEB-INF/templates/globalLayout.xhtml">
<ui:param name="context" value="publication"/>
<ui:define name="content">
<h:form>
<h:commandLink value="EDIT1"
action="#{test.edit()}" layout="block" >
</h:commandLink>
<h:commandLink value="EDIT2"
action="#{test.edit2()}" layout="block" >
</h:commandLink>
<ui:include src="#{test.page}"/>
</h:form>
</ui:define>
</ui:composition>
The subpage 1 (fragment)
<h:outputText value="Page 1 "></h:outputText>
<h:commandLink value="EDIT1" action="#{test.edit()}" layout="block" >
</h:commandLink>
<h:commandLink value="EDIT2" action="#{test.edit2()}" layout="block" >
</h:commandLink>
The subpage 2 (fragment)
<h:outputText value="Page 2 "></h:outputText>
<h:commandLink value="EDIT1" action="#{test.edit()}" layout="block" >
</h:commandLink>
<h:commandLink value="EDIT2" action="#{test.edit2()}" layout="block" >
</h:commandLink>
The managed Bean
package com.myapp;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean(name = "test")
#ViewScoped
public class TestManagedBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3750906342500909173L;
private String page;
public void edit() {
page = "page.xhtml";
}
public void edit2() {
page = "page2.xhtml";
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
Note
Using the "ui:fragment" element is not useable. For us, it take nearly one minute to generated the page whereas with full ajax it should takes nearly 2,3 seconds.
So the example below is not working for us.
<ui:fragment rendered="#{index.page eq 'page2'}">
<ui:include src="page2.xhtml"/>
</ui:fragment>
Try using <ui:decorate template="#{test.page}"/> instead.
I have a ViewScoped CDI bean (javax.faces.view.ViewScoped). It reconstructs (calls a #PostConstruct method) when an ajax render its parent element. What should I do?
Bean:
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
#Named("test")
#ViewScoped
public class TestBean implements Serializable {
private List<Integer> items;
#PostConstruct
private void postConstruct() {
Logger.getLogger("asd").log(Level.INFO, "construct");
items = new ArrayList<Integer>();
items.add(0);
items.add(1);
items.add(3);
items.add(4);
items.add(7);
items.add(10);
}
public List<Integer> getItems() {
return items;
}
public void setItems(List<Integer> items) {
this.items = items;
}
}
View:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 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:pt="http://xmlns.jcp.org/jsf/passthrough">
<h:head>
<title>Simple JSF Facelets page</title>
</h:head>
<h:body>
<h:form>
<h:commandButton value="No reconstructing">
<f:ajax render=":panel" />
</h:commandButton>
</h:form>
<h:panelGrid id="panel">
<h:panelGroup>
<h:form>
<h:commandButton value="Strange reconstructing occurs">
<f:ajax render=":panel" />
</h:commandButton>
</h:form>
<ui:repeat value="#{test.items}" var="i">
#{i}
</ui:repeat>
</h:panelGroup>
</h:panelGrid>
</h:body>
</html>
Firstly click on the first button.
I have a question concerning the p:messages component.
First, here is my configuration:
PrimeFaces: 4.0.3 (elite)
JSF: MyFaces 2.0.2
Server: WebSphere 8.5.0.2
Then, my code:
test.xhtml
<!DOCTYPE html>
<html 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">
<h:head>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</f:facet>
<meta http-equiv="cache-control" content="no-store,no-cache" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="expires" content="0" />
</h:head>
<h:body>
<div id="content">
<h:form id="form1">
<p:tooltip/>
<p:messages id="messages" showDetail="true" />
<p:remoteCommand async="true" autoRun="true" process="#this" partialSubmit="true" action="#{testBean.checkA}" />
<p:remoteCommand async="true" autoRun="true" process="#this" partialSubmit="true" action="#{testBean.checkB}" />
</h:form>
</div>
</h:body>
</html>
Test.java
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import org.primefaces.context.RequestContext;
#ManagedBean(name="testBean")
#ViewScoped
public class Test implements Serializable {
private static final long serialVersionUID = -1L;
public void checkA() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Message 1", null));
RequestContext.getCurrentInstance().update("form1:messages");
}
public void checkB() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,"Message 2", null));
RequestContext.getCurrentInstance().update("form1:messages");
}
}
What this code does is really simple. When the page loads, two AJAX calls are made (checkA and checkB). I have put a Thread.sleep(2000) in checkA for testing purpose as I want it to finish after checkB. Once a method is finished, it sends back a message to the UI.
When I load the page, I see both AJAX calls made. CheckB will be finished first, so I will see "Message 2" on my page. But as soon as checkA is finished, the message is replaced by "Message 1". What I would like to do is append "Message 1" to "Message 2", so the user will see both messages on the screen. Is there any way to do it or is it a limitation of the component?
Secondly, as you can see in my code, I have to call RequestContext.getCurrentInstance().update("form1:messages"); in order to see my p:messages being updated. If I remove this line of code and add autoUpdate="true" to the component, it doesn't work...
One thing to take into consideration, unfortunately, I cannot change the configuration of the server as I don't manage it and there are already dozens of other apps on it.
Thanks in advance for your help!
The problem you've here is that FacesMessages are Request Scoped. As you're performing two ajax requests, when you reach the end of the second one the first message is not available at that moment.
You're using a #ViewScoped bean which remains alive till you leave the view itself, so the workaround should be having there a kind of stack/queue which stores the messages to display. When you consider the last request have been done, just add all your messages to the FacesContext and clear the stack.
Other choice would be to perform all your operations in the same method and display the messages you want after that. You would decrease network traffic because of performing one request instead of two, but your choice seems interesting if you want to render specific parts of the page before other ones.
About your updating issue, remember you can specify the part of the form you want to update directly in the page. Try adding update="messages" to your p:remoteCommand tags. About autoUpdate not working, possibly your remoteCommand's partialSubmit attribute could be carrying you on problems. Check out the definition of that attribute from Primefaces docs:
partialSubmit: Enables serialization of values belonging to the partially
processed components only.
You can use multiple p:message components:
<p:message id="message1"
for="message1ValidatorCall" />
<h:inputHidden id="message1ValidatorCall" value="message1ValidatorCall">
<f:validator validatorId="myValidator" />
</h:inputHidden>
<p:message id="message2"
for="message2ValidatorCall" />
<h:inputHidden id="message2ValidatorCall" value="message2ValidatorCall">
<f:validator validatorId="mySecondValidator" />
</h:inputHidden>
You should consider faces validators if you want to check or validate sth:
#FacesValidator("myValidator")
public class MyValidator implements Validator {
#Override
public void validate(FacesContext facesContext, UIComponent uiComponent, Object o) throws ValidatorException {
//validator logic
}
}
The page is generated correctly with appropriate values in managed bean, but ajax events in these two h:selectOneMenus don't works. Listener is not called. An error has to be somewhere within tags, but I don't see it.
<f:view>
<h:form>
<h:messages />
<h:panelGrid columns="3">
<h:outputLabel value="Choose your faculty: *" for="faculties" />
<h:selectOneMenu id="faculties" value="#{registrateStudent.selectedFaculty}" >
<f:ajax event="change" listener="#{registrateStudent.genSpecializations}" execute="faculties" render="specializations" />
<f:selectItems value="#{registrateStudent.listFaculty}" var="curFac" itemLabel="#{curFac.name}" itemValue="#{curFac}" />
</h:selectOneMenu>
<h:message id="message_faculties" for="faculties" />
<h:outputLabel value="Choose your specialization: *" for="specializations" />
<h:selectOneMenu id="specializations" value="#{registrateStudent.selectedSpecialization}" >
<f:selectItems value="#{registrateStudent.listSpecialization}" var="curSpec" itemLabel="#{curSpec.name}" itemValue="#{curSpec}"/>
</h:selectOneMenu>
<h:message id="message_specializations" for="specializations" />
Managed Bean:
#ManagedBean(name = "registrateStudent")
#ViewScoped
public class RegistrateStudent {
private Faculty selectedFaculty;
private List<Faculty> listFaculty;
private Specialization selectedSpecialization;
private List<Specialization> listSpecialization;
private boolean showSpecialization = false;
/** Creates a new instance of RegistrateStudent */
public RegistrateStudent() {
users = new Users();
System.out.println("poaposd1");
student = new Student();
}
#PostConstruct
public void init() {
listFaculty = ff.findAll();
if (listFaculty != null) {
selectedFaculty = listFaculty.get(0);
listSpecialization = sf.findByFaculty(selectedFaculty.getIdFaculty());
if (listSpecialization != null) {
selectedSpecialization = listSpecialization.get(0);
}
else {}
} else {}
}
public void genSpecializations(AjaxBehaviorEvent event) {
if (sf.findByFaculty(selectedFaculty.getIdFaculty()) != null) {
this.showSpecialization = true;
} else {
JsfUtil.addSuccessMessage("faculties", "We don't have specializations for such faculty");
}
}
}
UPDATE:
I've found out a few interesting things:
<f:ajax> tag doesn't work at <h:link>, <h:selectOneMenu>, <h:button>, <h:commandButton>. In this cases incorrect values in render attribute is not noticed, but incorrect value of event attribute generate an error.
<h:outputLabel>, <h:inputText> work with <f:ajax> properly
The <f:ajax> requires jsf.js file being included in the HTML <head>. It contains all JS functions for doing the JSF ajax magic.
To achieve this, ensure that you're using <h:head> instead of <head> in the master template. JSF will then automatically include the necessary <script> element there pointing to jsf.js.
<!DOCTYPE html>
<html lang="en"
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">
<h:head>
<title>Look, with h:head</title>
</h:head>
<h:body>
Put your content here.
</h:body>
</html>
Note that in a bit decent webbrowser with a bit decent webdeveloper toolset like Firefox's Web Developer Toolbar and/or Firebug you should immediately have noticed JS errors like jsf is undefined when the ajax request is to be executed. That should at least have given something to think about.
Update: as per your update
I've found out a few interesting things:
<f:ajax> tag doesn't work at <h:link>, <h:selectOneMenu>, <h:button>, <h:commandButton>. In this cases incorrect values in render attribute is not noticed, but incorrect value of event attribute generate an error.
<h:outputLabel>, <h:inputText> work with <f:ajax> properly.
The <h:link> and <h:button> are intented for GET requests only, not POST requests. It should however work just fine on <h:selectOneMenu> and <h:commandButton>. Don't you have more code into the complete picture which you omitted from the question for simplicity? Which JSF impl/version are you using? Are you using the right libraries in classpath? It look like that you must really have messed up something.
To convince you (and myself) I just created the following copy'n'paste'n'runnable testcase
<!DOCTYPE html>
<html lang="en"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head>
<title>SO question 6089924</title>
</h:head>
<h:body>
<h:form>
<h:selectOneMenu value="#{bean.selected}">
<f:selectItem itemValue="#{null}" itemLabel="Select..." />
<f:selectItem itemValue="one" />
<f:selectItem itemValue="two" />
<f:selectItem itemValue="three" />
<f:ajax listener="#{bean.listener}" render="result" />
</h:selectOneMenu>
<h:commandButton value="commandButton" action="#{bean.submit}">
<f:ajax listener="#{bean.listener}" render="result" />
</h:commandButton>
<h:outputText id="result" value="#{bean.selected} #{bean.result}" />
<h:messages />
</h:form>
</h:body>
</html>
with this bean
package com.example;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.AjaxBehaviorEvent;
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private String selected;
private String result;
public void submit() {
System.out.println("submit");
}
public void listener(AjaxBehaviorEvent event) {
System.out.println("listener");
result = "called by " + event.getComponent().getClass().getName();
}
public String getSelected() {
return selected;
}
public void setSelected(String selected) {
this.selected = selected;
}
public String getResult() {
return result;
}
}
It runs fine with Mojarra 2.1.1 on Tomcat 7.0.12.
INFO: Starting Servlet Engine: Apache Tomcat/7.0.12
INFO: Initializing Mojarra 2.1.1 (FCS 20110408) for context '/playground'
Be careful if you have f:metadata and f:viewparam tags since the setters of the parameters will be called with every ajax request.
Can you provide the error log if there is any error/exception that is being generated when you call the ajax call?