JSF2 <ui:param give wrong value when used in <h:panelGroup - jsf-2

I have 2 <h:panelGroup for conditional text display. When I run with id empty than this condition is executed fine #{empty personBean.person.id} and I see text in it. If I put <h2>#{buttonText}</h2> in panels than I see buttonText properly displayed in h2 tag.
Now Problem:
In below code if I put <h2>#{buttonText}</h2> at the end like below than I always get value Update member due to this I can not use value of buttonText anywhere in the page below. Someone tell me what to do?
<h:panelGroup rendered="#{empty personBean.person.id}">
<h1>Add Information</h1>
<i>Use the form below to add your information.</i>
<ui:param name="buttonText" value="Add member" />
</h:panelGroup>
<h:panelGroup rendered="#{not empty personBean.person.id}">
<h1>Update Information</h1>
<i>Use the form below to edit your information.</i>
<ui:param name="buttonText" value="Update member" />
</h:panelGroup>
<h2>#{buttonText}</h2>
I am unable to use <ui:param like I use <c:set var="buttonText" value="Add member" /> JSTL set variable.

The <ui:param> is not evaluated during view render time (ask yourself; does it necessarily generate any HTML?), but during view build time. So the rendered attribute isn't been taken into account at all and you effectively end up with both being interpreted and the latter one would always override the former one.
Technically, you'd need to "render" ("build" is a better term, but it reads a bit strange) it conditionally using a view build time tag such as <c:if>. However, in your particular construct it's better is to just check the very same condition in <ui:param>'s value and have only one of it instead of two:
<ui:param name="buttonText" value="#{empty personBean.person.id ? 'Add' : 'Update'} member" />
or just evaluate it directly there where you need it
<h2>#{empty personBean.person.id ? 'Add' : 'Update'} member</h2>
See also:
JSTL in JSF2 Facelets... makes sense? - not exactly your issue, but just to understand "view build time" versus "view render time" better.

Related

<ui:repeat> inside <ui:repeat> displaying data more number of times

0 and i need to render some buttons based on condition, i'm getting the condition true but each time i visit the page the button its displaying with additionl buttons,here's my code
<ui:repeat var="r" value="#{sessionScope['restrictpageload']}" varStatus="status">
<ui:repeat var="permission" value="#{restrictPageLoad.isUserHasFeaturePermission(4,'abc')}" varStatus="status2">
<ui:fragment rendered="#{permission.featureCreate eq 'y'}" >
<h:commandButton value="Button1" action="#{bean.method()}"/>
</ui:fragment>
</ui:repeat>
</ui:repeat>
here my first <ui:repeat> gets the values from session and i'll pass as parameter to second and this will return me arraylist and i'm going to render the button based on condition.
I'm getting the values inside but each time i visit page two more button addsup.Please help.
too long for a comment...
3 points:
outer loop declares r and status which are not used in inner loop, so "here my first <ui:repeat> gets the values from session and i'll pass as parameter to second" is false
value="#{sessionScope['restrictpageload']}" is equivalent to value="#{restrictpageload}"
value="#{sessionScope['restrictpageload']}" maybe there's a typo. you mean value="#{sessionScope['restrictPageload']}" (uppercase P)
maybe you want to do something like this:
<ui:repeat var="restriction" value="#{bean.pageRestrictions}">
<ui:repeat var="permission" value="#{bean.userPermissions}">
<ui:fragment rendered="#{restriction == permission}">
<h:commandButton value="Button1" action="#{bean.method}"/>
</ui:fragment>
</ui:repeat>
</ui:repeat>
or better
<ui:repeat var="restriction" value="#{bean.pageRestrictions}">
<ui:fragment rendered="#{bean.userHasFeaturePermission(restriction)}">
<h:commandButton value="Button1" action="#{bean.method}"/>
</ui:fragment>
</ui:repeat>
however if your buttons are duplicating, you are adding something to your loops, maybe in isUserHasFeaturePermission?
UPDATE (comment reply)
read carefully the accepted answer of your linked question:
Your question is meaningless. There is no "passing parameters by " and there is no "passing parameters using ". Your words might make sense in some specific context - but the context is missing.
not related but worth mention, NEVER use c:forEach in JSF pages, unless you know exactly how JSF lifecycle works.
passing parameters in expressions depends on EL (ExpressionLanguage) library version.
you can pass parameters only if you have EL 2.2+. this library is shipped (normally) with the servlet container.
read this answer and linked for a complete explanation.
what's your servlet container? tomcat 6.0, glassfish 3.1?
however, does it throws an Exception?

security in Jsf2 guessing and modifying url should not be allowed

I have an application up and running. I have a page addstudent.xhtml page where the user adds the student details.When user finishes adding and submits he will be redirected displaystudent.xhtml page.
My question is when user directly types on browser
localHost:8081/Student/displaystudent.xhtml. Page is displayed with blank values.This should not happen. How do I prevent this even though he types on browser.
Both the files addstudent.xhtml displaystudent.xhtml pages are in web-inf folder. I am using Jsf2, primefaces 3.5
Make displaystudent.xhtml an include file which you render conditionally in addstudent.xhtml depending on whether the student is successfully added.
E.g., assuming standard JSF:
<h:panelGroup id="addStudent" layout="block">
<h:form rendered="#{empty bean.student.id}">
<h2>Add student</h2>
<h:inputText value="#{bean.student.name}" />
...
<h:commandButton value="Add" action="#{bean.add}">
<f:ajax execute="#form" render=":addStudent" />
</h:commandButton>
</h:form>
<h:panelGroup layout="block" rendered="#{not empty bean.student.id}">
<h2>Added student</h2>
<dl>
<dt>Student name</dt><dd>#{bean.student.name}</dd>
</dl>
</h:panelGroup>
</h:panelGroup>
(simplified; you could of course split off the add student to <ui:include src="/WEB-INF/displaystudent.xhtml"> and so on)
The button, whereby the add() method should return void or null, re-renders the <h:panelGroup id="addStudent">. If the student was successfully been added in the DB, then it should have a non-empty ID. This will cause the form to be hidden and the results panel to be shown.
See also:
Conditionally displaying JSF components
How to navigate in JSF? How to make URL reflect current page (and not previous one)

JSF2 Dynamic form is not being submitted

