Is there incompatibility between dynamic UI include and P:SelectOneMenu - jsf

I have a UI include that have a dynamic content , this content will be loaded when I press in a certain command link. the problem is when I press the command link the UI include is loaded without the Javascript created the PrimeFace:
could this problem be related to #Resource Dependency.
This my controller:
#Named
#ViewScoped
public class Test {
private String value;
private List<String> options=new ArrayList<>();
private String url="";
public String changeUrl(){
url="/snippets/test2.xhtml";
return "#";
}
#PostConstruct
public void init(){
options.add("test 1");
options.add("test 2");
options.add("test 3");
options.add("test 4");
}
//getter and setter
}
and this the xhtml page:
<h:form>
text
<ui:include src="#{test.url}" />
<p:commandLink action="#{test.changeUrl()}" value="submit" process="#this" update="#form"/>
</h:form>
And this the included Page:
<ui:composition>
<h:form>
<p:selectOneMenu value="#{test.value}">
<f:selectItems value="#{test.options}"/>
</p:selectOneMenu>
</h:form>
</ui:composition>

Two problems here: the ui:composition declaration in your included page is missing all of the required namespace declarations, and you are embedding a form within another form.
Your included page should look like this:
<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">
<p:selectOneMenu value="#{test.value}">
<f:selectItems value="#{test.options}"/>
</p:selectOneMenu>
</ui:composition>

Related

Primefaces 3.4.1 does not POST with a form inside a dialog

EDIT: the question does not have an answer with the linked resource, but I solved. I'll post the solution.
I'm working on a project that uses Primefaces 3.4.1 (and no, I can't update it).
I created a dialog with some inputs. The method is invoked, but the inputs are not populated in the bean. This does not happen in a "normal" form.
This is the simplified code:
browse.xhtml:
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
template="../layout/template.xhtml">
<ui:define name="body">
<p:dialog
id="dialog"
visible="#{bean.getDialogVisible()}"
modal="true"
>
<h:form id="form">
<p:inputText
id="x"
styleClass="Form-input"
value="#{bean.x}"
/>
<p:commandButton
value="submit"
action="#{bean.submit()}"
immediate="true"
></p:commandButton>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>
Bean.java:
#ManagedBean
#SessionScoped
public class Bean {
private String x;
private boolean isDialogVisible;
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
public boolean isDialogVisible() {
return isDialogVisible;
}
public void setDialogVisible(boolean isDialogVisible) {
this.isDialogVisible = isDialogVisible;
}
public boolean getDialogVisible() {
boolean res = this.isDialogVisible();
this.setDialogVisible(false);
return res;
}
public void submit() {
logger.info(this.x);
}
}
In loggind and during debugging, x is always null inside the method submit().
PS: note that the commandButton does not invoke submit() at all, if immediate="true" or ajax="false" are not specified.
I removed immediate="true" and added process="#form" to the p:commandButton and now it works.

p:selectManyMenu(with checkbox): Add item and select checkbox at the same time

xhtml code
<p:selectManyMenu id="menuid"
value="#{bean.selectedActivities}"
showCheckbox="true" scrollable="true" scrollHeight="150">
<f:selectItems value="#{bean.activities}" var="activity" itemValue="#{activity}"
itemLabel="#{activity}" />
</p:selectManyMenu>
<p:commandButton value="ADD ACTIVITY" id="addId">
<p:ajax event="click" process="#this" update="menuid" listener="#{bean.addActivity()}"/>
</p:commandButton>
Bean:
private List<String> selectedActivities = new ArrayList<>();
private List<String> activities = new ArrayList<>();
int index = 1;
public void addActivity(){
String activity = "Activity "+ (index ++);
activities.add(activity);
selectedActivities.add(activity);
}
This code is adding new item to the manyMenu but the checkbox is not selected.
Apart from some missing annotations I don't see much wrong. In any case, here is a tested solution based on your code that should work. First let's define the view. This is basically the same as in your example:
<?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" xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>SelectMany Example</title>
</h:head>
<h:body>
<h:form>
<p:selectManyMenu id="menuid"
value="#{selectManyBackingBean.selectedActivities}"
showCheckbox="true" scrollable="true" scrollHeight="150">
<f:selectItems value="#{selectManyBackingBean.activities}" var="activity" itemValue="#{activity}"
itemLabel="#{activity}" />
</p:selectManyMenu>
<p:commandButton value="ADD ACTIVITY" id="addId">
<p:ajax event="click" process="#form" update="menuid"
listener="#{selectManyBackingBean.onAddActivity}"/>
</p:commandButton>
</h:form>
</h:body>
</html>
Then, we define the backing bean:
#Data
#Named
#ViewScoped
public class SelectManyBackingBean implements Serializable {
private List<String> selectedActivities;
private List<String> activities;
private int index;
#PostConstruct
private void init() {
activities = new ArrayList<>();
selectedActivities = new ArrayList<>();
index = 0;
}
public void onAddActivity(){
String activity = "Activity " + (index++);
activities.add(activity);
selectedActivities.add(activity);
}
}
This should give you the expected behavior. Clicking three times on the ADD ACTIVITY button now yields the following result:
Notice the subtle change in the command button from process="#this" to process="#form". This will make sure that any changes you make in the component are also included in the form submission. If you keep it at the original value, any clicks on the check boxes in the menu will not be kept and will reset entries to the previous value when you press the command button (this is because the component in question is not included when the life cycle executes).

