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.
Related
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.
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.
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 would like to do a register form which works fine:
<h:form id="register_form">
<h:panelGrid columns="3">
<h:outputLabel for="email" value="E-mail:" />
<h:inputText id="email" value="#{userc.userb.user.email}">
<f:ajax event="blur" render="m_email" />
</h:inputText>
<h:message id="m_email" for="email" ajaxRendered="false" />
<h:outputLabel for="password" value="Passoword" />
<h:inputSecret id="password" value="#{userc.userb.user.password}">
<f:validator validatorId="confirmPasswordValidator" />
<f:attribute name="confirm" value="#{confirmPassword.submittedValue}" />
</h:inputSecret>
<h:message id="m_password" for="password" />
<h:commandButton value="Registerr" action="#{userc.register}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:messages globalOnly="true" layout="table" />
</h:panelGrid>
</h:form>
And this is my controller:
public void register(){
FacesMessage message;
try {
userb.encryptPassword();
userEAO.create(userb.getUser());
message = new FacesMessage("Register successfully!");
FacesContext.getCurrentInstance().addMessage(null, message);
} catch (Exception e) {
// 1062 : duplicate entry
if (e.getMessage().contains("Duplicate")){
message = new FacesMessage("User already registered, please try another email");
FacesContext.getCurrentInstance().addMessage(null, message);
}else{
message = new FacesMessage("An error occured, try again please");
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
}
So, for example, if some user try to register himself twice, I return this message, saying that's duplicate, but I wonder if this is the best approach.
How to treat these kinds of exceptions?
Those validations should be handled by your Business Logic Layer object, in this case, it looks like it is the userEAO object. You can decide if you should handle this error messages in the flavor of Exceptions (which IMHO won't use).
In my case, I prefer to use a Message class that basically contains an integer code and a message holding the results of the operation. For my case, I usually return 0 or more to indicate the operation was successful, and use negative codes to declare errors. This is a pretty basic example:
public class Message {
private int code;
private String message;
//constructor...
//getters and setters...
}
public class UserBL {
public Message create(User user) {
//do some fancy validations
if (!verifyDuplicatedUser(user)) {
return new Message(-1000, "Duplicated user");
}
//and the operations...
saveUser(user);
return new Message(0, "Register successfully!");
}
}
Now your controller will be forward to what it must really do (this means, no heavy business logic validations):
public void register() {
FacesMessage fmessage;
userb.encryptPassword();
Message message = userEAO.create(userb.getUser());
fmessage = new FacesMessage(message.getMessage());
FacesContext.getCurrentInstance().addMessage(null, fmessage);
}
This approach can even help you when you should validate a set of data, like validating the results of an Excel sheet and you must show a list of errors (because showing a single error lot of times is very annoying!).
You can improve the way you create the messages, like retrieving them from a table with the messages for your system, or using properties files to handling internationalization (that depends on your functional requirements, of course).
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.