I am writing an application with PrimeFaces 5, currently I am writing a screen with a couple of AutoComplete elements, with the idea that the value of one autocomplete influences the selections available in the second autocomplete.
The way I have tried to get this to work is that when the first autocomplete it filled in, an Ajax event is fired to update the backing bean with the value, so that when the second autocomplete is invoked, it had the value from the first autocompleted ready to switch on.
This is the page:
<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://xmlns.jcp.org/jsf/passthrough"
xmlns:pf="http://primefaces.org/ui">
<pf:panel id="header" header="Details" style="margin-bottom:20px">
<h:panelGrid columns="3" style="margin-bottom:10px;border-style:solid;border-width:0.1em;width:100%" cellpadding="5">
<pf:outputLabel id="input1Label" for="input1" value="Specify Input 1" />
<pf:autoComplete id="input1" value="#{bean.input1}" completeMethod="#{bean.completeInput1}"
var="input1" itemLabel="#{input1}" itemValue="#{input1}" >
<pf:ajax event="itemSelect" listener="#{bean.input1ItemSelect}"/>
</pf:autoComplete>
<pf:message id="input1Msg" for="input1"/>
<pf:outputLabel id="input2Label" for="input2" value="Input 2?" />
<pf:autoComplete id="input2" value="#{bean.input2}" completeMethod="#{bean.completeInput2}"
var="input2" itemLabel="#{input2}" itemValue="#{input2}" />
<pf:message id="input2Msg" for="input2"/>
</h:panelGrid>
</pf:panel>
</ui:composition>
However when a value is selected in input1, I get this error:
Unreachable, identifier 'bean' resolved to null: javax.el.PropertyNotFoundException: Target Unreachable, identifier 'bean' resolved to null
Now the next thing to point out is that this composition is included in a parent composition and "bean" is passed in as a parameter in the following fashion:
<c:forEach items="#{parentBean.blockNames}" var="blockName" varStatus="loop">
<f:subview id="block_subview_#{loop.index}">
<ui:include src="#{blockName}">
<ui:param name="bean" value="#{parentBean.blockBeans[loop.index]}"/>
</ui:include>
</f:subview>
</c:forEach>
What I've been able to establish is that if I change the reference "bean" in the pf:ajax tag to a named bean it is able to resolve the bean reference and attempts to invoke the listener method. So it seems like for some reason the pf:ajax tag is unable to cope with the "bean" reference because it is not the name of an actual bean but rather the name of a bean parameter passed in from the parent. However all the other tags are perfectly able to resolve "bean" here.
Is there a way round this?
Edit:
Changing the pf:ajax to a f:ajax seems to make the error go away, at least the correct listener method is then invoked. I'd rather not use this approach but maybe this information is useful.
You could try to put the content of the included page in a composite component and then use the composite component instead of the ui:include.
I worked at several complex JSF websites and never had any problems with the composite component technique while those ui:include always created some kind of problems in a loop.
Found out the cause, turns out the backing bean (or specifically, the backing bean of the parent page) was using #RequestScoped (or rather it was defaulting to this since no scope was specified), so presumably no longer existed by the time the user invoked the ajax call to it. Changing it to #ViewScoped fixed the problem.
Well,
this is probably happening because of the c:forEach tag. Try to use ui:repeat instead.
c:forEach is not a JSF tag, and it may cause confusion.
Related
I have a problem that validations from a composite's facet are being fired even when I do not render the composite.
I stripped the problem down to the following barebones code.
Here is the composite entityDetailPanel:
<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:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:common="http://java.sun.com/jsf/composite/common">
<composite:interface>
<composite:attribute name="prefix" required="true" />
<composite:facet name="lowerPanel"/>
</composite:interface>
<composite:implementation>
<h:form id="#{cc.attrs.prefix}entityDetailForm2"
styleClass="#{cc.attrs.prefix}EntityDetailPanelForm #{cc.attrs.prefix}Listener" >
<p:messages id="#{cc.attrs.prefix}messages" autoUpdate="true" closable="true"/>
<p:commandButton
value="SAVE"
update="#(.#{cc.attrs.prefix}Listener), #(.#{cc.attrs.prefix}EntityDetailPanelForm}"/>
<composite:renderFacet name="lowerPanel" rendered="false"/>
</h:form>
</composite:implementation>
</ui:composition>
And here is the invocation:
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:common="http://xmlns.jcp.org/jsf/composite/common">
<common:entityDetailPanel id="foo" prefix="Instruments">
<f:facet name="lowerPanel">
<!-- <p:inputText id="assetClassPrompt" required="true" requiredMessage="Why do we get this message?"/>-->
<p:selectOneMenu id="assetClassPrompt" required="true" requiredMessage="Why do we get this message?"
value="#{instrumentController.selectedData.assetClass}">
<f:selectItem itemLabel="foo" itemValue="foo"/>
<f:selectItem itemLabel="bar" itemValue="bar"/>
</p:selectOneMenu>
</f:facet>
</common:entityDetailPanel>
</ui:composition>
The combobox does NOT show on the screen (because it's not rendered), but why would I be getting a validation for something that's not rendered?
This is what I see when I click the SAVE button:
Stranger yet, is that I see THIS validation error even on other invocations of the composite that do NOT have that combobox.
I also noticed that if I do not include a unique ID on the <messages> tag, the message from one use of the composite will show up in other uses of the composite.
Is this a PrimeFaces or JSF bug, or am I missing something?
You might notice that I have a commented out <inputText> tag. It's worth mentioning that when I replace the <selectOneMenu> and replace it with the <inputText> I no longer see the problem.
I thought it might help to elucidate a bit on the larger problem I'm trying to solve.
I want to create something akin to a <p:layout> that has both fixed elements (for all uses of the composite) and non-fixed elements/panels which are passed in parametrically (for EACH use of the component).
Here is a screenshot where the items indicated in read are things that vary with each invocation of the composite. Everything else is always present in all invocations of the composite.
As you can see, the parameters are:
A button panel (buttons vary depending on context)
Some additional fields to add to the end of a form (which might contain validations
An entire lower panel (which might contain validations)
It's worth mentioning that all these things are validated together (for "SAVE" buttons), so it's desirable to have the <form> tag be within the composite output (which includes the panels passed in as parameters).
This problem is two-fold.
First, the <cc:renderFacet> is never designed to work this way. It does not support the rendered attribute. That it somehow works is because the facet is internally re-interpreted as an UIPanel component and all attributes are (incorrectly) automatically inherited from the tag. You should not rely on that. The rendered attribute is incorrectly considered during render response, causing confusing behavior that it "works". This is technically a bug in the JSF implementation. The attributes are (correctly) not inherited during the postback, causing the trouble you observed. The components are still decoded and validated "in spite of" that they are not rendered.
Second, the <p:inputText> extends from UIInput which checks before validation if there's any submitted value. A submitted value of null is interpreted as complete absence of the input field in the form, so it's skipped. A submitted value of an empty string is interpeted as an empty value, so it's validated. The <p:selectOneMenu>, however, has overriden the standard UIInput behavior and considers null the same way as an empty string. Even when the submitted value is null (which means that the input field wasn't in the form at all), it's still being validated. This is technically a bug in PrimeFaces side.
Your intent is at least clear: conditionally render a facet. The <cc:xxx> tags are evaluated during Facelets compile time (which is a step before view build time), so conditionally building the <cc:renderFacet> using JSTL <c:if> will also not ever work.
Your best bet is redefining "render lower panel" as a composite attribute, and create a backing component to explicitly copy this attribute into the facet after it's being added to the view.
<cc:interface componentType="entityDetailPanelComposite">
...
<cc:facet name="lowerPanel" />
<cc:attribute name="renderLowerPanel" type="java.lang.Boolean" default="false" />
</cc:interface>
<cc:implementation>
<f:event type="postAddToView" listener="#{cc.init}" />
...
<cc:renderFacet name="lowerPanel" />
...
</cc:implementation>
#FacesComponent("entityDetailPanelComposite")
public class EntityDetailPanelComposite extends UINamingContainer {
public void init() {
UIComponent lowerPanel = getFacets().get("lowerPanel");
ValueExpression renderLowerPanel = getValueExpression("renderLowerPanel");
if (renderLowerPanel != null) {
lowerPanel.setValueExpression("rendered", renderLowerPanel); // It's an EL expression.
} else {
lowerPanel.getAttributes().put("rendered", getAttributes().get("renderLowerPanel")); // It's a literal value, or the default value.
}
}
}
This has the additional benefit you can specify it from client on.
<my:entityDetailPanel ... renderLowerPanel="true" />
I am trying to DRY up popup windows in my JSF 2 project using composite components.
This code base uses Icefaces 3.3.0 (with their 1.8.2 compatibility layer for historical reasons), Mojarra 2.2.7, and Glassfish 4.1.
I have input.xhtml which provides a text input and uses a 2-button popup (ok/cancel), which in turn builds on the basic popup.
input.xhtml:
<composite:interface>
<!-- ... -->
<composite:editableValueHolder name="forInput" targets="theInput"/>
</composite:interface>
<composite:implementation>
<my:popup2Buttons>
<ice:inputText id="theInput" value="..."/>
<script>setInputFocus("#{cc.clientId}:theInput");</script>
</my:popup2Buttons>
</composite:implementation>
popup2buttons.xhtml:
<composite:interface>
<!-- ... -->
</composite:interface>
<composite:implementation>
<my:popup>
<composite:insertChildren/>
<ice:commandButton id="OkButton"
value="Ok"
actionListener="..."/>
<ice:commandButton id="CancelButton"
value="Cancel"
actionListener="..."/>
</my:popup>
</composite:implementation>
popup.xhtml:
<composite:interface>
<!-- ... -->
</composite:interface>
<composite:implementation>
<script>
function setInputFocus(id) {
document.getElementById(id).focus();
}
</script>
<ice:panelPopup>
<f:facet name="body">
<h:panelGroup>
<composite:insertChildren/>
</h:panelGroup>
</f:facet>
</ice:panelPopup>
</composite:implementation>
The popup works mostly as expected, i.e., I can enter something, the ok and cancel buttons work, and validation works as well.
What does not work is my JavaScript code that tries to focus the input when the popup opens.
When I look at the page in Firebug, I see that the input's ID is MyForm:j_idt63:j_idt64:j_idt67:theInput, but the JavaScript code tries to focus an element with the ID MyForm:j_idt63:theInput.
Why is #{cc.clientId} in input.xhtml not the correct ID that the input ends up getting later? What do I need to do to make this work?
I've seen BalusC's hint on adding a binding but I don't want a binding so that the composite component can be independent of any backing beans.
Is there something else I am missing here?
Composite components are implicitly naming containers. I.e. they prepend their ID to the client ID of the children. This makes it possible to use multiple of them in the same view without their children causing duplicate IDs in generated HTML output.
In your specific case, you wrapped the input field in another composite which is in turn wrapped in again another composite. If you're absolutely positive that you don't need multiple naming containers wrapping in each other in this specific composition, then those (popup2buttons.xhtml and popup.xhtml) probably shouldn't be composites, but rather <ui:decorate> templates or <ui:composition> tagfiles. See also When to use <ui:include>, tag files, composite components and/or custom components?
Coming back to the technical problem, it's caused because the #{cc.clientId} does not refer the ID of the nested composite component, but of the current composite component. And thus this would be off. As to the potential solution with binding, the answer which you found does nowhere tell that you should use a backing bean for this. The binding="#{foo}" code in the answer was as-is. It really works that way, without a bean property, see also JSF component binding without bean property. However, this construct would indeed fail when you include the same composite multiple times in the same view and thus multiple components share the same binding="#{foo}". It indeed isn't supposed to be shared by multiple components, see also What is component binding in JSF? When it is preferred to be used?
To solve this without a backing bean, you can use a so-called backing component.
com.example.InputComposite
#FacesComponent("inputComposite")
public class InputComposite extends UINamingContainer {
private UIInput input;
// +getter+setter.
}
input.xhtml
<cc:interface componentType="inputComposite">
...
</cc:interface>
<cc:implementation>
...
<h:inputText binding="#{cc.input}" ... />
<script>setInputFocus("#{cc.input.clientId}");</script>
...
</cc:implementation>
The alternative is to rework them into templates or tagfiles. Be careful that you don't overvalue/overuse composites.
I'm trying to use the setPropertyActionListener tag to set a value in my backing bean. However, it doesn't work as I expected.
Context: userService is an instance of my backing bean, which contains an int member, reqID. This, in turn, is the key to a map of objects that belong to a class called User. I'm trying to create a page that will list all instances of User, and provide a button to visit a separate view that shows that particular User's information. To do this, I'm attempting to set userService.reqID to the id of the chosen User so it can generate a reference to that user for the next view (which is done in the call userService.toUserInfo).
If I use the xhtml snippet below:
<ui:define name="content">
<h:form>
<h:panelGrid>
<ui:repeat value="#{userService.UserList.getUserList()}" var="user">
<li>
<h:outputText value="#{user.name}" />
<h:commandButton value="View details of #{user.name}" action="#{userService.toUserInfo}">
<f:param name="id" value="#{user.id}" />
<f:setPropertyActionListener target="#{userService.reqID}" value="#{id}"/>
</h:commandButton>
</li>
</ui:repeat>
</h:panelGrid>
</h:form>
</ui:define>
The tag does not appear to evaluate id correctly and I get a Null Pointer Exception.
Earlier, I tried changing my setPropertyActionListenerTag so it read out as:
<f:setPropertyActionListener target="#{userService.reqID}" value="id"/>
which gave me an error, because the tag was sending the string "id" as opposed to the int value of the parameter.
Is there some way to force f:setPropertyActionListener to evaluate the expression under value? Or is there another tag that will allow me to do this?
Also, is ui:param used appropriately here?
The <f:param> (and <ui:param>) doesn't work that way. The <f:param> is intented to add HTTP request parameters to outcome of <h:xxxLink> and <h:xxxButton> components, and to parameterize the message format in <h:outputFormat>. The <ui:param> is intented to pass Facelet context parameters to <ui:include>, <ui:decorate> and <ui:define>. Mojarra had the bug that it also behaves like <c:set> without a scope. This is not the intented usage.
Just use <c:set> without a scope if it's absolutely necessary to "alias" a (long) EL expression.
<c:set var="id" value="#{user.id}" />
Put it outside the <h:commandLink> though. Also in this construct, it's kind of weird. It doesn't make the code better. I'd just leave out it.
<f:setPropertyActionListener ... value="#{user.id}" />
See also:
Setting ui:param conditionally
what is the scope of <ui:param> in JSF?
Defining and reusing an EL variable in JSF page
Unrelated to the concrete problem, if you're using EL 2.2 (as you're using JSF 2.2, you undoubtedly are as it requires a minimum of Servlet 3.0, which goes hand in hand with EL 2.2), then just pass it as bean action method argument without <f:setPropertyActionListener> mess. See also a.o. Invoke direct methods or methods with arguments / variables / parameters in EL and How can I pass selected row to commandLink inside dataTable?
<h:commandButton ... action="#{userService.toUserInfo(user.id)}">
On again another unrelated note, such a "View user" or "Edit user" request is usually idempotent. You'd better use <h:link> (yes, with <f:param>) for this. See also a.o. Creating master-detail pages for entities, how to link them and which bean scope to choose and How to navigate in JSF? How to make URL reflect current page (and not previous one).
Oh, that <h:panelGrid> around the <ui:repeat><li> doesn't make sense in HTML perspective. Get rid of it and use <ul> instead. See also HTMLDog HTML Beginner tutorial.
I have the same problem as user1598186 has stated in his question here : p:commandButton doesn't call bean's method in an <ui:include> page
However, no solution has been given (he has removed <ui:include> tags altogether and used variables instead)
Are there any ways of using <ui:include> and still have my backing bean's method executed, when I'm calling it inside the commandButton.
Any help will be much appreciated.
EL 2.2 method parameters (so, #{bean.method()} instead of #{bean.method}) can be used to pass a method signature that can be used in the actionListener attribute of a commandButton. The following is an example of passing a ManagedBean property as well as passing a method signature:
Main Page
<ui:include src="/jointeam.xhtml">
<ui:param name="propertyValue" value="#{managedBean.property1} />
<ui:param name="method" value="#{managedBean.performAction()}" />
</ui:include>
jointeam.xhtml
...
<h:inputText value="#{propertyValue}" />
...
<p:commandButton value="Submit" actionListener="#{method}" />
You can see how powerful this is in terms of code reuse and for many instances is less verbose and easier to use than composite components.
I'm at the end of my rope with this one. I'm new to JSF so this is probably my misunderstanding of a lot of stuff.
<ui:composition>
<f:view>
<tr:form>
<ui:fragment rendered="#{param['type'] eq 'myType'}">
<ui:include src="/home/myPage.jspx" />
</ui:fragment>
......
I pass the page a certain type, it display's certain fields/criteria for a form and a bean backs it all because there is a single search.
Within myPage.jspx I have:
action="#{MyBean.submitForm}"
does not work, although a onsubmit="alert('hi');" does work as an attribute of the form element.
I guess what's most confusing is that
valueChangeListener="#{MyBean.stateChanged}"
does work on a field in the myPage.jspx
Why does the action (attribute of a button) not work?
During processing of the form submit, if the button or one of its parent components is not rendered, then the button's action won't be invoked. You need to make sure that the rendered attribute evaluates the same during processing of the form submit as it did when the form was displayed. In your case, you're depending on the value of a request parameter with the name type.
In this particular case, you could solve the problem by retaining the request parameter type by a <f:param> nested in the command button:
<h:commandButton ...>
<f:param name="type" value="#{param.type}" />
</h:commandButton>
Or, if you're using JSF 2.0, placing the bean in the view scope and setting the type parameter in the managed bean by <f:viewParam> can also solve it.
<f:metadata>
<f:viewParam name="type" value="#{bean.type}" />
</f:metadata>
...
<ui:fragment rendered="#{bean.type eq 'myType'}">
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated