jsf inputText disabled and readonly properties in form - forms

This question is a follow on from a previous question "InputText value null when disabled is true" however I can not add comments to it.
I am using jsf 2.2 and the both the disabled and readonly properties when set true, for the inputText and inputTextarea controls when included in a form is deleting data from the associated field in the database when the object is merged because the fields are null when the object is returned from the jsf page.
The purpose for setting these properties on a form's field is to display the data in the field but not allow the user to change it and save changes to other fields in the form.
What other way can this be achieved other than placing the fields outside of the form and complicate the page layout.
Graham

I solved the problem, it was caused by using #RequestScoped instead of #SessionScoped for my page controller bean.
What I was doing was using a edit link from a datatable passing the current product object to the doEditProduct method.
<h:dataTable id="viewProductsTable" value="#{productController.products}" var="_product"
styleClass="data-table" headerClass="table-header" rowClasses="table-row">
<h:column>
<f:facet name ="header">
<h:outputText value="Product Name" />
</f:facet>
<h:outputText value="#{_product.productName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Goal"/>
</f:facet>
<h:outputText value="#{_product.goal}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Details"/>
</f:facet>
<h:outputText value="#{_product.description}"/>
</h:column>
<h:column>
<h:form>
<h:commandLink value="Edit" action="#{productController.doEditProduct(_product)}"/>
</h:form>
</h:column>
</h:dataTable>
the productController.doEditProduct method then opened the edit page
public String doEditProduct(Product product) {
this.product = product;
return "edit-product.xhtml";
the edit page contained a simple edit form
<h:form id="addProductForm">
<h:panelGrid columns="2" columnClasses="top-alignment, top-alignment">
<h:outputLabel for="product-name" value="Product Name"/>
<h:outputText value="#{productController.product.productName}" id="product-name" />
<h:outputLabel for="goal" value="Goal" />
<h:inputTextarea value="#{productController.product.goal}" id="goal" rows="10" cols="100" />
<h:outputLabel for="details" value="Details" />
<h:inputTextarea value="#{productController.product.description}" id="details" rows="20" cols="100"/>
<f:facet name="footer">
<h:panelGroup style="padding-top: 15px; display: inline-block; float: right; white-space: nowrap">
<h:commandButton id="submit" value="Save" action="#{productController.updateProduct()}" class="button" />
<h:button id="Cancel" outcome="index.xhtml" value="Cancel" class="button"/>
</h:panelGroup>
</f:facet>
</h:panelGrid>
</h:form>
At this point the product data was displayed on the page. However when the save button was clicked and ran the update method
public String updateProduct() {
try {
log.log(Level.INFO, "Updating: {0}", product.getGoal());
productFacade.edit(product);
} catch (Exception e) {
log.log(Level.WARNING, e.toString());
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, "could not update product");
facesContext.addMessage(null, m);
return "";
}
return "index.xhtml";
Any field that had was disabled or readonly was set to null. In fact any non input field, anywhere on the page was set to null.
#RequestScope on the controller class meant that the class was being reinstantiated and thus the object stored in product was being assigned a new object in the PostConstruct method. The values in the editable fields were transferred to this new object and the non editable fields were set to null. Merging with the database meant that the data in the fields was deleted.
Using #SessionScoped means that the controller beans continues to exist across page requests. (I needed to remind myself about basic web page lifecycles)
Hope this helps anybody else that has this behaviour.
Graham

Related

Primefaces v.5.3.5 confirm dialog render issue outside main h:form and inside main form is rendered but it is not working properly

I am using PF v.5.3.5 and JSF v.2.2.8. It is a frequent topic in SO. I noticed that there is a bug in PF v.5.3.5 documentation related to the appendTo attribute.
1st approach
The p:confirmDialog is rendered and commandbuttons are rendered but actions does not work and message is not rendered if it is placed inside of nested h:form.
2st approach
If I place this dialog outside of main h:form it is not rendered at all also if I add the global="true" attribute.
3st approach
The p:confirmDialog is rendered and commandbuttons are rendered but actions does not work and message is rendered if the nested h:form is removed.
<h:form>
...
<p:confirmDialog id="askSessionDialog1" widgetVar="askSessionDialog1" severity="alert"
appendTo="#(body)" rendered="#{treeData.askSessionDialogRendered}" visible="#{treeData.askSessionDialogRendered}">
<h:form>
<f:facet name="message">
<h:outputText value="#{msg.WEB_ADMIN_PAGES_TREESEGMENT_NOSESSION}" escape="false"/>
</f:facet>
<p:commandButton value="#{msg.WEB_BUTTONS_OK}" action="#{treeData.save(false, true)}" icon="fa fa-check"
update="#(form)" type="button" />
<p:commandButton value="#{msg.WEB_BUTTONS_CANCEL}" action="#{treeData.setAskSessionDialogRendered(false)}"
icon="fa fa-close" onclick="PF('askSessionDialog1.hide()')" update="#(form)" type="reset" />
</h:form>
</p:confirmDialog>
...
</h:form>
BECKEND PART
setAskSessionDialogRendered(true);
RequestContext.getCurrentInstance().update("treeSegmentForm askSessionDialog askTurnOffDialog askSessionDialog1 askTurnOffDialog1");
Thanks in advance for constructive posts and comments.
SOLVED
This is the best approach that works for me now.
<h:form>
...
<p:confirmDialog id="askSessionDialog" widgetVar="askSessionDialog" severity="alert"
appendTo="#(body)" rendered="#{treeData.askSessionDialogRendered}" visible="#{treeData.askSessionDialogRendered}">
<f:facet name="message">
<h:outputText value="#{msg.WEB_ADMIN_PAGES_TREESEGMENT_NOSESSION}" escape="false"/>
</f:facet>
<h:form>
<p:commandButton value="#{msg.WEB_BUTTONS_OK}" icon="fa fa-check" type="button" accesskey="o">
<p:ajax event="click" listener="#{treeData.save(false, true)}" oncomplete="PF('askSessionDialog').hide()"
update="#(form)" />
</p:commandButton>
<p:commandButton value="#{msg.WEB_BUTTONS_CANCEL}" icon="fa fa-close" type="reset" accesskey="c">
<p:ajax event="click" listener="#{treeData.setAskSessionDialogRendered(false)}"
onsuccess="PF('askSessionDialog').hide()" update="#(form)" />
</p:commandButton>
</h:form>
</p:confirmDialog>
...
</h:form>
BACKEND
setAskSessionDialogRendered(true);
RequestContext.getCurrentInstance().update("treeSegmentForm");
SPACIAL THANKS TO: #YagamiLight
He helped me to kick off my solution.

Strange javax.el.PropertyNotFoundException, does not work with manual deploy but works in eclipse deploy

I'm having a problem to declare a property in a managed bean (JSF 2.2), I have already read other questions about name convention of property in beans and mine appears to be ok. My page.jsf is a ui composition and the property name is a date: private Date dataSemAtendimento. This is the calendar tag of primefaces (5.1) that I'm working with:
<p:dialog header="Escolha as data de feriado e ponto facultativo"
widgetVar="modalCalendar" id="modalCalendar" modal="true" width="400"
height="500" appendTo="#(body)">
<p:calendar id="popup" widgetVar="popupCal"
value="#{postoAtendimentoBean.dataSemAtendimento}">
</p:calendar>
<p:commandButton value="Adicionar data" update="tableCal">
<p:ajax listener="#{postoAtendimentoBean.adicionarDataFeriado}" />
</p:commandButton>
<p:dataList id="tableCal"
value="#{postoAtendimentoBean.postoDiaSemAtendimentoList}" var="data"
style="width:50%">
<f:facet name="header">
Datas que não ocorreram o atendimento
</f:facet>
<p:column>
<h:outputText value="#{data}">
<f:convertDateTime locale="pt" />
</h:outputText>
</p:column>
<p:column>
<p:commandButton icon="ui-icon-trash" update="tableCal"
action="#{postoAtendimentoBean.removerDataFeriado(data)}">
<p:ajax listener="#{postoAtendimentoBean.removerDataFeriado(data)}"></p:ajax>
</p:commandButton>
</p:column>
</p:dataList>
<p:separator />
<p:panelGrid style="margin: auto;">
<p:commandButton value="Confirmar" onclick="PF('modalCalendar').hide();" />
</p:panelGrid>
</p:dialog>
And this is the managed bean code related to the get/setter:
#ManagedBean
#ViewScoped
public class PostoAtendimentoBean extends AbstractCRUDBean<PostoAtendimento, Long> {
private Date dataSemAtendimento;
public Date getDataSemAtendimento() {
return dataSemAtendimento;
}
public void setDataSemAtendimento(Date dataSemAtendimento) {
this.dataSemAtendimento = dataSemAtendimento;
}
}
Error Rendering View[/resources/template/template.xhtml]: javax.el.PropertyNotFoundException: /pages/cadastros/posto_atendimento/manter_posto_atendimento_persistencia.xhtml #161,25 value="#{postoAtendimentoBean.dataSemAtendimento}": The class 'br.com.webtech.scheduler.bean.postoatendimento.PostoAtendimentoBean' does not have the property 'dataSemAtendimento'.
I'm running in a wildfly (8.2.1) instance, but the strange thing is when I deploy it manually it doesn't work but when I deploy via eclipse adding the ear inside the server tab it works normally. I'm lost, already tried a couple of things. Any ideas? Thanks.
Another strange thing is, this started to happen when I changed the context-root of my application via Maven webModule tag.
Edit: I made a workaround by copying the .class with the wrong context-root and putting it inside the generated ear with the new context-root, that works but it's an awlful way to solve the problem.

how to edit single row in rich:dataTable

i have to edit a row in a table using rich faces 4 and modal panel. I am new one so please tell me in details and i know to make a table in rich faces. i already searched so many things but not getting any fruitful
See answer for question "Richfaces: show details in popup [commandbutton, action and popupPanel]". It works in RichFaces 4.x with rowClick.
Or here is example with commandLink:
<a4j:commandLink action="#{actionBean.setupTransactionDetails}"
event="onclick" render="transactionDetails"
oncomplete="#{rich:component('transactionDetails')}.show()"
styleClass="rich-link">
<h:outputText value="#{res.transactionType}" />
<f:setPropertyActionListener value="#{res.transactionId}"
target="#{profile.transactionId}" />
</a4j:commandLink>
But I prefer updated version like this:
<a4j:jsFunction name="showDetail" action="#{actionBean.setupTransactionDetails}"
oncomplete="#{rich:component('transactionDetails')}.show();"
render="transactionDetails">
<a4j:param name="id" assignTo="#{profile.transactionId}"
converter="javax.faces.Long" />
</a4j:jsFunction>
<rich:dataTable id="txnTable" rows="#{referenceData.recordsPerPage}"
style="width: 100%" rowClasses="oddrow, evenrow"
value="#{profile.transactions}" var="res" sortMode="single">
<h:column width="110">
<f:facet name="header">
<h:outputText value="#{msg.transactionType}" />
</f:facet>
<a4j:commandLink onclick="showDetail('#{res.transactionId}');"
value="#{res.transactionType}" />
</h:column>
</rich:dataTable>
<rich:popupPanel id="transactionDetails" autosized="true"
style="max-height:600px;">
<!-- f:facet name="header" and f:facet name="controls" here -->
<h:form id="transactionDetailsForm">
<!-- some details here -->
</h:form>
</rich:popupPanel>
Profile backing bean
private Long transactionId; // + getter and setter
Action backing bean
public void setupTransactionDetails() {
Transaction txn = DAO.getInstance().get(Transaction.class, getProfile().getTransactionId());
transactionForm.setup(txn);
}
In case if you use EL 2.2 (or higher) you can call action bean method with parameter.

Clear form in p:dialog on close after failed action/method call

I've got a form within a p:dialog component being submitted via AJAX. The form in the dialog is via a ui:include of another .xhtml containing just the form and its components (no, I am not nesting forms; the dialog itself is not within any form). The included page's backing bean is 'ViewScoped'.
MOST things function fine:
On successful validation, the form will execute the save method; after a successful save, the dialog closes; opening a subsequent record shows proper record information from the database.
On unsuccessful validation, the submitted values persist and the dialog remains open and displays validation errors, fixing the invalid fields and resubmitting results in a successful save.
The problem comes in when the action called by the p:commandButton fails. In the event that it fails, the dialog remains open and displays "Error saving changes" via h:messages to the user; additionally, the submitted values still persist in the input fields. This is fine (and even desired) while the form remains open, however-- upon closing the dialog and reopening it, the submitted values are STILL in the text fields. This is bad because it gives the user the impression that the save did succeed (as the h:messages component is now blank due to the dialog update).
So far I have tried the following, NONE of which have remedied the problem:
1.1) Setting the backing bean of the included form to a new instance of the bean on dialog open.
1.2) Since the bean is now a new instance, I am also repopulating the address object with details from a data bean.
2.1) Disabling the close button on the dialog and adding a p:commandButton "Cancel" button with a p:resetInput component in
it to close the dialog/reset the form. (dialog closes, but submitted
values in form persist).
2.2) Calling a method from this p:commandButton that removes the RequestMap for the included form's backing bean.
2.3) Tried with the button set to both immediate=true and immediate=false.
2.4) Tried with the button set to process=#this, a similar tactic I have used to close a form to ensure it will have fresh fields upon
reopening.
You would think between setting the backing bean to a new instance, and repopulating the address object I would be seeing a fresh form, but NOPE.
Here is some of the source:
Portion of mainform.xhtml
<p:dialog id="dlgAddress"
header="Address Edit"
widgetVar="dialogAddress"
dynamic="true"
modal="false"
closable="false"
resizable="false"
styleClass="dlgAddress"
visible="#{addressform.showDlgAddress}">
<ui:include src="addressform.xhtml"/>
</p:dialog>
addressform.xhtml
<h:form id="fDlgAddress">
<div id="addresses-container">
<h:messages id="msgDlgAddress" errorClass="errormsg" infoClass="infomsg1" layout="table"/>
<h:panelGrid columns="1"
styleClass="pgAddresses"
rendered="#{!addressform.address.exists}">
<h:outputText value="No active #{addressform.address.atypCode} address found."
styleClass="record-not-exists"/>
<h:outputText value="Use the form below to create one."/>
</h:panelGrid>
<p:panelGrid columns="2"
styleClass="pgDlgForm pgAddresses">
<h:outputLabel value="Address Type"/>
<h:inputText id="atypCode1"
value="#{addressform.address.atypCode}"
disabled="true"
rendered="#{addressform.address.exists}"/>
<h:selectOneMenu id="atypCode2"
value="#{addressform.address.atypCode}"
rendered="#{!addressform.address.exists}">
<f:selectItems value="#{addressform.atypCodeList}"
var="atyp"
itemValue="#{atyp}"
itemLabel="#{atyp}"/>
</h:selectOneMenu>
<h:outputLabel value="Street 1"
for="street1"/>
<h:inputText id="street1"
value="#{addressform.address.addressLine1}"/>
<h:outputLabel value="Street 2"
for="street2"/>
<h:inputText id="street2"
value="#{addressform.address.addressLine2}"/>
<h:outputLabel value="Street 3"
for="street3"/>
<h:inputText id="street3"
value="#{addressform.address.addressLine3}"/>
<h:outputLabel value="Street 4"
for="street4"/>
<h:inputText id="street4"
value="#{addressform.address.addressLine4}"/>
<h:outputLabel value="City"
for="city"/>
<h:inputText id="city"
value="#{addressform.address.city}"
required="true"
requiredMessage="Please enter a city."/>
<h:outputLabel value="State"
for="statCode"/>
<h:selectOneMenu id="statCode"
value="#{addressform.address.stateCode}">
<f:selectItem itemLabel="Select State/Province"
itemValue=""/>
<f:selectItems value="#{states.statesList}"
var="stat"
itemValue="#{stat.statCode}"
itemLabel="#{stat.statDesc}"/>
</h:selectOneMenu>
<h:outputLabel value="Zip Code"
for="zipCode"/>
<h:inputText id="zipCode"
value="#{addressform.address.zip}"/>
<h:outputLabel value="Country"
for="natnCode"/>
<h:selectOneMenu id="natnCode"
value="#{addressform.address.nationCode}"
required="true"
requiredMessage="Please choose a nation.">
<f:selectItem itemLabel="Select Country"
itemValue=""/>
<f:selectItems value="#{nations.nationsList}"
var="natn"
itemValue="#{natn.natnCode}"
itemLabel="#{natn.natnDesc}"/>
</h:selectOneMenu>
<h:outputLabel value="From Date"
for="fromDate"/>
<p:calendar id="fromDate"
value="#{addressform.address.fromDate}"
showButtonPanel="true"/>
<h:outputLabel value="To Date"
for="toDate"/>
<p:calendar id="toDate"
value="#{addressform.address.toDate}"
showButtonPanel="true"/>
<h:outputLabel value="Inactivate"
for="inactivateAddress"
rendered="#{addressform.address.exists}"/>
<h:selectBooleanCheckbox id="inactivateAddress"
value="#{addressform.address.inactivate}"
rendered="#{addressform.address.exists}"/>
<h:outputLabel value="Delete"
for="deleteAddress"
rendered="#{addressform.address.exists}"/>
<h:selectBooleanCheckbox id="deleteAddress"
value="#{addressform.address.delete}"
rendered="#{addressform.address.exists}"/>
</p:panelGrid>
</div>
<div class="button-container">
<p:commandButton value="Save Changes"
action="#{addressform.save}"
type="submit"
ajax="true"
process="#form"
update="#form"/>
<p:commandButton value="Cancel"
process="#this"
onclick="dialogAddress.hide();">
<p:resetInput target="fDlgAddress"/>
</p:commandButton>
</div>
</h:form>
Recorddetailsform (backing bean for form from which address dialog is called)
public void showDlgAddress(){
FacesContext ctx = FacesContext.getCurrentInstance();
ELResolver resolver = ctx.getApplication().getELResolver();
RecordDetails recordDetails = (RecordDetails) resolver.getValue(ctx.getELContext(), null, "recordDetails");
//Set addressform backing bean to new instance and load address into it from recordDetails
resolver.setValue(ctx.getELContext(), null, "addressform", new Addressform());
Addressform addressform = (Addressform) resolver.getValue(ctx.getELContext(), null, "addressform");
addressform.setAddress(recordDetails.getAddress());
}
Addressform (address form's backing bean)
public void save() {
FacesContext ctx = FacesContext.getCurrentInstance();
RequestContext rctx = RequestContext.getCurrentInstance();
ELResolver resolver = ctx.getApplication().getELResolver();
Records records = (Records) resolver.getValue(ctx.getELContext(), null, "records");
RecordDetails recordDetails = (RecordDetails) resolver.getValue(ctx.getELContext(), null, "recordDetails");
Mainform mainform = (Mainform) resolver.getValue(ctx.getELContext(), null, "mainform");
Person person = (Person) resolver.getValue(ctx.getELContext(), null, "person");
//Pretty lengthy SQL stuff here. Commented out. Just wanted to display the display logic below for the dialog.
if (errorMsg != null) {//If errorMsg is not null, then error occurred.
showDlgAddress = true;//Ensures address dialog remains open in event of action error.
queueErrorMessage(errorMsg);
rctx.update("dlgAddress");
return;//break out of method on error.
} else {
showDlgAddress = false;
rctx.update("dlgAddress");
}
//If everything saves without error, repopulate address and update recordDetails dialog.
recordDetails.populateAddress(records.getSelectedRecord());
mainform.updateDlgRecordDetails();
}
Other Info:
JSF2
Primefaces 3.5
Tomcat 6.0
Netbeans
Try this:
Put your dialog inside a form (dialogInputForm)
Add the attribute update=":dialogInputForm"
Nest the resetInput tag within the button that opens the dialog and specify the target as the just created form
The commandButton:
<p:commandButton process="#this" actionListener="#{bean.prepare}" update=":dialogInputForm" oncomplete="thirdPartyDialog.show()" value="Open Input Dialog" >
<p:resetInput target=":dialogInputForm" />
</p:commandButton>
And the form which contais the dialog
<h:form id="dialogInputForm" >
... your dialog ...
</h:form>
This worked for me, place this ajax event in the dialog. When the dialog is closed, the validations will be cleaned
<p:dialog id="dlgAddress"
header="Address Edit"
widgetVar="dialogAddress"
dynamic="true"
modal="false"
closable="false"
resizable="false"
styleClass="dlgAddress"
visible="#{addressform.showDlgAddress}">
<ui:include src="addressform.xhtml"/>
<p:ajax event="close" update="dlgAddress" resetValues="true" />
</p:dialog>

adding row to a p:datatable with requestScope managed bean where i have a form validation

I've read the using-databatables for BalusC and i tried the sample to add a row using request scope but i found a problem is that when i add the
<h:inputHidden binding="#{myBean.dataItemId}" />
all buttons of my page will not work. at first i thought the problem is from the converter
<h:inputHidden binding="#{myBean.dataItemId}" converter="javax.faces.Integer"/>
but also without the converter the same problem i have
second the more interesting is that i didn't understand from the sample code how when adding a new row to the datatable the table gets my added rows before
example if i add the first row and put data the second row while adding i realized that the add function creates a new ArrayList where i think it will deletes the first row
As mentioned in the top "Notice" block of that article, it is targeted on JSF 1.2. Adding a row can much easier be achieved using the JSF 2.0 view scope.
Based on the example given in the JSF 1.2 article, you just need to make 2 changes:
Put the bean in the view scope.
Remove the whole <h:inputHidden> and the addCount property and any references on it.
Here's a kickoff example in JSF 2.0 flavor:
#ManagedBean
#ViewScoped
public class Bean {
private List<Item> items;
#EJB
private ItemService service; // Or just DAO. Whatever you want.
#PostConstruct
public void init() {
items = service.list();
}
public void add() {
items.add(new Item());
}
public void save() {
service.save(items);
}
public List<Item> getItems() {
return items;
}
}
And the view:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:outputText value="#{item.id}" rendered="#{item.id != null}" />
<h:outputText value="new" rendered="#{item.id == null}" />
</h:column>
<h:column>
<h:outputText value="#{item.name}" rendered="#{item.id != null}" />
<h:inputText value="#{item.name}" rendered="#{item.id == null}" />
</h:column>
<h:column>
<h:outputText value="#{item.value}" rendered="#{item.id != null}" />
<h:inputText value="#{item.value}" rendered="#{item.id == null}" />
</h:column>
</h:dataTable>
<h:commandButton value="Add" action="#{bean.add}" />
<h:commandButton value="Save" action="#{bean.save}" />