I have a form that is defined in a separate jsf page. This is is included to the main page when i click a link. Now the form is being displayed correctly. But the problem is that the submit button is not calling the action function defined.
The code to include the page( As suggested in this question: JSF2 Dynamically loading pages by ajax
<h:panelGroup id="editdivparent" layout="block">
<h:panelGroup id="editdiv" rendered="#{formsBean.edituserdiv}" layout="block">
<h:form id="userform" class="form-horizontal">
<ui:include src="edituserdetails.xhtml">
</ui:include>
</h:form>
</h:panelGroup>
</h:panelGroup>
The included page contains just the form elements with submit button:
<h:commandButton action="#{userBean.register() }" value="Update">
</h:commandButton>
I am getting no errors. On submitting the form the current page is redisplayed. I have put some print statements in the action function. Also there is a query error is put. None of them are being generated.
Am i doing something wrong here?
The commandButton action property already expects a method expression, so just take the parenthesis out, like this:
<h:commandButton action="#{userBean.register}" value="Update" />
Also, make sure you don't have nested forms when making templates with includes.
I hope it helps.

JSF not firing bean setters when using f:ajax

This is an update on a previous post I made regarding conditional rendering of page components. I can now conditionally render different components on the page based on selected user inputs using the f:ajax tag. The trouble is that when I click my commandbutton the inputs that are conditionally rendered using ajax aren't being read on submit. I am guessing it is because the whole page isn't rerendered when I add in the new components and the submit button can't see them, even though they are there. Here is the segment of my form page(it is wrapped in a h:form tag):
<h:outputLabel for="selectPersonType" value="Select Type: "/>
<h:selectOneMenu id="selectPersonType" value="#{addPersonBean.personType}" label="Person Type" required="true">
<f:selectItem itemValue=""/>
<f:selectItems value="#{listBean.personTypes}" />
<f:ajax render="results"/>
</h:selectOneMenu>
<h:message for="selectPersonType" style="color: red"/>
</h:panelGrid>
<h:panelGroup id="results">
<h:panelGroup rendered="#{addPersonBean.personType == 'STUDENT'}">
<h:outputLabel for="selectSchoolType" value="School Type: " />
<h:selectOneMenu id="selectSchoolType" value="#{addPersonBean.schoolType}">
<f:selectItems value="#{listBean.schoolTypes}" />
<f:ajax execute="selectSchoolType"/>
</h:selectOneMenu>
</h:panelGroup>
<h:panelGroup rendered="#{addPersonBean.personType == 'PATIENT'}">
<h:outputLabel for="smoker" value="Smoker? " />
<h:selectBooleanCheckbox id="smoker" value="#{addPersonBean.smoker}">
<f:ajax execute="smoker"/>
</h:selectBooleanCheckbox>
</h:panelGroup>
</h:panelGroup>
<h:commandButton value="Add Person" action="#{addPersonBean.action}"/>
The trouble here is that the components with ids 'selectSchoolType' and 'smoker's values don't get set when I click the commandButton because they are rendered conditionally using the selectPersonType select menu after the page has loaded. Is there a way to fire the components when their values change instead of when I click the submit button (therefore, their values should be processed before I even click submit). As you can see I have tried to use f:ajax with the execute attribute attached to the components in question but it didn't seem to work. (I believe the default events for these components are valueChange so haven't added them to the f:ajax tags, but I have tried 'change' and 'valueChange').
All your <f:ajax> things are inside a conditionally rendered component. This construct will fail when the condition behind rendered attribute evaluates to false during processing the form submit. This will happen when the #{addPersonBean} is in the request scope and doesn't preinitialize the condition behind the rendered attribute during (post)construction, or when it's performing business logic in getters/setters in a wrong way.
Placing the #{addPersonBean} in the view scope and ensuring that you aren't doing business logic in getters/setters should fix this problem.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5 applies to you
How to choose the right bean scope?

How can I set numbers within IDs dynamically in JSF

I design a JavaEE website with the help of JSF2 and Facelets. The code beyond is just an example how the JSF-Code looks like.
When the user of the website wants to create new users but forgets to set e.g. the firstname, an error occurs and the element will be highlighted (red color and red frame around the element).
For highlighting I have to use the attribute:
class="#{faceletUtils.getLabelStyleClass('createUsersForm:allUsers:0:firstName')}"
The problem is that I have to set the number 0 dynamically but as far as I know nesting is not allowed in JSF. I could use #{curUser.number} to get the number.
Question: How can I set the numbers in the for and class attributes?
for="createUsersForm:allUsers:0:firstName"
class="#{faceletUtils.getLabelStyleClass('createUsersForm:allUsers:0:firstName')}"
An example of the JSF-Code:
<h:form id="createUsersForm">
<ui:repeat id="allUsers" value="#{createUserController.users}" var="curUser">
<div class="formLine">
<label for="createUsersForm:allUsers:0:firstName" class="#{faceletUtils.getLabelStyleClass('createUsersForm:allUsers:0:firstName')}">
<h:outputText value="#{userStaticText['user.firstName.label']}"/>
</label>
<h:inputText id="firstName" value="#{curUser.firstName}" class="#{faceletUtils.getLabelStyleClass('createUsersForm:allUsers:0:firstName')}"/>
</div>
</ui:repeat>
</h:form>
Best regards,
Jana
Just use <h:outputLabel> instead of <label>. JSF will automatically use the right for value. Further you can use #{component.clientId} to get the client ID of the current component (although I think the particular functional requirement of highlighting invalid fields can be solved in a much simpler manner).
<h:form id="createUsersForm">
<ui:repeat id="allUsers" value="#{createUserController.users}" var="curUser">
<div class="formLine">
<h:outputLabel for="firstName" styleClass="#{faceletUtils.getLabelStyleClass(component.clientId)}"
value="#{userStaticText['user.firstName.label']}"/>
<h:inputText id="firstName" value="#{curUser.firstName}" styleClass="#{faceletUtils.getLabelStyleClass(component.clientId)}"/>
</div>
</ui:repeat>
</h:form>
Note that I fixed the wrong class attribute of <h:inputText> as well.

Resources