Saving data from multiple inputtext boxes created by a loop in jsf - jsf

Basically, I have an input text box that I want to submit for each item in the array. The code below is cut down to the relevant portions
<c:forEach items="${mybean.mats}" var="mat">
<p:dataTable var="datarow" value="#{mybean.getDatarows(mat.itemId)}" rowIndexVar="row">
<p:column>
<p:inputText value="#{bean.amt}" />
</p:column>
</p:dataTable>
</p:panel>
<p:commandButton value="Confirm" action="#{mybean.runSubmit}" process="#this" />
</c:forEach>
From what I know, each individual item needs to have its own variable name to save the data in each input text box. I know the method I'm currently using is wrong, so is there another way to save all the data? Perhaps in an array or something?

First, mixing the JSTL c:foreach with a datatable is not recommended. Use ui:repeat instead.
Second, your p:dataTable value has to reference a collection that exists during the lifetime of the backing bean. It looks to me like the call to #{mybean.getDatarows(mat.itemId)} generates a list of items dynamically. That's going to be a problem since your backing bean will need to call the getDatarows when the values are re-applied to the bean on your ajax call runSubmit to save the values. In this case, you will need to save the dynamically created list to the backing bean so that the same collection will match up exactly to the collection used to produce the html.
For example, suppose your backing bean contains the property List<List<Mat>> mats, where the Mat class contains a single property 'dataId'. Then, your EL could be:
<h:form id="input-form">
<ui:repeat id="mats-repeat" value="#{mats}" var="mat">
<p:dataTable id="mat-table" value="#{mat}" var="dataObj">
<p:column>
<p:inputText id="dataId" value="#{dataObj.dataId}" />
</p:column>
</p:dataTable>
</ui:repeat>
</h:form>
Since the form, repeat, and dataTable components are naming containers, they ensure that any child components are named uniquely. In this case, the first input mat element would be rendered as:
<input id="input-form:mats-repeat:0:mat-table:0:dataId" ...

Related

JSF validation error prevents updating another valid rows of an h:dataTable placed in an h:form

I have an h:dataTable inside of an h:form, where each row has it's own h:commandButton type="submit" action="#{bean.saveChanges(item)}".
f:inputs are declared as required and they also need to match a pattern.
If every input is in the right format, then it works fine.
Otherwise it needs only one input to be wrong and an updating function on a commandButton corresponding to a completely different item in another row seems not to be called, therefore not updated in the database.
Also only the wrong row's validation message is displayed and the changes are maintained in the view by a (backing Spring view scoped) bean, so the user might actually think, that the initial row was indeed updated in the database too.
Is there a way, how to separate individual rows of the h:dataTable, so that the validation messages of another row does not stop other items from being updated by the method of a (Spring/backing) bean?
Use ajax to process/execute only the current row. You can achieve that by explicitly specifying the client IDs of the input components in <f:ajax execute>.
<h:form>
<h:dataTable ...>
<h:column>
<h:inputText id="foo" ... />
</h:column>
<h:column>
<h:inputText id="bar" ... />
</h:column>
<h:column>
<h:inputText id="baz" ... />
</h:column>
<h:column>
<h:commandButton ...>
<f:ajax execute="foo bar baz #this" ... />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
This won't process the inputs in other rows. Use if necessary <f:ajax render> to update the <h:message(s)> associated with the inputs.
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
The required on the input cause the Process validation to fail and the render response to be invoked.
A simple solution could be You could remove the required from the input and handle the case in you managed bean. Since the action would move on till Phase 5: Invoke application the valid data can be saved. For all invalid rows highlight the row by having a boolean in you data model.

JSF Updating values in a bean from a list