RequestContext won't work

I am having trouble to update the view from the bean in the back using PrimeFaces's RequestContext. In the example below I have a button and 2 panels. When pressing the button, I want to update one panel, but not the other one.
It does not work though and I can't find the error! requestContext.update("panela"); is fired, but doesn't do its job!
Help greatly appreciated!
The XHTML file:
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head/>
<h:body>
<h:form>
<p:panelGrid columns="1">
<p:commandButton value="Save" actionListener="#{runtimeUpdatesBean.save}" />
<p:panel id="panela">
<h:outputText value="#{runtimeUpdatesBean.texta}"/>
</p:panel>
<p:panel id="panelb">
<h:outputText value="#{runtimeUpdatesBean.textb}"/>
</p:panel>
</p:panelGrid>
</h:form>
</h:body>
</html>
The bean:
package com.glasses.primework;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.primefaces.context.RequestContext;
#ManagedBean
#SessionScoped
public class RuntimeUpdatesBean {
private String texta;
private String textb;
private boolean outcome;
public String getTexta() {
texta += "a";
System.out.println("RuntimeUpdatesBean.getTexta() = " + texta);
return texta;
}
public String getTextb() {
textb += "b";
System.out.println("RuntimeUpdatesBean.getTextb() = " + textb);
return textb;
}
public void save() {
RequestContext requestContext = RequestContext.getCurrentInstance();
if(outcome) {
System.out.println("RuntimeUpdatesBean.save() = update panela");
requestContext.update("panela");
outcome = false;
} else {
System.out.println("RuntimeUpdatesBean.save() = update panelb");
requestContext.update("panelb");
outcome = true;
}
}
}
Well the problem is the ID of the component that you are referring.
In JSF when you place a component inside h:form (or Some Primefaces components like TabView), that component's Id will be generated based on the h:form id too.
Here is the Example:
<h:form id="panelaForm">
<p:panel id="panela">
....
</p:panel>
</h:form>
In the above case your p:panel's id will be generated as panelaForm:panela.
In your case since you haven't provided any ID for h:form a dynamic id will be attached like for example j_xyz:panela(you can see it using you browser's Inspect Element).
So If you wan to access p:panel with Id panela inside the same h:form then no need to attach the form Id.
But If you want to access the p:panel outside h:form then you need to attach the h:form id to access it.
Solution to you problem is: use an custom ID to your h:form (which is a best practice by the way..) and access the p:panel by attaching that form ID.
<h:form id="panelaForm">
<p:panel id="panela">
....
</p:panel>
</h:form>
And in Managed bean use:
RequestContext.getCurrentInstance().update("panelaForm:panela");
I'm the new guy here (Java EE) however below solution works for me:
<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head/>
<h:body>
<h:form id="form">
<p:panelGrid columns="1">
<p:commandButton value="Save" actionListener="#{runtimeUpdatesBean.save}" update=":form" />
<p:panel id="panela">
<h:outputText value="#{runtimeUpdatesBean.texta}"/>
</p:panel>
<p:panel id="panelb">
<h:outputText value="#{runtimeUpdatesBean.textb}"/>
</p:panel>
</p:panelGrid>
</h:form>
</h:body>

how to add a component to the page from a managed bean in jsf / primefaces [duplicate]

