In my JSF 2.2 application on Glassfish 4.0, i need to allow update of single fields within a page.
For each field, i created a h:form containing two ui:fragments.
Each of there fragments is rendered based on the value of a boolean edit attribute named enteEdit in my backing bean FascicoloDettaglio.
FascicoloDettaglio is #ViewScoped.
The first fragment contains an h:outputText with the value from my bean, and a h:commandLink used to update the edit attribute and fire an AJAX request to re-render the form, which causes the first fragment to disappear and the second fragment to appear.
The second fragment contains the h:inputText used to edit the field, and the submit h:commandButton, which resets the edit attribute and then AJAX-calls the action method.
However, the second button never works; the action is not called and the button simply does nothing; while it should call the action and then re-render the entire form, turning the second fragment off and the first on.
I can't understand why it doesn't work.
This is the JSF code fragment:
<h:form>
<ui:fragment rendered="#{not fascicoloDettaglio.enteEdit}">
<h:outputText value="#{fascicoloDettaglio.fascicolo.ente}" />
<h:commandLink rendered="#{request.isUserInRole('affgen')}">
<h:graphicImage name="img/modify.png" width="24" height="24" title="Modifica" />
<f:ajax render="#form" />
<f:setPropertyActionListener target="#{fascicoloDettaglio.enteEdit}" value="true" />
<f:setPropertyActionListener target="#{fascicoloDettaglio.ente}" value="#{fascicoloDettaglio.fascicolo.ente}" />
</h:commandLink>
</ui:fragment>
<ui:fragment rendered="#{fascicoloDettaglio.enteEdit}">
<h:inputText value="#{fascicoloDettaglio.ente}" requiredMessage="Introdurre l'ente ricorrente." required="true" styleClass="largetext #{component.valid ? '' : 'inputvalidationerror'}">
<f:validateLength maximum="255" />
</h:inputText>
<h:commandButton action="#{fascicoloDettaglio.salvaEnte}" value="Salva">
<f:setPropertyActionListener target="#{fascicoloDettaglio.enteEdit}" value="false" />
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:messages />
</ui:fragment>
</h:form>
Any help would be very appreciated.
Related
I'm new to jsf, and I'm writing my first application using richfaces. I'm having trouble with the ajax tag that I use to update the associated managed bean property on server for rich:calendar components. This is the code:
<rich:panel header="Computing Options">
<h4>Time Interval</h4>
<h:panelGrid columns="4" width="100%">
<h:outputText value="From" />
<rich:calendar id="intervalFrom" value="#{scenarioEditor.intervalFrom}" popup="true" showApplyButton="true" datePattern="yyy-MM-ddTHH:mm">
<a4j:ajax execute="#this" event="change" render="outFrom" />
</rich:calendar>
<h:outputText value="To" />
<rich:calendar id="intervalTo" value="#{scenarioEditor.intervalTo}" popup="true" showApplyButton="true" datePattern="yyy-MM-ddTHH:mm">
<a4j:ajax execute="#this" event="change" render="outTo" />
</rich:calendar>
<h:outputText id="outFrom" value="From: #{scenarioEditor.intervalFrom}" />
<h:outputText id="outTo" value="To: #{scenarioEditor.intervalTo}" />
</h:panelGrid>
<h4>Algorithms</h4>
<h:panelGrid columns="2">
<h:selectBooleanCheckbox value="#{scenarioEditor.visibilityClashes}" id="clash" >
<f:ajax execute="#this"/>
</h:selectBooleanCheckbox>
<h:outputLabel value="Visibility Clashes Evaluator" for="clash" style="width:170px" />
<h:selectBooleanCheckbox value="#{scenarioEditor.xBandInterference}" id="xband" >
<f:ajax execute="#this"/>
</h:selectBooleanCheckbox>
<h:outputLabel value="X-Band Interferences Evaluator" for="xband" style="width:170px"/>
</h:panelGrid>
</rich:panel>
checkboxes works fine, but the calendars do not. Why? I`ve tried both f:ajax and a4j:ajax without luck.
To better clarify, I want that right after the user has finished entering a value into the calendar, an ajax request is made that call the setter method for the associated property. And this, for the calendar does not happen while for the checkboxes, it does.
The ajax event is failing because of T in datePattern="yyy-MM-ddTHH:mm" is not a valid date formatting pattern. If you add a <rich:messages/> component to your field, you'll see that a conversion error is occurring on each ajax request. Remove the T and you'll be fine
I'm trying to create a page where some content will be displayed after ajax request. Here is part of my code:
<h:panelGroup>
<h:form>
Retrive object by id: <h:inputText id="myInput" value="#{myManager.id}"/>
<h:commandButton value="ok" action="#{myManager.getById}" >
<f:ajax execute="myInput" render="resultRow" />
</h:commandButton>
<h:panelGroup id="resultRow" >
<br />
You retrived object which id is:
<h:outputText value="#{retrivedObject.id}" />
and its name is:
<h:outputText value="#{retrivedObject.name}" />
</h:panelGroup>
</h:form>
</h:panelGroup>
My problem is taht the "You retrived object which id is: " is rendered even before I retrive any object. I want it to be hidden until I click my command button. Is it possible to do only with jsf + html (this have to be done with ajax)? I could use some javascript if I will have to, but I prefer not.
I tried to solve this by rendered="#{!retrivedObject.id==0}" (my object can't have id 0), but this doesn't work - panel group isn't rendered at all and when I call ajax reqest it is unable to find "resultRow" id.
Thanks for help in advance.
It may not be exactly what you are looking for but you can always wrap the panelGroup in a div and set the div visibility to hidden, then use javascript to change the visibility when you click the command button.
You can use the rendered attribute like this :
<h:panelGroup>
<h:form>
Retrive object by id: <h:inputText id="myInput" value="#{myManager.id}"/>
<h:commandButton value="ok" action="#{myManager.getById}" >
<f:ajax execute="myInput" render="resultRow" />
</h:commandButton>
<h:panelGroup id="resultRow">
<h:panelGroup rendered="#{retrivedObject ne null}">
<br />
You retrived object which id is:
<h:outputText value="#{retrivedObject.id}" />
and its name is:
<h:outputText value="#{retrivedObject.name}" />
</h:panelGroup>
</h:panelGroup>
</h:form>
</h:panelGroup>
I have a jsf page with
<h:inputText required="true"> attribute.
When I click on my add button, I want to see an error if the field is blank.
I have a <f:message> to display this.
But how can I escape (cancel) the page with that field blank? In my case it continually posts the error message and I have to enter something in the field to go to another page.
If your cancel button is a POST requests e.g. <p:commandButton>,<h:commandButton>, <p:commandLink>, or <h:commandLink>
You can put your cancel button outside the form that has the <h:inputText> so that form is not submitted
<h:form>
<h:inputText value="#{bean.string}" required="true"/>
</h:form>
<h:form>
<p:commandButton value="Cancel" action="anotherpage.xhtml"/>
</h:form>
If you are navigating without any actions or method invocation, then you can use GET requests e.g. <h:button>, <p:button>, <h:link> or <h:outputLink>.
Example:
<h:form>
<h:inputText value="#{bean.string}" required="true"/>
<p:button value="Cancel" outcome="anotherpage.xhtml"/>
</h:form>
You can use immediate="true" in your <p:commandButton>. Then it will skip the validation.
For example:
<p:commandButton action="#{managedBean.action}" value="Cancel" immediate="true" />
Just don't process the form on submit if you want to cancel or navigate away.
I.e. don't do
<h:form>
...
<p:commandButton value="Cancel" action="#{bean.cancel}" />
</h:form>
But just do
<h:form>
...
<p:commandButton value="Cancel" action="#{bean.cancel}" process="#this" />
</h:form>
Or, better if you're only returning a navigation outcome in cancel() method anyway
<h:form>
...
<p:button value="Cancel" outcome="otherpage.xhtml" />
</h:form>
I am building an invoice application. When the user selects the client, then the services associated with the client are re-rendered in a dataTable by an ajax event. But, the ajax event of the selectOneMenu in the dataTable does not fire.
This is the form which lets the user select a client:
<h:form>
<h:selectOneMenu id="clientSelect" value="#{invoiceBean.client}">
<f:ajax execute="clientSelect" listener="#{invoiceServiceListener.processClientValueChange}" render=":test :invoiceData"/>
<f:selectItems value="#{invoiceBean.clientOptions}"/>
</h:selectOneMenu>
</h:form>
This will fire an ajax event which fills the services array in the invoiceBean and re-renders the dataTable which displays the services in another selectOneMenu in the dataTable. This part works properly.
This is the datatable that is re-rendered after selecting the client by the above form:
<h:panelGroup id="test">
<h:dataTable id="invoiceData" value="#{attributes.priceAttributes}" var="loop">
<h:column>
<ui:param name="service" value="service#{loop}" />
<ui:param name="description" value="description#{loop}" />
<ui:param name="price" value="price#{loop}" />
<h:form id="invoiceSelectMenu">
<h:selectOneMenu id="selectMenu" value="#{invoiceBean[service]}">
<f:ajax event="change" execute="selectMenu" listener="#{invoiceServiceListener.procesServiceValueChange}" render="#form" />
<f:attribute name="row" value="#{loop}" />
<f:selectItems value="#{invoiceBean.services}" />
</h:selectOneMenu>
<h:inputText id="description" value="#{invoiceBean[description]}" />
<h:inputText id="price" value="#{invoiceBean[price]}" />
<h:outputText value="#{loop}" />
</h:form>
</h:column>
</h:dataTable>
</h:panelGroup>
The selectOneMenu is filled properly. However, the ajax event in this select one menu does not work after it has been re-rendered by the first form. But, if I manually fill the services array without submitting the first form, then this ajax event executes normally. By the way, this ajax event also sets a value to the description and price input fields, which should be re-rendered when the event happens. The invoiceBean is request scoped.
This is going to be tricky. Due to JSF spec issue 790, whenever you re-render some content containing another <h:form> using <f:ajax>, then its view state will get lost. To solve this, you'd basically need to reference the full client ID of another <h:form> inside <f:ajax> instead of some containing component. But you've basically multiple forms inside a <h:dataTable> which can't be referenced by an absolute client ID.
You'd need to rearrange the code to put the <h:form> outside the <h:dataTable> and change the <f:ajax> to execute only the necessary components.
<h:form id="invoiceDataForm">
<h:dataTable id="invoiceData" value="#{attributes.priceAttributes}" var="loop">
<h:column>
<ui:param name="service" value="service#{loop}" />
<ui:param name="description" value="description#{loop}" />
<ui:param name="price" value="price#{loop}" />
<h:selectOneMenu id="selectMenu" value="#{invoiceBean[service]}">
<f:ajax execute="selectMenu,description,price" listener="#{invoiceServiceListener.procesServiceValueChange}" render="#form" />
<f:attribute name="row" value="#{loop}" />
<f:selectItems value="#{invoiceBean.services}" />
</h:selectOneMenu>
<h:inputText id="description" value="#{invoiceBean[description]}" />
<h:inputText id="price" value="#{invoiceBean[price]}" />
<h:outputText value="#{loop}" />
</h:column>
</h:dataTable>
</h:panelGroup>
and then reference it form the first form as follows:
<f:ajax execute="clientSelect" listener="#{invoiceServiceListener.processClientValueChange}" render=":invoiceDataForm" />
Note that some component libraries such as PrimeFaces have already workarounded/solved this in the component library specific ajax engine. So if it might happen that you're already using PrimeFaces, you could also replace <f:ajax> of the first form by <p:ajax>.
Unrelated to the concrete problem, the <f:attribute name="row" value="#{loop}" /> may not do what you expect it does. It will set null because <f:xxx> tags run during view build time, not during view render time tag. The #{loop} is not available during view build time. But that's subject for a different question :)
When I hit the commandButton it puts in the value that product.amount started as rather than what is currently typed in the input box.
<h:inputText value="#{product.amount}" />
<h:commandButton id="Button"
value="Buy"
tabindex="2" >
<f:ajax listener="#{shopBean.addToCart(product.product, product.amount)}"
execute="#this"
render="#all" />
</h:commandButton>
You need to include the input field in the execute attribute of the <f:ajax> so that it get processed as well, otherwise it will simply be ignored altogether.
<h:inputText id="amount" ... />
<h:commandButton ...>
<f:ajax execute="#this amount" ... />
</h:commandButton>
Or just put the whole in a single form and use execute="#form".
<h:form>
<h:inputText ... />
<h:commandButton ...>
<f:ajax execute="#form" ... />
</h:commandButton>
</h:form>
By the way, the render="#all" defeats one of the main advantages of using ajax. Try to render exactly only the component(s) which actually needs to be updated.