So, I have a session scoped bean that has a 2 lists of string values. This bean is called AgreementBean.java. I'm showing these lists in a page called agreementDetail.xhtml like this
<h:dataTable id="servers" value="#{agreement.licenseServerNames}" var="licenseServerName">
<h:column>
<h:inputText value="#{licenseServerName}"/>
</h:column>
</h:dataTable>
Computer IDs<br/>
<h:dataTable id="idNames" value="#{agreement.computerIdNames}" var="computerIdName">
<h:column>
<h:inputText value="#{computerIdName}"/>
</h:column>
</h:dataTable>
As you can see, I expect user input on these values. I need to make an Ajax call to update those values when the customer clicks on a "Save button". Here's the button's jsf code.
<script type="text/javascript">
function showAlert(data){
alert("SAVED!");
}
</script>
<h:commandButton value="Save" immediate="true" type="submit" action="#{agreement.save}">
<f:ajax onevent="showAlert"/>
</h:commandButton><br/><br/>
The "Save" bean method does nothing right now, except for logging the values stored in both lists.
When clicking on the button, 2 things are happening right now. If the customer changed the values on the inputFields, the bean's list's value is set to null. If the customer didn't change anything, then the bean's original value is kept.
How can I fix this? Thanks!
There are 2 problems with your command button:
<h:commandButton value="Save" immediate="true" type="submit" action="#{agreement.save}">
<f:ajax onevent="showAlert"/>
</h:commandButton>
immediate="true" causes that only input elements which also have immediate="true" set will be processed. However, your inputs don't have this attribute set.
<f:ajax execute> defaults to #this, causing that only the command button itself is processed during form submit. Your inputs are therefore skipped in processing.
Get rid of the misplaced attribute and tell <f:ajax> to execute the entire form.
<h:commandButton value="Save" type="submit" action="#{agreement.save}">
<f:ajax execute="#form" onevent="showAlert"/>
</h:commandButton>
See also:
Why was "immediate" attribute added to the EditableValueHolders?
Then there's a potential problem with your data model. You seem to be supplying a List<String> to the data table instead of a List<SomeBean>. The String is immutable and doesn't have a setter for the value. A <h:inputText value="#{string}"> is never going to work. For the first table, you really need to have a LicenseServer bean with a private String name property. You can then use it as follows:
<h:dataTable value="#{agreement.licenseServers}" var="licenseServer">
<h:column>
<h:inputText value="#{licenseServer.name}"/>
See also:
Why input (for example h:inputText) nested in h:dataTable do not update Bean model?
Unrelated to the concrete problem, are you aware that onevent is invoked 3 times? For the purpose you'd probably like to check if ajax event status equals to "success".
See also:
Proccess onclick function after ajax call <f:ajax>

Set f:param in external h:commandButton (JSF2)

I really love actionListener and the possibility to pass whole objects as as parameter, instead needing to pass values as String or creating (hidden) form fields. I'm using JSF 2.1 (Mojarra) and RichFaces (for popupPanel).
Currently I'm stuck with the following problem:
I create a table with a button that opens a popup. In that popup, the user can edit the data of the current user/object in the table.
When I click the button in the popup to save the edits, how can I submit the values from the popup AND tell the bean action which userObject I'm edited?
Currently, my workaround is using a hidden inputText field in the popup, but I don't like it this way. Is there an alternative?
This is what I try to achieve (minimized):
<h:datatable value="#{bean.users}" var="user">
<h:column>
Username #{user.name}
</h:column>
<h:column>
<input onclick="showPopup()"/>
</h:column>
</h:datatable>
<rich:popupPanel>
<h:inputText value="#{bean.text}" />
<h:commandButton value="Action" actionListener="#{bean.doSomething}">
<f:attribute name="selected" value="#{userObjectFromDatatable}" /> <-- HOW? -->
</h:commandButton>
</rich:popupPanel>
Looks pretty straightforward for you to preserve the selected the userObject in a conversation-like scope as in #ViewScoped. See this article for details on the #ViewScope. As an example, Declare a variable of the desired type as an instance variable in your backing bean
UserObject userObject;
//getters and setters
In your table you'll now have something like the following to set the selected object in your backing bean
<h:commandButton value="Action" actionListener="#{bean.doSomething}">
<f:setPropertyActionListener value="#{user}" target="#{bean.userObject}"/>
</h:commandButton>
By setting the variable in your backing bean from within the table, the viewscope will ensure that any other operation you perform on that object will be with the same instance, provided you stay on the same JSF view and you do not navigate away from it.

