I have a dataTable with a list of items and a checkbox for selecting an item to edit. Ticking an item and clicking the edit button pops up a component which has fields and update and cancel buttons. Here's what happens.
Dialog appears
I empty all fields and click UPDATE, required messages appear since all fields are empty, data is not saved
Click CANCEL, dialog disappears
Click and edit the same item again
Some fields are not showing. I checked the datatable and database, data for the item still exists. Just not showing on the edit dialog the 2nd time around.
I noticed that the fields not showing are only those that have NULL attributes. NOT NULL fields are fine. I wonder if this has something to do with sessions. (Using Primefaces for all components)
Code for the edit dialog
<p:dialog header="#{bundle.Edit}" modal="true" widgetVar="editDialog" resizable="false">
<h:form id="edit-form">
<p:messages id="edit-error" autoUpdate="true" closable="true"/>
<h:outputLabel value="#{bundle.Name}" for="name" /><span class="required">*</span>
<p:inputText id="name" value="#{controller.selected.name}" required="true" requiredMessage="#{bundle.Name} #{bundle.FieldIsRequired}" maxlength="45"/>
<h:outputLabel value="#{bundle.Input}" for="input" /><span class="required">*</span>
<h:selectOneRadio id="input" value="#{controller.selected.input}" required="true" requiredMessage="#{bundle.Input} #{bundle.FieldIsRequired}">
<f:selectItem itemLabel="◯ " itemValue="0" />
<f:selectItem itemLabel="☓ " itemValue="1" />
</h:selectOneRadio>
<h:outputLabel value="#{bundle.IsOption}" for="isOption" /><span class="required">*</span>
<h:selectOneRadio id="isOption" value="#{controller.selected.isOption}" required="true" requiredMessage="#{bundle.IsOption} #{bundle.FieldIsRequired}">
<f:selectItem itemLabel="◯ " itemValue="0" />
<f:selectItem itemLabel="☓ " itemValue="1" />
</h:selectOneRadio>
<h:outputLabel value="#{bundle.Remark}" for="remark" />
<p:inputTextarea id="remark" value="#{controller.selected.remark}"/>
<p:commandButton action="#{controller.update()}"
value="#{bundle.Save}"
actionListener="#{controller.prepareList()}"
oncomplete="handleEditDialog(xhr, status, args)"
update=":form:datatable :edit-form:edit-error"
/>
<p:commandButton value="#{bundle.Cancel}"
onclick="editDialog.hide(); reset();"
type="button"/>
</h:form>
</p:dialog>
Code for the update function
public String update() {
RequestContext context = RequestContext.getCurrentInstance();
try {
current.setUpdateDate(new Date());
Map<String, Object> param = JsfUtil.getExternal().getSessionMap();
int createUser = (Integer) param.get("LOGIN_ID");
Account account = accountFacade.find(createUser);
current.setUpdateUser(account);
getFacade().edit(current);
search();
prepareList();
JsfUtil.addSuccessMessage(ResourceBundle.getBundle(JsfUtil.getSessionBundle()).getString("Updated"));
updateOk = true;
current = null;
context.addCallbackParam("updated", true);
return "";
} catch (Exception e) {
if (e.getCause().getCause().getMessage().contains("uk_")) {
JsfUtil.addErrorMessage("edit-form:edit-error",JsfUtil.getResourceString("Duplicate"));
context.addCallbackParam("updated", false);
} else {
JsfUtil.addErrorMessage(e, ResourceBundle.getBundle(JsfUtil.getSessionBundle()).getString("PersistenceErrorOccured"));
context.addCallbackParam("updated", false);
}
return null;
}
}
Based on what you are describing I think the following scenario is happening. When you see the form and you delete all fields and you hit save, the components that have no validators are actually overwriting some of the previous property values of your bean. That's why when you reload it for a second edit, you'll notice that all the components that have a validator attached (e.g required = true) are appearing but those with no validators are blank. In reality, you are actually doing a partial update. What you actually need to do is mark all fields as required to avoid that problem.
My teammate just found out a fix for this one. There is a function on the controller generated by NetBeans called prepareList().
public String prepareList() {
recreateModel();
return "";
}
private void recreateModel() {
items = null;
}
Basically we added this on catch block of the update() function. It is called after every unsuccessful update and recreates the model. The bug existed because the field retained its state of not having a value after an unsuccessful update.
Related
Cant understand <h:selectOneMenu> component. Tried many ways to pass parameter from dropdown to java, and 4 different ways to call java method. First two ways (onchange and commandbutton doesnt call java) other two does, but works badly as it cant set selectedItem to java variable:
<h:form id="tasks">
<h:selectOneMenu id = "selectonemenu" value="#{services.selectedItem}"
immediate="true" onchange="javascript: return this.form.submit();">
<f:selectItems value="#{services.selectItems}" />
</h:selectOneMenu>
<h:commandButton value = "StringHello" action="#{services.StringHelo}" />
<s:link action="#{services.StringHello}" reRender="tasks"></s:link>
<a:commandLink id="aclink"
action="#{services.StringHello}"
ajaxSingle="true" eventsQueue="globalQueue"
ignoreDupResponses="true" requestDelay="0"
onComplete="return false;"
status="globalStatus">
aclink
</a:commandLink>
<h:outputText id = "valueofselected" value = "#{services.selectedItem}"/>
</h:form>
And Services.Java:
private String selectedItem;
public String getSelectedItem() {
if (selectedItem == null) {
selectedItem = "All"; // This will be the default selected item.
}
System.out.println("getSelectedItem "+selectedItem);
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
System.out.println("setSelectedItem");
}
public List getSelectItems() {
List selectItems = new ArrayList();
selectItems.add(new SelectItem("All", "All"));
selectItems.add(new SelectItem("A", "A"));
selectItems.add(new SelectItem("B", "B"));
selectItems.add(new SelectItem("C", "C"));
selectItems.add(new SelectItem("D", "D"));
System.out.println("getSelectItems: "+selectItems.size());
return selectItems;
}
public void StringHello(){
System.out.println(" SelectedItem - "+selectedItem);
}
returns null in console:
14:41:51,897 INFO [STDOUT] SelectedItem - null
but i can see that outputText's value is always "All" and in console i see every time when getSelectedItem method is called:
14:41:49,087 INFO [STDOUT] getSelectedItem All
Also, i think it's very important: after i choose any value, page refreshes and it becomes default 'All' value again.
Do you really want to send the whole form (do a form submit)?
Try this, there should be no page refresh:
<h:form id="tasks">
<h:selectOneMenu value="#{services.selectedItem}">
<f:selectItems value="#{services.selectItems}" />
<f:ajax execute="#this" render="result"/>
</h:selectOneMenu>
<h:outputText id="result" value="#{services.selectedItem}"/>
</h:form>
#ujulu was right, i created separate java class with #Scope(ScopeType.SESSION) and my form was located at wrong place, i moved it higher in hierarchy, to get rid of any parent components. And it works now.
I have a popup in which you have to select components for you pc. Each component contains a label and a drop down list with all the selected components in the database. Next to the list there is an 'add' button, when clicked it give another popup, which is used when the user does not find what he wants in the list. The add function calls a method which checks the input of the user for already existing inputs and adds if there is none. MY PROBLEM: is that I can not find a solution for refreshing the list which was updated. I am trying to use <p:ajax /> but I keep getting Cannot find component errors.
---HTML CODE----
<form id="dialog">
<h:outputText value="Computer: " styleClass="dialog-labels" />
<ul style="list-style-type: none">
<li>
<div class="dialog-container">
<h:outputLabel value="Processor: " style="float:left;" />
<p:selectOneMenu id="procs" filterFunction="true" filterMatchMode="true" styleClass="dialog-dropdown-list" style="width:15em;">
<f:selectItem itemLabel="Select Processor" itemValue="" noSelectionOption="true" />
<f:selectItems id="list" value="#{javaHTMLConnection.procList}" />
</p:selectOneMenu>
<p:commandButton value="Add" id="addProc" styleClass="dialog-buttons" onclick="PF('addProcBox').show();" style="font-size: 10px;" />
<h:form id="popUp">
<p:dialog header="Add Processor" widgetVar="addProcBox" height="200" width="180" draggable="false" resizable="false" style="font-size:13px;">
<h:outputLabel value="Processor: " style="float:left;" />
<p:inputText id="procInput" value="#{components.procID}"/>
<p:growl id="growl" life="10000" />
<p:commandButton value="Save" styleClass="dialog-bottom-buttons" action="#{components.addProcessor()}" update="growl" onclick="PF('addProcBox').hide();" style="font-size: 10px;" />
<p:ajax listener="#{javaHTMLConnection.onAdd()}" update=":dialog:list" />
<p:commandButton value="Cancel" id="CancelAddProc" styleClass="dialog-bottom-buttons" onclick="PF('addProcBox').hide();" style="font-size: 10px;" />
</p:dialog>
</h:form>
</div>
</li>
</form>
----JavaHTMLConnection----
public void onAdd()
{
if(components.addProcessor()==true)
{
components.getAllComponents();
}
}
----Components(Java code)----
public boolean addProcessor()
{
try
{
db.openDatabase();
db.con.setAutoCommit(false);
if (!db.ifExists("processor.name", "processor", procID))
{
db.Entry("processor", procID);
addMessage("Success ! Your input has been saved");
return true;
}
else
{
addMessage("Error, the input already exists");
}
}
catch (SQLException e)
{
try
{
db.con.rollback();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
finally
{
try
{
db.con.setAutoCommit(true);
}
catch (SQLException e)
{
e.printStackTrace();
}
}
return false;
}
P.S.: Don't mind the naming as when this will be figured out everything will be made generic as I need to adapt this to 15 more components
As Emil already mentioned, nested forms are a really bad thing which you should get rid of immediately.
Also, as Emil suggested, that kind of error message is usually related to incorrect component-selectors. Those are mainly caused due to the fact that a parent naming container is missing in the selector. Either determine the correct id using some debugging tool or, instead of
<p:ajax listener="#{javaHTMLConnection.onAdd()}" update=":dialog:list" />
try using some of the solutions suggested in this thread: Primefaces - Cannot find component with identifier outside the datatable
I personally prefer to use the following syntax, which relies on a primefaces-method searching for an id in various naming containers:
<p:ajax listener="#{javaHTMLConnection.onAdd()}" update=":#{p:component('list')}" />
First of all, you have nested forms, which you should get rid of.
As for question you should inspect the specific html element (for example by using firebug) to find out the id of it.
Hi I have read tons of similar questions but the answers didnt work for me.
I have this
<p:selectOneMenu id="tipoTaxon" value="#{taxonDM.taxon.tipoTaxon}"
name="tipoTaxon">
<f:converter converterId="tipoTaxonConverter" />
<f:selectItem itemLabel="Seleccione uno" itemValue="0" />
<f:selectItems value="#{tipoTaxonDM.tiposTaxones}" var="txn"
itemValue="#{txn.idTipoTaxon}" itemLabel="#{txn.nombreTipo}" />
<p:ajax render="test" />
</p:selectOneMenu>
<p:inputText id="test" rendered="#{taxonDM.taxon.tipoTaxon != null}" />
As you can see I want to render test when an option is selected. tipoTaxon is basically a table on my database and is class, so I had to make a converter. It seems to work so for now, I am not getting the errors I had before. Now I dont get any errors but "test" is not getting rendered.
I tried the following
#{taxonDM.taxon.tipoTaxon != null}
also
#{taxonDM.taxon.tipoTaxon.idTipoTaxon != null}"
I tried setting test on another panel
<h:panelGrid columns="2" id="formTaxon">
<h:outputLabel value="Nombre Científico Taxón" for="taxonInput" />
<p:inputText value="#{taxonDM.taxon.nombreCientificoTaxon}"
id="taxonInput" />
<h:outputLabel value="Nombre Común" for="nombreComunInput" />
<p:inputText value="#{taxonDM.taxon.nombreComunTaxon}"
id="nombreComunInput" />
<h:outputLabel value="Tipo" for="tipoTaxon" />
<p:selectOneMenu id="tipoTaxon" value="#{taxonDM.taxon.tipoTaxon}"
name="tipoTaxon">
<f:converter converterId="tipoTaxonConverter" />
<f:selectItem itemLabel="Seleccione uno" itemValue="0" />
<f:selectItems value="#{tipoTaxonDM.tiposTaxones}" var="txn"
itemValue="#{txn.idTipoTaxon}" itemLabel="#{txn.nombreTipo}" />
<p:ajax render="formTaxon2" />
</p:selectOneMenu>
</h:panelGrid>
<h:panelGrid columns="2" id="formTaxon2">
<p:inputText id="test" rendered="#{taxonDM.taxon.tipoTaxon != null}" />
</h:panelGrid>
using render="test" or render="formTaxon2"
I added a listener method to p:ajax and it worked so i know it is getting invoked.
public void tipoTaxonesXX(AjaxBehaviorEvent e){
System.out.println("Working");
}
It did printed "Working" on my console.
My form is not saving either so I guess it has trouble transforming from tipotaxon or number, but it gets null, i ll fix that later.
Here is the converter if someone needs to
import ec.edu.puce.biologia.model.TipoTaxon;
#FacesConverter("tipoTaxonConverter")
public class TipoTaxonConverter implements Converter {
private TipoTaxonDao tipoTaxonDao;
#Override
public Object getAsObject(final FacesContext arg0, final UIComponent arg1,
final String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
try {
TipoTaxon tipoTaxon = tipoTaxonDao.recuperar(Long.valueOf(value));
System.out.println("Getting the operation value = "
+ tipoTaxon.getNombreTipo());
return tipoTaxon;
} catch (NumberFormatException e) {
return null;
// throw new ConverterException(new
// FacesMessage("Unknown operation ID: " + value));
} /*
* catch (EntidadNoEncontradaException e) { throw new
* ConverterException(new FacesMessage("Unknown operation ID: " +
* value)); }
*/
}
#Override
public String getAsString(final FacesContext arg0, final UIComponent arg1,
final Object value) {
if (!(value instanceof TipoTaxon)
|| ((TipoTaxon) value).getIdTipoTaxon() == null) {
return null;
}
return String.valueOf(((TipoTaxon) value).getIdTipoTaxon());
}
}
I need to put some exceptions
UPDATE ANSWER
My code here has many errors, I changed it a lot, but the main problem was that the EJB on the converter didnt work. I ended up using ManagedBean. More on that here http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#ProcessingGETRequestParameters
As I said in my previous answer to your question, both <p:selectOneMany> value must point to your user class, TipoTaxon, and every <f:selectItem>/<f:selectItems> itemValue must also point that same user class, TipoTaxon.
As you see, neither itemValue="0", nor itemValue="txn.nombreTipo" satisfies the abovementioned statement. Correct it and see it working.
My advice for future postings will be to post the complete, relevant and necessarily formatted code, which in your case includes converter code, your model class and managed bean parts. Also, do not post the same question twice/thrice, etc. and instead try to work it out on your own, otherwise it'll be closed as duplicate.
I'm having trouble with passing a single value from the data table to the backing bean. I always get the value of 0 when I try to print it in the method in the confirm dialog but when I try to print it in the method in the command button, it shows the value that I need. I think it resets the value or whatever.
<p:dataTable id="labLists" var="lab" value="#{coltsysHome.laboratory}" >
.....
<p:column headerText=" ">
<p:commandButton value="DELETE" onclick="confDlg.show()" icon="ui-icon-closethick" action="#{coltsysHome.action}">
<f:setPropertyActionListener value="#{lab.lab_id}" target="#{coltsysHome.lab_id_del}" />
</p:commandButton>
</p:column>
For the confirm dialog:
<p:confirmDialog widgetVar="confDlg" header="DELETE LABORATORY" message="Are you sure you want to delete this lab?">
<h:form id="delDlgForm">
<p:commandButton id="confirm" value="Yes Sure" oncomplete="confDlg.hide()" actionListener="#{coltsysHome.deleteLab(event)}"/>
<p:commandButton id="decline" value="Not Yet" onclick="confDlg.hide()" type="button" />
</h:form>
Bean (RequestScoped):
...getter and setter (lab_id_del)
public void deleteLab(ActionEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
String cpath = context.getExternalContext().getRequestContextPath();
try (Connection conn = dataSource.getConnection()) {
ColtsysDAO coltsysDAO = new ColtsysDAO(conn);
coltsysDAO.deleteLab(lab_id_del, coltsysDAO.getUserID(getUser_name()));
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
public void action() {
System.out.println("lab_id_del: " + lab_id_del);
}
The first and foremost change you need to do is: RequestScoped->ViewScoped as Luiggi Mendoza has suggested. you might need to add process attribute to the p:commandButton with the id of the p:dataTable. Also you can pass the lab object directly into action method without using f:setPropertyActionListener as: action="#{coltsysHome.action(lab)}" and take it as: public String action(Lab lab). Why not actionListener!
I have a p:dataGrid that used to update itself in 3.0.1. Now I upgraded to PF 3.1 and the ajax update event of the "availableIcons" component does not fire anymore. I don't get an error that the component is not found in the view.
The XHMTL
<h:form id="Application">
......
<p:confirmDialog id="iconDialog" message="Select one icon"
showEffect="bounce" hideEffect="explode" header="Icon Selection"
severity="alert" widgetVar="iconSelect" modal="false">
<p:dataGrid id="availableIcons" var="icon"
value="#{appEditController.availableIcons}" columns="4">
<p:column>
<p:panel id="pnl" header="" style="text-align:center">
<h:panelGrid columns="1" style="width:100%" id="iconPanelGrid">
<p:graphicImage value="/resources/icons/#{icon.icon}"
id="iconImage" />
<p:selectBooleanCheckbox id="iconSelector"
value="#{icon.selected}"
disabled="#{appEditController.isIconSelected(icon)}">
<p:ajax update="availableIcons" event="change"
process="availableIcons"
listener="#{appEditController.iconSelectedChanged(icon)}" />
</p:selectBooleanCheckbox>
</h:panelGrid>
</p:panel>
</p:column>
</p:dataGrid>
<p:commandButton value="Done" update="currentIcon"
action="#{appEditController.updateCurrentIcon}" ajax="false"
oncomplete="iconSelect.hide()" />
</p:confirmDialog>
.......
</h:form>
I don't see what's missing or what's incorrect.
This is the backing bean code
public void updateCurrentIcon() {
for (IconVO iconVO : availableIcons) {
if (iconVO.isSelected()) {
log.debug("CURRENT ICON IS NOW " + iconVO.getIcon());
currentIcon = iconVO;
break;
}
}
}
public void iconSelectedChanged(IconVO iconVO) {
if (iconVO == currentIcon) {
log.debug("NULLING ICON");
currentIcon = null;
} else {
log.debug("SETTING NEW ICON");
currentIcon = iconVO;
}
}
public boolean isIconSelected(IconVO iconVO) {
log.debug("IS ICON SELECTED " + iconVO.getIcon());
if (currentIcon == null
|| iconVO.getIcon().equals(currentIcon.getIcon())) {
return false;
}
return currentIcon != null;
}
I tried to do update="#form", then the update fires but it closes the modal panel completely.
Thanks,
Coen
Indeed, the way how PrimeFaces locates components by relative client ID has been changed in PrimeFaces 3.1 to adhere the UIComponent#findComponent() javadoc.
In your particular case, you need to specify the absolute client ID of the <p:dataGrid> instead. Easiest way to figure it is to check the ID of the <p:dataGrid> in the generated HTML source. With the code given so far, that would be Application:availableIcons. You need to prefix it with : to make it absolute and then reference it in update as follows:
<p:ajax update=":Application:availableIcons" ... />
Update as per the comments it turns out to not work at all. You could try wrapping the table in some invisible containing component like <h:panelGroup> and update it instead. Alternatively, you could consider moving the <h:form> into the dialog and use update="#form" instead. Having the <h:form> outside the dialog is kind of odd anyway. You surely won't submit all the other inputs which are outside the dialog inside the same form.