In my JSF Application, I have a page with several inputtext components. When the page is displayed, those inputtext components are populated with data from the database. When I hit the submit button, I want to pass those values as parameters to the next facelet.
What is happening is when I hit Submit, the old values are being passed, and not the updated values that the user has typed in. Here is what one of the inputtext components looks like:
<div align="center">
<h:outputLabel value="Product Quantity " />
<h:inputText id="quantity" value="#{product.quantity}" />
</div>
Then, in the submit button I am trying to get the values that the user types in:
<h:button value="Save Edits" outcome="welcome">
<f:param name="quantity" value="#{product.quantity}" />
</h:button>
Let's say that 100 was the original quantity that the field was populated with. When the user changes it to 110, and hits submit, the welcome facelet still thinks 100 is the value. Any ideas?
Is there any particular reason you've decided to use a <h:button/> instead of an <h:commandButton/>? Because that's the reason why your parameters are not making it to the next page
<h:commandButton/> processes it's enclosing <h:form/>, submitting it's content to the server in a POST request (and the JSF processing lifecycle kicks in e.t.c.) while the <h:button/> will generate a GET request. <h:button/> is generally used for navigation. Stick to <h:commandButton/> if you want to do more than navigate
Related
I have a form with a few different text fields which the user needs to fill in to be able to go to the next step. The next step of the page is accessed by clicking a commandbutton "Next" and should only be enabled when all of the fields are valid (validated on the server).
The problem is that the user can click the "next step" button directly after changing a field with valid input to invalid input, without loosing focus on the field, causing the validation to not get triggered in time to prevent the user to go to the next step.
Here is an example of one of the fields, together with the commandbutton doing the submit.
<p:inputTextarea id="lineFreeText" value="#{line.freeText}" rows="1" disabled="#{facesContext.validationFailed and component.valid}"
maxlength="#{itemConstant.MAX_FREE_TEXT_LENGTH}" counter="freeTextCounter"
counterTemplate="{0}/#{itemConstant.MAX_FREE_TEXT_LENGTH}" rendered="#{showFreeText and !line.hasItemForm()}" validator="freeTextValidator" validatorMessage="#{messages.freeTextRequired}" requiredMessage="#{messages.freeTextRequired}">
<p:ajax event="change" process="#this" listener="#{cartController.saveLine(line)}" update="#form cartForm lineFreeText lineEditedSymbols lineFreeTextMessage #([id$=nextStepBtn])" />
</p:inputTextarea>
<h:commandButton value="#{messages['checkout.nextStep']}" id="nextStepBtn" rendered="#{cartController.size() gt 0 and !clientContext.OCIRequest}"
onclick="$('.jqRealNextStepButton').click();" style="border: 2px solid #008091; padding: 0.5em;"
styleClass="ju-button" disabled="#{clientContext.client.visitor or checkoutDeliveryDateController.disableNextButton() or totalMinAmountNotMet or facesContext.validationFailed or not facesContext.postback}"
title="#{clientContext.client.visitor ? messages.disabledForVisitor : tooltip}">
<f:ajax execute="#this" />
</h:commandButton>
I want the commandbutton to cancel the submit when there's an on going ajax happening, so that the validation can finish before the form is submitted, enabling me to prevent users from inputting invalid data and continuing. Is there an easy way to accomplish this?
Cheers
The solution was to change the commandbutton to the primefaces one, and remove the onclick pointing to another commandlink, which executed the backend-logic to traverse to the next page. When I put the action-method in the <p:commandbutton/> the ajax-events were properly queued.
I have a page with results form a search arranged in pages. When I navigate forwards to the detail view and backwards to the result view, the result view is going to page1. How can I fix this? I am using two ViewScoped beans. I tried SessionScoped, but it will do the same. What is the best way to do this?
result page
<f:metadata>
<f:viewParam name="lang" value="#{search.language}" />
<f:viewAction action="#{result.init()}" />
</f:metadata>
<h:form>
<ui:repeat value="#{result.recipesView}" var="rec">
<h:link value="#{rec.title}" outcome="recipeshow">
<f:param name="id" value="#{rec.id}" />
</h:link>
<br/>
<h:outputText value="#{rec.id}"/><br/>
<h:outputText value="#{rec.author}"/><br/>
<h:outputText value="#{rec.createDate}"/><br/>
<br/>
</ui:repeat>
<br/>
<ui:repeat value="#{result.pagesArray}" var="page">
<h:commandLink value="#{page.pageNumber}" disabled="#{page.pageDisabled}">
<f:ajax listener="#{result.doPages()}" render="#form"/>
<f:param name="currentPage" value="#{page.pageNumber}"/>
</h:commandLink>
</ui:repeat>
</h:form>
If you do the manipulation of view scoped data, like managing the current page via <h:commandLink> it will be available as long as you interact with the current view by making postbacks. When you show the details view you are no longer dealing with results view anymore, so your view information is basically gone. So when you press the browser's back button you will either revert to the first page (in case page is not cached) or to the view as it was left beforehand (in case page is cached), but you'll get a ViewExpiredException.
What you need to do to overcome that difficulty is to hold the information in the URL the back button points to. In other words, give up using post links (<h:commandLink>) to page the results and switch to using get links (<h:link>) instead. The latter will be used to send a new get request holding the relevant information (current page, paging size, paging order, etc.) to show the results. This can be done by using <f:param> and <f:viewParam> tags. In this light when back button is pressed you will be shown the results with the parameters defined in the request. Idempotence of the result is the key in your situation.
So, you'll have a bunch of <f:viewParam> tags to keep the paging data in results view. You also need to change your command links to plain <h:link>s with nested <f:param>s that represent paging data as well.
This JSF1 code has me totally puzzled for hours. The basic setup is this page displayed with Seam2:
<h:form encType="multipart/form-data">
<rich:dataTable value="#{results}">
...
</rich:dataTable>
<h:selectOneMenu value="#{contact.type}">
<s:selectItems value="#{contactTypes}" var="t" label="#{t.label}" />
<s:convertEntity />
<a4j:support event="onchange" reRender="submitControls" />
</h:selectOneMenu>
<h:selectOneMenu value="#{template}">
<s:selectItems value="#{allTemplates}" var="t" label="#{t.label}" />
<s:convertEntity />
<a4j:support event="onchange" reRender="submitControls" />
</h:selectOneMenu>
<a4j:outputPanel id="submitControls" layout="block">
<a4j:outputPanel rendered="#{null != results and results.size gt 0 and ('ONE' == contact.type.label or template != null)}">
<h:commandButton value="submit" action="#{manager.generate}" />
</a4j:outputPanel>
<h:outputText value="Search first" rendered="#{results == null or results.size == 0}" />
<h:outputText value="Select template first" rendered="#{'ONE' == contact.type.label and template == null}" />
</a4j:outputPanel>
</h:form>
Obviously, the original page is a bit larger. What has me scratching my head is that if I don't change contact.type (leave it at a default selected by the backing bean) the form submits fine. If I switch the type to ONE this correctly renders the "Select template first" text instead of the submit control. Restoring the submit button by selecting another type re-produces the <input> BUT without the onclick handler that was there when the form was first rendered.
Now a click on the <h:commandButton> sends a request to the server but does NOT trigger the associated action. However, it now restores the onclick handler and a second click triggers a proper submit.
I'm at a loss why this is so. Any suggestions?
EDIT: moving the rendered attribute to the button results in the same behavior (even if it did work, the original panels contain more controls that share the same condition, so they do serve a purpose)
EDIT2: I've just tested that simply re-adding the "lost" onclick handler (via firebug) that gets rendered on the submit button makes the action work as intended. I'm beginning to suspect a bad interaction between richfaces and the trinidad libs also included in this project (but not used on this page).
It's a safeguard against tampered/hacked requests. Otherwise a hacker would be able to invoke actions s/he isn't allowed to invoke by just editing the sent HTTP request parameters accordingly that the non-rendered (e.g. due to missing "ADMIN" role) command button will be invoked.
You need to make sure that you prepare the same model (managed bean instance with all properties responsible holding the conditions behind rendered attribute) during the HTTP request of processing the form submit as it was during the HTTP request of displaying the form. In JSF2, this is easy achievable by placing the bean in the view scope instead of the request scope. The view scope lives as long as you're interacting with the same view. In JSF1, you'd need to grab a 3rd party framework tag like Tomahawk's <t:saveState> or RichFaces' <a4j:keepAlive> in order to simulate the JSF2 view scope.
<a4j:keepAlive beanName="results" />
The same story applies to disabled attribute by the way.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?
I think that with the rendered attribute and anything inside you have to take care that the evaluation of it is the same on the initial request AND the submit. It may change just before the render phase but if its not the same during application invoke it will most likely ignore the action if in this phase the button would not be rendered.
As far as i remember this happend for me mostly when the rendered expression uses something like an entity attribute that will be changed during the apply request values phase already.
I have a page where the user can upload a file to the server. He can set which groups/users can read/write (to) the file.
This is done by selects. One select holds the names of the groups the user is currently in, and on the same row is a select with options Read and Write. On the second row is the corresponding stuff for selecting users.
When the user selects a group and either Read or Write for said group, he then presses a button. After pressing the button I would like to show the user a list of permissions below the select. The list would have a group name, access setting for said group and a button to remove the permission item.
My problem is, I'm not able to update the page and show the list of permissions. Server side the permissions are added to an ArrayList, but I can't get the contents to show in a4j:repeat. How can I get the repeat tag to update?
Here is what I've been trying to do so far:
<h:form>
<h:selectOneMenu value="#{assetUploadForm.currentGroupName}" valueChangeListener="#{assetUploadForm.groupNameChanged}">
<f:selectItem itemValue="users" itemLabel="users" />
<f:selectItem itemValue="foobar" itemLabel="Foobar" />
<a4j:ajax event="valueChange" render="second" execute="#this" />
</h:selectOneMenu>
<h:selectOneMenu value="#{assetUploadForm.currentGroupRW}" valueChangeListener="#{assetUploadForm.groupRWChanged}">
<f:selectItem itemValue="R" itemLabel="Read"/>
<f:selectItem itemValue="W" itemLabel="Write"/>
<a4j:ajax event="valueChange" render="second" execute="#this" />
</h:selectOneMenu>
<a4j:commandButton action="#{assetUploadForm.addGroupRights}" value="add group" render="groupList"/>
<ul>
<a4j:repeat value="#{assetUploadForm.groupPermissions}" var="permission" id="groupList">
<li><h:outputText value="#{permission.permissionSetItemId}"/></li>
</a4j:repeat>
</ul>
</h:form>
So, the problem is a4j:repeat is never updated. If I replace the repeat with an outputtext, and set the commandbutton to render it, the page is updated "correctly".
The <a4j:repeat> does not render any HTML to the response. The render attribute of <a4j:ajax> however expects a component with that ID being physically present in the HTML DOM tree (it is namely behind the scenes using JavaScript document.getElementById() stuff to get the element which needs to be updated after the ajax response has returned). This is thus not possible in combination with <a4j:repeat>. You would need to specify its parentmost JSF HTML component instead, or at least to wrap it in a new one.
E.g.
<a4j:commandButton action="#{assetUploadForm.addGroupRights}" value="add group" render="groupList"/>
<h:panelGroup id="groupList">
<ul>
<a4j:repeat value="#{assetUploadForm.groupPermissions}" var="permission">
<li><h:outputText value="#{permission.permissionSetItemId}"/></li>
</a4j:repeat>
</ul>
</h:panelGroup>
As a different alternative, you can also just use the <rich:list> component instead which renders the complete <ul><li> for you already. You're then basically updating the <ul> directly.
<a4j:commandButton action="#{assetUploadForm.addGroupRights}" value="add group" render="groupList"/>
<rich:list id="groupList">
<h:outputText value="#{permission.permissionSetItemId}"/>
</rich:list>
To learn about which components all are available and how to use them, peek around in the showcase site and the component reference.
I don't know why it does not work but as a work-around you could probably use h:dataTable for this. With some css tweaking that could be rendered with the same looks.
Or wrap a a4j:outputPanel around the a4j:repeat and try what happens if you render that.
MAG,
Milo van der Zee
I'm developping an application in JSF2.0. I encountered a problem when mixing ajax and a panelGroup with a rendered attribute.
My page contains 3 panels. In the first panel the user selects an item from a <h:selectOneMenu>. This causes to render the second panel.
The second panel contains an h:dataTable that is connected to a DataModel in the backing bean. The values of the dataTable are determined by the item that was chosen in the <h:selectOneMenu> of the first panel. Each row in the table contains a commandLink to view detailed info about the item of that row:
<h:commandLink action="#{faseController.selectInvulling}">
<f:ajax render="#form" execute="#form" />
</h:commandLink>
Clicking on the commandLink the third panel gets rendered:
<h:panelGroup rendered="#{faseController.invullingSelected}" layout="block" styleClass="panelElement" id="invulling">
<label>
<span>Datum:</span>
<h:inputText value="#{faseController.selectedInvulling.datum}" required="true" requiredMessage="Gelieve een datum in te vullen." converterMessage="Gelieve een geldige datum in te vullen (dd/mm/jjjj)." >
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:inputText>
</label>
<label>
<span>Evaluatie</span>
<h:inputTextarea value="#{faseController.selectedInvulling.evaluatie}" cols="100" />
</label>
<label>
<span>Methode</span>
<h:inputTextarea value="#{faseController.selectedInvulling.methode}" cols="100" />
</label>
</h:panelGroup>
This is where I encounter a problem. The first time I click on a commandLink to view the detailed info about that row in the table, I get the correct data in the third panel. Afterwards I change the item in the <h:selectOneMenu> of the first panel: the correct corresponding dataTable gets rendered in the second panel. However this time when I click on a commandLink in the table to view the details of that item, I get to see the info from the item I clicked the first time.
If I ommit rendered="#{faseController.invullingSelected}" everything works fine, but this causes confusion in the view, since the third panel is now always rendered.
All three panels are located in the same form. My backing bean is ViewScoped. What am I doing wrong? Any help woud be greatly appreciated.
This can happen if you're doing business logic in an getter method instead of in an (action)listener method. I also wonder if you really need to execute and render the entire form. Try to be more specific in specifying the elements which are to be executed and/or re-rendered.
The question is way too broad and the code is not complete enough in order to pinpoint the real cause and propose the a ready-to-use solution.
Try using this.
<a4j:commandLink action="#{faseController.selectInvulling}" execute="#this"
render="thirdPanelId" limitRender="true"/>
Execute only the components which you want to process and render only the components which needs to be refreshed.