Losing inputs submitted in composite component

I have a problem with submitting composite components.
Most of my composite components contain both the input components and the "submit" button.
When I tried to put the button still in the same h:form but not in the same composite component, the submitted value seemed to be "lost" somewhere. And, for instance, my validators got called on original values.
Example :
<composite:interface>
<composite:attribute name="titreContext" required="true"/>
</composite:interface>
<composite:implementation>
<p:outputPanel id="selectionTitreDetailsPanel" styleClass="selectionTitreDetails">
<p:outputPanel id="selectionTitreDetailsPanelInner" rendered="#{not empty cc.attrs.titreContext.selected}">
<p:panelGrid columns="2" id="panelId">
<h:outputText id="idLabel" value="Id :"/>
<h:outputText id="id" value="#{cc.attrs.titreContext.selected.titeluid}"/>
<p:tooltip for="id" value="Identifiant unique"/>
</p:panelGrid>
<p:panelGrid columns="2" id="titelePanel">
<p:outputLabel for="selectTitele" value="Titre :"/>
<p:selectOneMenu id="selectTitele" value="#{cc.attrs.titreContext.selected.titele}" effect="fold" styleClass="fullWidth">
<f:selectItems value="#{constants.getTitelesForTypman(cc.attrs.titreContext.selected.titele.typman)}" var="titele" itemLabel="#{titele.titelelil}" itemValue="#{titele}" styleClass="fullWidth"/>
<p:column styleClass="fullWidth">#{titele.titelelil}</p:column>
</p:selectOneMenu>
</p:panelGrid>
[...]
<p:commandButton id="confirmerModifications" icon="small_edit" type="submit" value="Confirmer les modifications"
action="#{elutersEditionContext.confirmeModifsSelection}" process="mandatsTerritorial"
update="mandatsTerritorial #{cc.attrs.notifUpdates}"/>
</composite:implementation>
works.
But putting the p:commandButton out of the composite :
<h:form>
<mylib:mycomponent /*parameters *//>
<p:commandButton /*parameters*/ />
</h:form>
does not work. When I debug my validators, I can see that the modified values where not even submitted. Neither getLocalValue, getSubmittedValue nor getValue is changed.
Is there a syntax in composite component declaration to use to correct this situation ?
By the way : when I was writing my components as composite components rather than custom components, retrieving #{asen} in the backing bean just worked.
Thanks in advance.
I am using :
PrimeFaces 3.4.1
CODI 1.0.5
OpenWebBeans 1.1.6
MyFaces 2.1.9
Tomcat 7.0.32
(update) This very strange problem was caused by h:form nesting.
Very strange because h:form nesting did not perturbate the processing of the first level of composite components, but caused this strange "input lost" in nested composite.
Nesting looked like this :
<h:form>
...
<p:tabView ...>
<p:tab>
<h:form>
<my:composite ....>
</h:form>
</p:tabView>
</h:form>
You're using a relative client ID in the process attribute of the <p:commandButton>:
<p:commandButton ... process="mandatsTerritorial" />
A relative client ID is relative to the parent NamingContainer component. It will be searched as direct child of the NamingContainer component. If the child is by itself a NamingContainer, then its children would not be searched.
Composite components are by itself in fact also NamingContainer components. If the button is placed in the composite, then this will be searched as direct child of the <cc:implementation>. In your particular case, only the component with id="mandatsTerritorial" will be processed on form submit, including all of its children (note that this component is nowhere visible in the code posted so far, but I'd imagine that you omitted it for brevity).
If the button is placed in <h:form>, then this will be searched as direct child of the <h:form>. However as this is apparently been placed inside the composite (which is, as said, another NamingContainer component), it wouldn't be found and hence basically nothing would be processed. You'd need to fix the process to point to the right client ID. E.g.
<h:form>
<mylib:mycomponent id="mycomponent" />
<p:commandButton ... process="#this mycomponent:mandatsTerritorial" />
</h:form>
This way it will process itself (mandatory to invoke the action!) and the component with id="mandatsTerritorial" inside the <cc:implementation> of the composite with id="mycomponent".
As a completely different alternative, which would work just fine in this particular construct, is to remove the process attribute altogether. It defaults to #form already which will thus process the entire form.
Update as per your question update: nesting forms is invalid in HTML. Using the JSF <h:form> representation doesn't change that; you'd still end up with nested forms in HTML. The browser behaviour is unspecified as to which data would be submitted to the server. Make sure that you don't nest <h:form> in JSF as well.

input binding in ui:repeat in jsf

i am using facelets jsf 2.0 with primefaces 3.0.M2 component library.
i am trying to achieve dynamic numbers of rows including iput fields that are filled when a datatable selection occurs.
whenever a selection is made the dynamic rows generated correctly with input fields but after the first selection for following selections dynamic row count changes correctly but the input fields does not update and keeps showing inputs from the first selection.
here is how i iterate list in facelet;
<ui:repeat value="#{goalEntranceBean.selectedCard.parameterList}" var="prmBean" >
<li><h:outputText value="#{prmBean.lookUp.value}"/></li>
<li>
<h:outputText value="Weight:"/>
<p:inputText id="wx" required="true" value="#{prmBean.weight}">
</p:inputText>
<h:outputText value="Percent:"/>
<p:inputText required="true" value="#{prmBean.percent}">
</p:inputText>
</li>
</ui:repeat>
my bean where i get the list of cards and set the selectedCard with rowSelect event in datatable.
#ManagedBean(name = "goalEntranceBean")
#ViewScoped
public class GoalEntranceAction implements Serializable {
private List<ScoreCard> personalCards = new ArrayList<ScoreCard>();
private ScoreCard selectedCard = new ScoreCard();
......
}
when i checked in debug mode i can see the true list but in screen the elements does not change.
This is a common problem (gets asked every couple of days). To make long story short, inputs inside ui:repeat do not work, period.
It is a problem with JSF, a long standing, famous one. Maybe it will be fixed. Maybe not, it seems that no one really cares (I mean - an input? in a... ui:repeat? such crazy scenario!).
A quick-fix is to use a h:dataTable, possibly ungodly abused with css to make it look like a list. A long-fix is to use some iterator from a different library. Primefaces has an element that should work that renders an unordered list.
thanks for your replies. Sorry for forget sharing the solution.
As i mentioned above i have primefaces datatable.
On row selection event i render datatable and want to update the cells of that datatable.
USING p:inputtext easily solved my problem. Now i can change the data on screen and i can see the values after update operation on screen. I don't understand the reason but it works.
<p:dataTable var="orgPrmBean"
value="#{scoreCardOperationsBean.selectedCard.orgParameterList}"
emptyMessage="#{labels.norecord}"
rowKey="#{orgPrmBean.id}"
>
<p:columnGroup type="header">
<p:row>
<p:column headerText="Parameters" colspan="3" style="text-align:left;width:480;"/>
</p:row>
</p:columnGroup>
<p:column style="text-align:left;width:200px;">
<h:outputText value="#{orgPrmBean.info}"/>
</p:column>
<p:column style="text-align:left;width:180px;">
<p:inputText value="#{orgPrmBean.weight}"
rendered="#{scoreCardOperationsBean.selectedCard.goalEdit}">
<f:convertNumber maxFractionDigits="0"/>
</p:inputText>
</p:column>
</p:dataTable>
It IS possible to make it work, but the solution is to bind the inputs to a backing bean, and update the values of the controls in the backing bean via listeners (using the new value received in the argument). Obviously this isn't a good solution if you have a complex form, as you need to add a listener/control in the backing bean for each control in the page, but it's practical if you just have one or two inputs.

Resources