I've got a form which has a domain model with some JSR-303 validation beans. Now I would like to include a "Save draft" feature without any validation. If I set immediate=true on my corresponding commandButton validation is skipped but also the form submit.
Is there a way to update the model in my save draft action?
Use <f:validateBean> where on you set the disabled attribute.
<h:inputText value="#{bean.input}">
<f:validateBean disabled="#{bean.draft}" />
</h:inputText>
If this evaluates true, this will skip all bean validation on the property associated with the input's value. You should only ensure that the boolean draft property is set before the validations phase takes place. E.g.
<h:commandButton value="Save draft" action="#{bean.saveDraft}">
<f:param name="draft" value="true" />
</h:commandButton>
with
#ManagedProperty("#{param.draft}")
private boolean draft;
or if it's a view scoped bean on which #ManagedProperty won't work:
public boolean isDraft() {
return "true".equals(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("draft"));
}
Another way is to check in EL if the button is pressed by determining the presence of its parameter name. For example, with the following form and button ID
<h:form id="form">
<h:inputText value="#{bean.input}">
<f:validateBean disabled="#{not empty param['form:draft']}" />
</h:inputText>
<h:commandButton id="draft" value="Save draft" action="#{bean.saveDraft}" />
</h:form>
Related
Using JSF 1.2 and Richfaces 3.3, I have this form:
<h:form>
<rich:tabPanel switchType="client" id="tabPnl">
<rich:tab label="MAIN_TAB">
<h:outputText value="#{msg.date}"/>
<rich:calendar value="#{MyBean.date}">
<f:validator validatorId="CalendarValidator" />
</rich:calendar>
<h:message for="DataInici" errorClass="error" />
<h:outputText value="#{msg.selector}"/>
<h:selectOneMenu id="select_val" value="#{MyBean.selectedItem}">
<f:selectItem itemLabel="#{msg.select_value}" itemValue="-1" />
<f:selectItems value="#{MyBean.listOfItems}" />
<f:validator validatorId="NumSelValidator" />
<a4j:support event="onchange" reRender="tabPnl" ajaxSingle="true" />
</h:selectOneMenu>
<h:message for="select_val" errorClass="error" />
</rich:tab>
<rich:tab label="SUBTAB1" id="subtab1" rendered="#{MyBean.selectedItem == 1}">
// form components such as inputText and/or SelectOneMenu.
</rich:tab>
<rich:tab label="SUBTAB2" id="subtab2" rendered="#{MyBean.selectedItem == 2}">
// Other form components such as inputText and/or SelectOneMenu.
</rich:tab>
</rich:tabPanel>
<h:commandButton value="#{msg.insert}" action="#{MyBean.insertData}">
</h:form>
At the begining, SUBTAB1 and SUBTAB2 are not rendered as the default value for MyBean.selectedItem is -1.
Firstly, the user picks a date in the <rich:calendar> component and, after that, it selects a value in the <h:selectOneMenu>. After that, the desired behaviour (what I want to achieve) is reRender the tabPanel without losing the data already introduced. Consequently, I expect the tabs SUBTAB1 or SUBTAB2 become rendered depending on what the value chosen in the <h:selectOneMenu>.
What I get: The tabPanel is reRendered, the appropiate SUBTAB is rendered but the data introduced in the first tab is lost.
How can I render these tabs without losing the data already introduced? I've tried to reRender the specific tabs, but it dosen't make them become rendered (I suppose it only affects to their content).
Thank you in advance.
Note: All beans involved are Session scoped.
Problem is that the inputs values are not processed on server.
Remove ajaxSingle="true" from a4j:support, so the whole form is processed when selectOneMenu value changes. You can use process attribute to limit the submitted area (in case you don't want to process the whole form).
ajaxSingle
Limits JSF tree processing (decoding, conversion, validation and model
updating) only to a component that sends the request. Boolean. Default
value is "false".
I am Using JSF 2 and EJB 3.1 to create a form.
I am using this part of the page to get me some data, so I can pass it to my bean using the confirmDialog just below
<p:column headerText="#{bundle.edit}" style="width:10px; overflow:visible;">
<p:rowEditor/>
</p:column>
<p:column headerText="#{bundle.delete}" style="width:10px; overflow:visible;">
<p:commandButton update=":form" oncomplete="confirmation.show()"
image="ui-icon ui-icon-close" title="Delete">
<f:param value="#{user}" name="userAction" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:confirmDialog message="Are you sure? user:#{param['userAction']} " width="500"
header="Confirm" severity="alert" widgetVar="confirmation">
<p:commandButton value="Yes sure" update=":form"
actionListener="#{userController.deleteAction(param['userAction'])}"
oncomplete="confirmation.hide()" />
<p:commandButton value="Not yet" onclick="confirmation.hide()" type="button" />
</p:confirmDialog>
</h:form>
And this is the Bean that should get it
#Named(value = "userController")
#Stateful
#RequestScoped
#TransactionManagement(TransactionManagementType.CONTAINER)
public class UserController implements Serializable {
private User current;
#Inject
private br.com.cflex.itm.dataaccess.UserFacade userFacade;
public UserController() {
}
public void deleteAction(User user) {
userFacade.remove(user);
}
But My bean is only receiving null as User, and in the Dialog I am printing the data so I can see there is a User Object selected there.
What is wrong in passing params like that ?
Why am I getting null in my Bean? Because they are getting lost in the communication between client and server-side...
<p:commandButton action="#{userController.deleteAction(param['userAction'])}" />
The EL of action (and actionListener) is evaluated when the form is been submitted, not when the form is been displayed. Request parameters are request scoped and are not there in the subsequent request of the form submit. You need to pass it along:
<p:commandButton action="#{userController.deleteAction(param['userAction'])}">
<f:param name="userAction" value="#{param['userAction']}" />
</p:commandButton>
The EL of <f:param> is evaluated when the form is been displayed. So it will be there in the generated HTML and JavaScript will take care that it is passed along.
Note that request parameters are of String type. Expecting them to be User won't work at all. Basically, it contains the value of User#toString(). You'd need to take String as action argument and convert it to User yourself. Or better, use <f:viewParam> wherein you can explicitly specify a converter.
I'm trying to use one <h:commandButton> with ajax to check some conditions, if it's OK the other <h:commandButton> with no ajax will be display. The one with ajax work well, but the other doesn't although I have specified a return String to another page. I cannot figure out why it failed, the syntaxes are all correct.
<h:form>
<label style="font-weight: bold">Room Code: </label>#{r.code}
<label style="font-weight: bold">Room Type: </label>#{r.roomType}
<label style="font-weight: bold">Price Per Day: </label>#{r.pricePerDay}
<br/>
<h:commandButton value="Check" action="#{bookingController.checkRoom}">
<f:param name="selectedRoomID" value="#{r.id}"/>
<f:ajax execute="#form" render="informer"/>
</h:commandButton>
<h:panelGroup id="informer">
<h:outputText value="#{bookingController.message}" rendered="#{bookingController.checked}"/>
<h:commandButton value="Book now!" action="#{bookingController.doBook}" rendered="#{bookingController.goodToBook}">
<f:param name="selectedRoomID" value="#{r.id}"/>
<f:param name="customerID" value="#{customerLoginController.customerUser.customer.id}"/>
</h:commandButton>
</h:panelGroup>
</h:form>
You've a rendered attribute on the second <h:commandButton>. If it evaluates false during processing of the form submit, then the button's action won't be invoked. This will happen if the bean is request scoped and you don't preserve the same condition for the rendered attribute during the form submit request as it was during displaying the form.
There are several ways to go around this. Since you're using JSF 2.0, best is to put the bean in the view scope instead.
#ManagedBean
#ViewScoped
public class BookingController {
// ...
}
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I'm currently learning about jsf 2.0 from core jsf 2.0 book + glassfish + cdi.
I have a question about the validation feature of JSF.
Let's say i have a very simple login application, which has a very simple layout like :
userid : (input field for userid - using required="true")
password : (input secret for password - using required="true")
loginButton + registerButton(using immediate="true") + checkUserIdAvailabilityButton
Now, let's say the loginButton is pressed, and the userid and password are left empty, validation error would occur on both of the fields, and that's working as what i intended.
And when the registerButton is pressed, it doesnt care whether the userid or password is filled by the user, since it's using immediate="true", thus bypassing validation and the command gets executed at the apply request value phase, and that's still working as what i intended.
And here comes my problem .. When the checkUserIdAvailabilityButton is pressed, i only expect the userid to be filled, and i dont need to care about whether the password field is filled or not, but the password field will throw error saying that it's a required field.
Is there anyway to resolve this kind of problem ? I know this could be a very simple application, but in my working place, i think they design lots of screens like this, like the save button along with refresh button with different required fields but the buttons are in the same page.
Thank you !
Set both the availability button and username field with immediate="true" and put the register button in a separate <h:form>.
E.g.
<h:form>
<h:inputText value="#{bean.username}" required="true" immediate="true" />
<h:inputSecret value="#{bean.password}" required="true" />
<h:commandButton value="Login" action="#{bean.login}" />
<h:commandButton value="Check name availability" action="#{bean.checkNameAvailability}" immediate="true" />
</h:form>
<h:form>
<h:commandButton value="Register" action="#{bean.register}" />
</h:form>
An alternative is to determine in the required attribute which button is been pressed (it's then present as request parameter).
<h:form id="form">
<h:inputText value="#{bean.username}" required="#{not empty param['form:login'] or not empty param['form:check']}" />
<h:inputSecret value="#{bean.password}" required="#{not empty param['form:login']}" />
<h:commandButton id="login" value="Login" action="#{bean.login}" />
<h:commandButton id="check" value="Check name availability" action="#{bean.checkNameAvailability}" />
<h:commandButton value="Register" action="#{bean.register}" />
</h:form>
A very simple JSF applicaton:
InputText element is assigned with Validator.
f:ajax is used to render next element (phoneNumber) by using blur event.
PhoneNumber will only be displayed if inputText pass the validator and isValid boolean value is set to true
Here is the code snippet
<h:form id="invOrdersWizForm">
<h:inputText id="name" maxlength="9" styleClass="ordLabelNarrow"
validator="#{person.validatePerson}"
value="#{person.name}">
<f:ajax render="phoneLabel" event="blur"/>
</h:inputText>
<h:outputText id="phoneLabel"
rendered="#{person.isValid}"
styleClass="ordLabelWide" value="#{person.phoneNumber}" />
</h:form>
ManagedBean
public void validatePerson(FacesContext context, UIComponent toValidate, Object value) {
name = ((String) value).toUpperCase();
phoneNumber = "12345678";
isValid = true;
}
The problem is, for some reason, the phoneNumber is not rendered at all.
The only way that I can make it work is by changing f:ajax to render #form
<h:inputText id="name" maxlength="9" styleClass="ordLabelNarrow"
validator="#{person.validateSecurityCode}"
value="#{person.name}">
<f:ajax render="#form" event="blur"/>
</h:inputText>
Or remove rendered from phoneNumber
rendered="#{person.isValid}"
For some reason f:ajax with specific element Id and rendered based on managedBean Attribute cannot co-exist.
Any idea or advice guys?
NOTE: this behaviour also happen when I use listener instead of validator
The f:ajax operates at the client side. The element which is specified in render must be already present in the client side HTML DOM tree. Put it in for example a h:panelGroup instead which is always rendered to the client side.
<h:panelGroup id="phoneLabel">
<h:outputText rendered="#{person.isValid}" value="#{person.phoneNumber}" />
</h:panelGroup>