Using Primefaces 5.0, JSF 2.2.7, deployed on EAP 6.1.
I have this Managed Bean below.
import hh.bean.Service;
import hh.dao.ServiceDao;
import hh.dao.impl.ServiceDaoImpl;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class View1 implements Serializable {
private static final long serialVersionUID = 1L;
private ServiceDao serviceDao = new ServiceDaoImpl();
#PostConstruct
public void init() {
System.out.println(View1.class.getName() + ": init() " + this);
}
public List<Service> getServices(){
return serviceDao.getAllServices();
}
}
I'm calling it from the xhtml below.
<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:p="http://primefaces.org/ui">
<h:head>
<title>Home Web</title>
<f:facet name="first">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
<meta name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
</f:facet>
</h:head>
<h:body>
<h:outputStylesheet library="css" name="newcss.css" />
<p:dataTable var="service" value="#{view1.services}">
<p:column style="width:16px">
<p:rowToggler />
</p:column>
<p:column headerText="Id">
<h:outputText value="#{service.id}" />
</p:column>
<p:column headerText="xxxx">
<h:outputText value="#{service.description}" />
</p:column>
<p:rowExpansion>
<p:dataTable var="sv" value="#{view1.services}">
<p:column headerText="Id">
<h:outputText value="#{sv.id}" />
</p:column>
</p:dataTable>
</p:rowExpansion>
</p:dataTable>
</h:body>
</html>
I noticed every time I expand the row my init() gets called. I thought #ViewScoped lives on when the request stays on the same page.
When I switch to #SessionScoped, init() does not get called when I expand a row.
Edit 1: Put the entire xhtml in, specify jsf version/impl
Edit 2: Fixed this issues by surrounding the p:dataTable with h:form. Not sure why that fixed it...
Fixed this issues by surrounding the p:dataTable with h:form. Not sure why that fixed it...
The JSF view state is maintained by javax.faces.ViewState hidden input field of the <h:form>. If you don't use a <h:form>, then PrimeFaces won't be able to find that hidden input field in order to pass its value along with the jQuery ajax request.
If this information is absent in the (ajax) request, then JSF will simply create a brand new view and inherently also all view scoped beans associated with it.
Related
I was building a very simple WebApp with Maven, to create a small REST Api (while using JSF).
In one of my beans (amongst other methods and variables) I created a very simple List just to test if I could get its options in JSF <p:selectItems>
Here's the bean code:
#ManagedBean(name="er", eager=true)
public class ExchangeRates {
private List<String> frase = new ArrayList<>();
public List<String> getFrase() {
frase.add("opcao1");
frase.add("opcao2");
return frase;
}
public void setFrase(List<String> frase) {
this.frase = frase;
}
/*some more code that doesn't use "frase"*/
And here's the (xhtml) JSF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Currency Conversion REST Api</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</h:head>
<h:body>
<h1>Currency Conversion</h1>
<h:form>
<h:outputLabel for="txtName">
<h:outputText value="Quantity: " />
</h:outputLabel>
<h:inputText id="txtNamea" value="#{er.quantity}" />
<br></br><br></br>
<h:outputLabel for="currency1" value="Convert from: "/>
<h:selectOneMenu id="currency1" value="#{er.currency1}" style="width:70px">
<f:selectItems value="#{er.frase}" />
</h:selectOneMenu>
</h:form>
</h:body>
</html>
The dropdown created by <f:selectItems> was supposed to give me the 2 options ("opcao1" and "opcao2"). However, when I click it it acts as if I didn't assign any variable or values to it, what could I be doing wrong?
I have a strange situation with a composite component. I'm using it all over my web application but now I noticed that if I update a form containing my composite component, the component get's rendered twice (at times).
My component (let's say it's called datecc) is defined as follows:
<?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:composite="http://java.sun.com/jsf/composite" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:body>
<composite:interface>
<composite:attribute name="value"/>
<composite:attribute name="shortFormat"/>
<composite:attribute name="style"/>
<composite:attribute name="styleClass"/>
<composite:attribute default="false" name="inputLabel"/>
</composite:interface>
<composite:implementation>
<span id="#{cc.clientId}">
<h:outputText rendered="#{not cc.attrs.inputLabel}" style="#{cc.attrs.style}" styleClass="#{cc.attrs.styleClass}" value="#{cc.attrs.value}">
<f:convertDateTime pattern="#{cc.attrs.shortFormat ? 'dd/MM/yy' : 'dd/MM/yyyy'}" timeZone="#{timezone}"/>
</h:outputText>
<span>asdasdfasdf</span>
<h:inputText disabled="true" rendered="#{cc.attrs.inputLabel}" style="#{cc.attrs.style}" styleClass="#{cc.attrs.styleClass}" value="#{cc.attrs.value}">
<f:convertDateTime pattern="#{cc.attrs.shortFormat ? 'dd/MM/yy' : 'dd/MM/yyyy'}" timeZone="#{timezone}"/>
</h:inputText>
</span>
</composite:implementation>
</h:body>
</html>
The page I'm calling it from is something similar to this:
<h:form id="form">
<p:dataTable id="rowsTable" value="#{myBean.rows}" var="it"
selectionMode="single" selection="#{myBean.selectedRow}" rowKey="#{it.key}"
rowStyleClass="#{myBean.isRed(it) ? 'red' : null}">
<p:ajax event="rowSelect" update=":menuForm :detailForm :contextualMenu"/>
<column>....</column>
<column><mycc:datecc value="#{it.date}" inputLabel="true" /></column>
</p:dataTable>
</h:form>
<h:form id="detailForm>
<!-- this field is rendered twice once I select a row in the above table -->
<mycc:datecc value="#{myBean.selectedRow.date}" inputLabel="true" />
</h:form>
I'm unfortunatelly doing some work on the setSelectedRow method in my bean #Named #ConversationScoped public class MyBean { ... } however I don't think that's causing the problem.
I solved my problem by implementing the following class.
package com.company.faces.cc;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
#FacesComponent("inputDate")
public class Date extends UIInput implements NamingContainer {
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
}
Although I don't really know why this solves the issue since it doesn't add much to the component.
Trying to use an ajax request to render a label without refreshing the entire page. So far every time I click the command button the whole page refreshes still and I can't seem to figure out what I am doing wrong.
Search By Title..
<h:commandButton class="addButton"
id="checkStatusButton"
value ="Check Status"
action = "#{itemWeb.findItem}">
<f:ajax execute="checkStatusForm"
event="click"
render="statusLabel"/>
</h:commandButton>
<h:outputText id="statusLabel"
value="#{itemWeb.foundItem.status}">
</h:outputText>
The page refresh because you do not use JSF Standard tags(h:head, h:body).
Thus, you should change the index.xhtml to below example.
<!--
Index.html setup
Holds the form for input data
-->
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<link href='http://fonts.googleapis.com/css?family=Roboto'
rel='stylesheet' type='text/css'></link>
<link href='resources/css/main.css'
rel='stylesheet' type='text/css'></link>
<title>
<ui:insert name="title"
Library Management System
</ui:insert>
</title>
<!--
Quick style setup..
-->
</h:head>
<h:body>
<h:form id="checkStatusForm">
<div class="group">
<h:inputText id="searchCheckInput"
value="#{itemWeb.searchString}">
</h:inputText>
<label>Search By Title..</label>
<span class="highlight"></span>
<span class="bar"></span>
</div>
<h:commandButton class="addButton"
id="checkStatusButton"
value ="Check Status"
action ="#{itemWeb.findItem}">
<f:ajax execute="checkStatusForm"
event="action"
render="statusLabel"/>
</h:commandButton>
<h:outputText id="statusLabel"
value ="#{itemWeb.foundItem.status}">
</h:outputText>
</h:form>
</h:body>
</html>
See also: Adding HTML Head and Body Tags
Try to process only the desired field rather than the whole form, in the execute attribute:
<h:commandButton class="addButton" id="checkStatusButton" value ="Check Status" action = "#{itemWeb.findItem}">
<f:ajax execute="searchCheckInput" event="click" render="statusLabel"/>
</h:commandButton>
You need to use event="action" instead of event="click". The event="action" is namely the default event the is listening on when nested in an h:commandButton component.
An example is shown below.
xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<f:view contentType="text/html">
<h:head>
<f:facet name="first">
<meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
<title>ajax-call</title>
</f:facet>
</h:head>
<h:body>
<h:form id="checkStatusForm">
<h:inputText id="searchCheckInput"
value="#{itemWeb.searchString}">
</h:inputText>
<label>Search By Title..</label>
<br/>
<h:commandButton class="addButton"
id="checkStatusButtonListener"
value ="Check Status (Listener)"
actionListener="#{itemWeb.findItemListener}">
<f:ajax execute="checkStatusForm"
event="action"
render="statusLabel"/>
</h:commandButton>
<h:commandButton class="addButton"
id="checkStatusButton"
value ="Check Status"
action="#{itemWeb.findItem}">
<f:ajax execute="checkStatusForm"
event="action"
render="statusLabel"/>
</h:commandButton>
<br/>
<h:outputText id="statusLabel"
value ="#{itemWeb.foundItem.status}">
</h:outputText>
</h:form>
</h:body>
</f:view>
</html>
managedbean
package com.wittakarn.view;
import com.wittakarn.model.Item;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
/**
*
* #author Wittakarn
*/
#ViewScoped
#ManagedBean(name = "itemWeb")
public class ItemWeb implements Serializable{
private String searchString;
private Item foundItem;
public ItemWeb(){
foundItem = new Item();
}
public String getSearchString() {
return searchString;
}
public void setSearchString(String searchString) {
this.searchString = searchString;
}
public Item getFoundItem() {
return foundItem;
}
public void setFoundItem(Item foundItem) {
this.foundItem = foundItem;
}
public void findItem(){
foundItem.setStatus("status A");
}
public void findItemListener(ActionEvent event){
foundItem.setStatus("status B");
}
}
domain
package com.wittakarn.model;
import java.io.Serializable;
/**
*
* #author Wittakarn
*/
public class Item implements Serializable{
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
The following simplificated Code is working when I set ajax="false". With ajax="true" the second commandButton don't calls personPM.commitEditPerson() when pushed after was updated by Button1 or Button2.
Can someone help me whats wrong here? Because it seems to be not easy to solve, I add the whole code that it can be easily reproduced (JSF 2.2, Primefaces is 3.5, GlassFish 4.0):
<?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:p="http://primefaces.org/ui">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form id="f1">
<p:commandButton id="Button1" update=":neuePerson" value="Neue Person" action="#{testPM.setCurrentPerson()}"/>
</h:form>
<h:panelGroup id="neuePerson">
<h:form id="f2" >
<p:commandButton id="Button2" update=":neuePerson" value="Übernehmen" action="#{testPM.commitEditPerson()}"/>
</h:form>
</h:panelGroup>
</h:body>
</html>
Session Scoped Bean TestPM.java:
package at.feimas.administration.presentation;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TestPM {
private String currentPerson;
private String firstName;
private static final Logger logger = Logger.getLogger(TestPM.class.getName());
public void setCurrentPerson() {
logger.log(Level.INFO, "New Person");
}
public void commitEditPerson(){
logger.log(Level.INFO, "Edit Person");
}
}
The problem is caused by a version mismatch PF 3.5 is not ready for JSF 2.2! I used PF snapshot 4.0 and it worked.
This code should show the whole problem and how to solve it with PF 3.5 and JSD 2.2, but I strongly suggest to use versions which work together!:
<h:body>
<h:form id="f1">
<p:commandButton id="Button1" update=":f2:buttonpanel2" value="New Person" actionListener="#{testPM.setFirstName}"/>
</h:form>
<h:panelGroup id="buttonpanel1">
<h:form id="f2">
<h:panelGroup id="buttonpanel2">
<h:outputText value="#{testPM.firstName}" id="firstName"/>
<p:commandButton id="Button2" update=":f2:buttonpanel2" value="Apply" actionListener="#{testPM.commitEditPerson}"/>
</h:panelGroup>
</h:form>
</h:panelGroup>
</h:body>
If the buttons use 'update=":buttonpanel1"' this leads to the behaviour I posted here in the question: As soon the update takes place, form f2 doesn't work anymore. If the buttons use 'update=":f2:buttonpanel2"' everything works as expected.
This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 7 years ago.
In JSF2, is it possible to change the of value of src of ui:include dynamically using Ajax request (like for example PrimeFaces p:commandButton)?
Thank you.
<h:form>
<h:commandLink value="Display 2" action="#{fTRNav.doNav()}">
<f:setPropertyActionListener target="#{fTRNav.pageName}" value="/disp2.xhtml" />
</h:commandLink>
</h:form>
<ui:include src="#{fTRNav.pageName}"></ui:include>
That's what I have right now. Is it possible to make it Ajax (using p:commandButton)?
The JSTL tags as proposed in the other answer are not necessary and it is not nicely reuseable.
Here's a basic example using pure JSF (assuming that you runs Servlet 3.0 / EL 2.2, otherwise you indeed need to use <f:setPropertyActionListener> like as in your question):
<h:form>
<f:ajax render=":include">
<h:commandLink value="page1" action="#{bean.setPage('page1')}" />
<h:commandLink value="page2" action="#{bean.setPage('page2')}" />
<h:commandLink value="page3" action="#{bean.setPage('page3')}" />
</f:ajax>
</h:form>
<h:panelGroup id="include">
<ui:include src="#{bean.page}.xhtml" />
</h:panelGroup>
with
private String page;
#PostConstruct
public void init() {
this.page = "page1"; // Ensure that default is been set.
}
// Getter + setter.
here is how I render subcontent dynamically using MnagedBean. First I set page in the center (that will be changed by menu triggers) with private String name="/main_pages/mainpage.xhtml", then each time submenu is clicked the HelloBean resets "name" and contents is updated by update=":content" - then new name is retrieved from Bean:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:facet name="first">
<meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
</f:facet>
</h:head>
<h:body>
<p:layout fullPage="true">
<p:layoutUnit position="north" size="150" resizable="true" closable="true" collapsible="true">
<h1>Madeline<br>shop</br></h1>
</p:layoutUnit>
<p:layoutUnit position="south" size="100" closable="true" collapsible="true">
Zapraszamy do odwiedzania naszego biura!
</p:layoutUnit>
<p:layoutUnit position="west" size="175" header="Menu" collapsible="true">
<h:form>
<p:menu>
<f:ajax render=":content">
<p:menuitem value="O naszej agencji" action="#{helloBean.setName('/main_pages/onas.xhtml')}" update=":content" />
<p:menuitem value="Ubezpieczenia pojazdów" action="#{helloBean.setName('/main_pages/ubpoj.xhtml')}" update=":content" />
<p:menuitem value="Ubezpieczenia majątkowe" action="#{helloBean.setName('/main_pages/ubmaj.xhtml')}" update=":content" />
<p:menuitem value="Ubezpieczenia na życie" action="#{helloBean.setName('/main_pages/ubnaz.xhtml')}" update=":content" />
<p:menuitem value="Zapytaj" action="#{helloBean.setName('/main_pages/zapytaj.xhtml')}" update=":content" />
<p:menuitem value="Kontakt" action="#{helloBean.setName('/main_pages/kontakt.xhtml')}" update=":content" />
</f:ajax>
</p:menu>
</h:form>
</p:layoutUnit>
<p:layoutUnit position="center">
<br></br><br></br>
<p:panel id="content">
<ui:include src="#{helloBean.name}" />
</p:panel>
</p:layoutUnit>
</p:layout>
</h:body>
</html>
my ManagedBean:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import java.io.Serializable;
/**
*
* #author root
*/
#ManagedBean
#RequestScoped
public class HelloBean implements Serializable {
/**
* Creates a new instance of HelloBean
*/
private static final long serialVersionUID = 1L;
private String name="/main_pages/mainpage.xhtml";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
You need to use the <c:if test="condition"> tag around the ui:include and then when the ajax button is clicked, the panel that holds the ui:include is refreshed.
Example:
First make sure that the jstl core taglib is included by inserting the following namespace in the document:
<html xmlns:c="http://java.sun.com/jsp/jstl/core>"
Then, you can use the <c:if> tag as follows :
<c:if test="#{!logBean.loggedIn}">
<ui:include src="loginpage.xhtml" />
</c:if>
<c:if test="#{logBean.loggedIn}">
<ui:include src="home.xhtml" />
</c:if>