First my apology. I can't state the question well/clearly enough.
I have a web application built upon jsf 2.x + spring data jpa + hibernate frameworks. There is an editable dataTable in where you could add/remove/update a row. When you click "Add Row" button new instance of car object (entity domain model) is added to a list then when you press save button, it is persisted to database just fine. Very straight forward.
This is foo.xhtml page.
<p:panelGrid>
<p:row>
<p:column>....</p:column>
<p:column>
<h:form id="fooForm">
<p:dataTable id="fooTable" var="c" value="#{fooBean.cars}"
editable="true" rows="10" paginator="true">
......
<f:facet name="footer">
<p:commandButton value="Add Row" actionListener="#{fooBean.addCar}"
update="fooTable" process="#this" />
</f:facet>
</p:dataTable>
<p:commandButton value="Save" action="#{fooBean.save}" update="fooTable" process="#this"/>
</h:form>
</p:column>
</p:row>
</p:panelGrid>
This is bean.
#ManaagedBean
#Viewscoped
public FooBean class implements Serializable {
.....
public void addCar() {
....
}
public void save() {
// use spring abstraction layer to persist entity object
}
Issue I ran into:
However the trouble I am having is once I decided to remove "Save" button from foo.xhtml and
<p:commandButton value="Save" action="#{fooBean.save}" .../>
move save() method inside of addCar() method from the FooBean
public void addCar() {
....
save();
}
The following exception is thrown when I click "Add Row" button and I've been trying to understand why but failed so far.
SEVERE: org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient valu
e: com.yoon.model.Car.age; nested exception is org.hibernate.PropertyValueException: not
-null property references a null or transient value: com.yoon.model.Car.age
Update with self explanatory answer
It turns out to be a programmatic error of mine. When I click on "Add Row" from a table, it should handle only adding an instance of car model with its fields fully entered and add the object to a list. However when I relocated save method inside of addCar method that gets triggered by clicking "Add Row" button, empty car object in where fields are all NULL pushed by hibernate to DB before it grants a chance a user to fill out the required fields. In the table, those fields CAN NOT BE NULLABLE so in turn aforementioned exception was thrown.
I was able to achieve my initial objective of clicking "Add Row" button would capture user input and persist an instance of car to database.
Removing following button
<p:commandButton value="Save" action="#{fooBean.save}" />
Having ajax component.
<p:dataTable ....>
<p:ajax event="rowEdit" listener="#{fooBean.save}" />
....
</p:dataTable>
Related
I am new to JSF 2.0. I got stuck in deleting record from the database. When delete button of a particular record is fired it should delete from database using Hibernate. Here are some snippets attached, help me out.
.XHTML
<ui:repeat var="ruleVar" value="#{repricing.repricingRules}">
<div class="col-md-3">#{ruleVar.name}</div>
<div class="col-md-7">#{ruleVar.description}</div>
<div>
<h:commandLink value="Delete" action="#{repricing.Deleterule}" >
<f:param name="ruleID" value="#{ruleVar.id}"></f:param>
</h:commandLink>
</div>
</ui:repeat>
bean.java
public void Deleterule() {
System.out.println("bean");
String ruleId = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()
.get("ruleID");
}
When I click on this delete button I could not see the word bean in console.From bean I will return the id from Bean->Boimpl->Daoimpl
DaoImpl
public void delete(int rep){
repricingDao.delete("from table where id="+rep);
}
So first I need to send id from JSF page to Bean.
I have two datatables in one jsf page and both are having two different managed beans.
//master table
<p:dataTable id="dataTable" var="req" lazy="true"
value="#{emp.lazyModel}" paginator="true" rows="10"
selection="#{emp.selectedRequest}">
<p:ajax event="rowSelectRadio" listener="#{emp.onRowSelect}" />
<p:column selectionMode=">
<h:outputText value="#{req.empNo}" />
</p:column>
// detail table
<p:dataTable id="Det" var="det" lazy="true"
value="#{dept.lazyModel}" paginator="true" rows="1">
<p:column>
<f:facet name="header">
<h:outputText value="DeptNo" />
</f:facet>
<h:outputText value="#{det.deptNo}" />
</p:column>
Managed beans respectively
// Master table managed Bean
#Named("emp")
#ViewAccessScoped
public class EmployeeManagedBean implements Serializable {
#PostConstruct
public void init() {
initTable();
}
// Detail table managed Bean
#Named("dept")
#ViewAccessScoped
public class DepartmentManagedBean implements Serializable {
#PostConstruct
public void init() {
initTable();
}
initTable() is a method which populates LazyModel for both managed beans
When I select a row in master datatable, I am able to get selected row value in managed bean for first datatable which is EmployeeManagedBean
My question is what is the best approach to populate the second datatable by passing the selected row value of first datatable to second managed bean and thus populate the second datatable? The triggering point to display values in second datable should be based on the selection of a row in first datatable.
Any help is highly appreciable.
Thanks
I am new with this all, but I try doing like this:
pass selected row to second bean (DepartmentManagedBean)
took departments according to selected row
update second datatable, using p:ajax attribute update
<h:dataTable value="#{studentBean2.studentList}" var="student">
<h:column>
<f:facet name="header">
<h:outputText value="STUDENT-ID" />
</f:facet>
<h:outputText value="#{student.studentId}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="STUDENT-NAME" />
</f:facet>
<h:inputText value="#{student.studentName}" />
</h:column>
.........
.........
</h:dataTable>
<h:commandButton type="submit" action="#{studentBean2.action}" value="ENTER" />
As from the above code, datatable values can be edited in <h:inputText> field and submitted. Those edited values are seen in action() method of bean StudentBean2.
As I followed the log, it showed that when I submit the page in the phase "Apply Request Values" the getStudentList() method is called. In this method I do the JDBC call to fetch students from the Database and set the newly fetched studentlist.
But in the "Invoke Application" phase, in method action() I get the edited data in the list which I have submitted. How exactly does this happen?
JSF has set them for you during the update model values phase. During this phase, the processUpdates() method of every component will be invoked. In case of the <h:dataTable> it's the UIData#processUpdates(). For every row it will then invoke the same method of the input component, which is in your case UIInput#processUpdates().
Basically:
get data model of UIData; // studentList = studentBean2.getStudentList()
for (every row of data model) {
get the current row item by index; // student = studentList.get(index)
for (every child UIInput component of UIData) {
set its value; // student.setStudentName(value)
}
}
Unrelated to the concrete problem, doing the JDBC call inside the getter method is a bad idea. The getter method will be called more than once during bean's life, so the JDBC call will be unnecessarily made too many times. You should make the JDBC call in bean's (post)constructor instead. See also Why JSF calls getters multiple times.
I am Using JSF 2 and EJB 3.1 to create a form.
I am using this part of the page to get me some data, so I can pass it to my bean using the confirmDialog just below
<p:column headerText="#{bundle.edit}" style="width:10px; overflow:visible;">
<p:rowEditor/>
</p:column>
<p:column headerText="#{bundle.delete}" style="width:10px; overflow:visible;">
<p:commandButton update=":form" oncomplete="confirmation.show()"
image="ui-icon ui-icon-close" title="Delete">
<f:param value="#{user}" name="userAction" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:confirmDialog message="Are you sure? user:#{param['userAction']} " width="500"
header="Confirm" severity="alert" widgetVar="confirmation">
<p:commandButton value="Yes sure" update=":form"
actionListener="#{userController.deleteAction(param['userAction'])}"
oncomplete="confirmation.hide()" />
<p:commandButton value="Not yet" onclick="confirmation.hide()" type="button" />
</p:confirmDialog>
</h:form>
And this is the Bean that should get it
#Named(value = "userController")
#Stateful
#RequestScoped
#TransactionManagement(TransactionManagementType.CONTAINER)
public class UserController implements Serializable {
private User current;
#Inject
private br.com.cflex.itm.dataaccess.UserFacade userFacade;
public UserController() {
}
public void deleteAction(User user) {
userFacade.remove(user);
}
But My bean is only receiving null as User, and in the Dialog I am printing the data so I can see there is a User Object selected there.
What is wrong in passing params like that ?
Why am I getting null in my Bean? Because they are getting lost in the communication between client and server-side...
<p:commandButton action="#{userController.deleteAction(param['userAction'])}" />
The EL of action (and actionListener) is evaluated when the form is been submitted, not when the form is been displayed. Request parameters are request scoped and are not there in the subsequent request of the form submit. You need to pass it along:
<p:commandButton action="#{userController.deleteAction(param['userAction'])}">
<f:param name="userAction" value="#{param['userAction']}" />
</p:commandButton>
The EL of <f:param> is evaluated when the form is been displayed. So it will be there in the generated HTML and JavaScript will take care that it is passed along.
Note that request parameters are of String type. Expecting them to be User won't work at all. Basically, it contains the value of User#toString(). You'd need to take String as action argument and convert it to User yourself. Or better, use <f:viewParam> wherein you can explicitly specify a converter.
I have a problem using HtmlDataTable for viewing data from database.
When I create component, the table has sometimes (not always) twice number of columns.
It is shown correctly and after several refreshes (without move in dtb or something) there is for example 6 columns instead of 3 and application (sometimes) become unstable.
Since this time I can't work with table because it reports "duplicate Id for a component"..
Simple example (source: http://balusc.blogspot.com/2006/06/using-datatables.html):
<h:form id="bde">
<h:dataTable id="tbl"
binding="#{myBDE.dataTable}"
value="#{myBDE.dataList}"
var="bdeItem">
<h:column>
<f:facet name="header">
<h:outputText value="S" />
</f:facet>
<h:outputText value="#{bdeItem.s}" rendered="#{!myBDE.editModeRow}"/>
<h:inputText value="#{bdeItem.s}" rendered="#{myBDE.editModeRow}" required="true" size="3"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="ID" />
</f:facet>
<h:outputText value="#{bdeItem.id}"/>
</h:column>
</h:dataTable>
</h:form>
And java.class
protected HtmlDataTable dataTable;
public void setDataTable(HtmlDataTable dataTable)
{
this.dataTable = dataTable;
}
public HtmlDataTable getDataTable()
{
if (dataTable == null)
{
dataTable = new HtmlDataTable();
dataTable.setRows(DEFAULT_TABLE_ROWS);
}
return dataTable;
}
And the Error message:
javax.servlet.ServletException: Component ID j_idt92:bde:tbl:j_idt129 has already been found in the view.
javax.faces.webapp.FacesServlet.service(FacesServlet.java:422)
root cause
java.lang.IllegalStateException: Component ID j_idt92:bde2:tbl:j_idt129 has already been found in the view.
com.sun.faces.util.Util.checkIdUniqueness(Util.java:821)
com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
com.sun.faces.application.view.StateManagementStrategyImpl.saveView(StateManagementStrategyImpl.java:144)
com.sun.faces.application.StateManagerImpl.saveView(StateManagerImpl.java:133)
com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:225)
com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:418)
com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:410)
Followed by tree of components.
I thing there's nothing duplicated in code, but dataTable create a new columns and after that it's really duplicated
I have two working similar modules, and the third doesn´t work.
Have you ever met this kind of problem?
Thanks for advice
This can happen if the bean is session scoped instead of request scoped and you're sharing this bean among multiple views. Best is to keep the bean to which the component is been bound in the request scope.
As an alternative, you can also use DataModel as value instead of binding the table to HtmlDataTable if the functional requirement is to get the currently selected row.