This question already has answers here:
How to dynamically add JSF components
(3 answers)
Closed 6 years ago.
A click on a commandButton should trigger an action in a ManagedBean: to add a new "outputText" component to the current page.
The overall idea is to have the page changed dynamically with user action, with server side action because new elements added to the page need data from a db to be laid out.
-> How do I add a component to the page from a managed bean in jsf / primefaces? Let's say that the elements should be added in an existing div like:
<div id="placeHolder">
</div>
(this div could be changed to a jsf panel if needs be)
Note: if alternative methods are better to achieve the same effect I'd be glad to learn about them.
I'll provide you another solution apart from the one you posted. Basically it has a List of given outputs, which is increased everytime the button is pushed. That should render exactly the same DOM tree as the solution you stated:
<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:head>
<title>Tiles</title>
<h:outputStylesheet name="css/320andup_cle.css" />
</h:head>
<h:body>
<h:form>
<h:commandButton actionListener="#{bean.createNewTile}" title="new"
value="new" />
</h:form>
<h:panelGroup layout="block" id="tiles">
<ui:repeat var="str" value="#{bean.strings}">
<h:panelGroup>
<h:outputText styleClass="tile" value="#{str}" />
</h:panelGroup>
</ui:repeat>
</h:panelGroup>
</h:body>
</html>
#ManagedBean
#SessionScoped
public class Bean {
List<String> strings = new ArrayList<String>();
public List<String> getStrings() {
return strings;
}
public void createNewTile() {
strings.add("output");
}
}
Apart from being much simpler IMHO, it has a main advantage: it doesn't couple your server side code to JSF implicit API. You can change the #ManagedBean annotation for #Named if you want it to be a CDI managed bean.
The solution:
This is a jsf page with a button creating a new div each time it is clicked:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Tiles</title>
<h:outputStylesheet name="css/320andup_cle.css" />
</h:head>
<h:body>
<h:form>
<h:commandButton actionListener="#{bean.createNewTile()}" title="new" value="new"/>
</h:form>
<h:panelGroup layout="block" id="tiles">
</h:panelGroup>
</h:body>
</html>
The Managed Bean:
#Named
#SessionScoped
public class Bean implements Serializable {
private UIComponent found;
public void createNewTile() {
HtmlPanelGroup div = new HtmlPanelGroup();
div.setLayout("block");
HtmlOutputText tile = new HtmlOutputText();
tile.setValue("heeeeeRRRRRRRRRRRRRR ");
tile.setStyleClass("tile");
div.getChildren().add(tile);
doFind(FacesContext.getCurrentInstance(), "tiles");
found.getChildren().add(div);
}
private void doFind(FacesContext context, String clientId) {
FacesContext.getCurrentInstance().getViewRoot().invokeOnComponent(context, clientId, new ContextCallback() {
#Override
public void invokeContextCallback(FacesContext context,
UIComponent component) {
found = component;
}
});
}
}
See this app built with this logic of dynamically generated components: https://github.com/seinecle/Tiles

How to add a message to a specific component from JSF backing bean

I have an h:inputText and an h:message connected to it:
<h:inputText id="myText" value="#{myController.myText}" />
<a4j:outputPanel>
<h:message for="myText" .../>
</a4j:outputPanel>
I want to send a message to it from java, in a manner like:
FacesContext.getCurrentInstance().addMessage(arg0, arg1);
which is sent to h:messages, but to a specific id in a specific form.
How can I do this? (Without implementing validation bean or validation method - meaning without throwing validation exception).
You need to provide the so called client id, which you'll find on UIComponent.
The following is a quick example of how to use this.
Consider the following bean:
#ManagedBean
#RequestScoped
public class ComponentMsgBean {
private UIComponent component;
public UIComponent getComponent() {
return component;
}
public void setComponent(UIComponent component) {
this.component = component;
}
public String doAction() {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(component.getClientId(), new FacesMessage("Test msg"));
return "";
}
}
being used on the following Facelet:
<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:body>
<h:form>
<h:outputText id="test" value="test component" binding="#{componentMsgBean.component}"/>
<h:message for="test"/>
<h:commandButton value="click me" action="#{componentMsgBean.doAction}" />
</h:form>
</h:body>
</html>
This will add a Faces message with content "Test msg" for the outputText component used in the example.
Another way to do that is: give an ID to the form, like "form1", then, when add the message, the clientId is "form1:test".

Resources