JSF links in table not updating, sorting not swapping - jsf

I have a table displayed. When the user clicks on the headers i want the table to reorganise itself, sorted according to the selected header. Clicking on the same header again, swaps the order of sorting
Within the table, there are several commandLinks.
Now, the problems are as follows
the first update to the sorting order happens, but clicking on the header again will not swap the order.
When the table is refreshed, the links have their value changed, but the link still maps to the object that was previously there
Code:
Table:
<h:form title="table">
<h:dataTable value="#{employee.employeeList}" var="a"
styleClass="order-table" headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
style="width:100%">
<h:column>
<f:facet name="header"><h:commandLink value="Number" action="#{employee.sortByNumber()}" /></f:facet>
<h:commandLink value="#{a.number}" action="#{employee.setEmp(a)}" />
</h:column>
...
...
...
</h:dataTable>
</h:form>
Employee Bean:
public String filter = ""; //has getters and setters
public String order = ""; //has getters and setters
public static final String ORDER_ASCENDING = "asc";
public static final String ORDER_DESCENDING = "desc";
public static final String FILTER_NUMBER = "number";
public void sortByNumber(){
if(filter.equals(FILTER_NUMBER)){
swapOrder();
}else{
filter = FILTER_NUMBER;
order = ORDER_ASCENDING;
}
refreshPage();
}
public void swapOrder(){
if(order.equals(ORDER_ASCENDING)){
order = ORDER_DESCENDING;
}else{
order = ORDER_ASCENDING;
}
}
public void refreshPage(){
FacesContext context = FacesContext.getCurrentInstance();
String viewId = context.getViewRoot().getViewId();
ViewHandler handler = context.getApplication().getViewHandler();
UIViewRoot root = handler.createView(context, viewId);
root.setViewId(viewId);
context.setViewRoot(root);
}
public String setEmp(Employee employee) {
this.employee = employee;
return "details"; //redirects to the details page where the employee set in the previous line is used
}

Related

JSF PrimeFaces Extensions Timeline: How to update a Timeline via AJAX?

I'm having a hard time doing basic AJAX updates of a timeline.
Let me start with a basic example where I want to update the start and end times of a timeline based on the selection of a dropdown list:
<h:form id="form">
<h:outputLabel for="period" value="#{str.schedule_period}"/>
<h:selectOneMenu id="period" value="#{timelineController.period}" label="#{str.schedule_period}">
<f:selectItems value="#{timelineController.periodWeeks}" />
<p:ajax event="change" update="timeline" />
</h:selectOneMenu>
<pe:timeline id="timeline" value="#{timelineController.model}"
editable="true"
eventMargin="0"
minHeight="120"
stackEvents="false"
start="#{timelineController.timelineStart}"
min="#{timelineControllertimelineStart}"
end="#{timelineController.timelineEnd}"
max="#{timelineController.timelineEnd}"
showNavigation="false" showButtonNew="false"
showCurrentTime="false"
axisOnTop="true"
timeZone="#{timelineController.timezone}"
zoomMin="28800000"
dropActiveStyleClass="ui-state-highlight" dropHoverStyleClass="ui-state-hover">
<p:ajax event="drop" listener="#{timelineController.onDrop}"
global="false" process="timeline"/>
</pe:timeline>
</h:form>
When I select an item in the dropdown list, an AJAX event fires and sets the period property in the backing bean, but the new value is not reflected in the timeline component. As a workaround, I wrapped the timeline in a p:outputPanel and updated the wrapper instead and it works:
...
<h:selectOneMenu id="period" value="#{timelineController.period}" label="#{str.schedule_period}">
<f:selectItems value="#{timelineController.periodWeeks}" />
<p:ajax event="change" update="wrapper" />
</h:selectOneMenu>
...
<p:outputPanel id="wrapper">
<pe:timeline id="timeline" value="#{timelineController.model}"
editable="true"
eventMargin="0"
minHeight="120"
stackEvents="false"
start="#{timelineController.timelineStart}"
min="#{timelineControllertimelineStart}"
end="#{timelineController.timelineEnd}"
max="#{timelineController.timelineEnd}"
showNavigation="false" showButtonNew="false"
showCurrentTime="false"
axisOnTop="true"
timeZone="#{timelineController.timezone}"
zoomMin="28800000"
dropActiveStyleClass="ui-state-highlight" dropHoverStyleClass="ui-state-hover">
<p:ajax event="drop" listener="#{timelineController.onDrop}"
global="false" process="wrapper"/>
</pe:timeline>
</p:outputPanel>
Note that I also had to change the process attribute of p:ajax to wrapper.
So my first question is: why doesn't the update work without wrapping the timeline component?
My second question is about drag and drop. As you can you see from my code above, I have attached a drop listener to the timeline. And I'm also able to drag and drop events from a p:dataList BEFORE I make a selection in the dropdown list. Once I select a new period in the dropdown list, the timeline gets updated appropriately, but I'm not able to drag and drop events to the timeline any more (the onDrop listener doesn't get fired). Here's my p:dataList:
<p:dataList id="eventsList" value="#{timelineController.users}"
var="user" itemType="none">
<h:panelGroup id="eventBox" layout="box" style="z-index:9999; cursor:move;">
#{user.toString()}
</h:panelGroup>
<p:draggable for="eventBox" revert="true" helper="clone" cursor="move"/>
</p:dataList>
Any ideas what's wrong here?
I'm also including the TimelineController class for reference:
#ManagedBean
#ViewScoped
public class TimelineController {
#EJB UserService userDao;
private TimelineModel model;
private String name;
private ZoneId timezone;
private Period period;
private Duration defaultShiftDuration;
private LocalDateTime timelineStart;
private LocalDateTime timelineEnd;
#PostConstruct
protected void initialize() {
timezone = ZoneId.of("Europe/Berlin);
period = Period.ofWeeks(2);
defaultShiftDuration = Duration.ofHours(8);
timelineStart = LocalDateTime.now().with(DayOfWeek.MONDAY).withHour(0).withMinute(0).truncatedTo(ChronoUnit.MINUTES);
// create timeline model
model = new TimelineModel();
}
public TimelineModel getModel() {
return model;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTimezone() {
return timezone.getId();
}
public void setTimezone(String timezone) {
this.timezone = ZoneId.of(timezone);
}
public List<SelectItem> getPeriodWeeks() {
List<SelectItem> weeks = Lists.newArrayList();
weeks.add(new SelectItem(1, "1 " + JsfUtil.getStringResource("schedule_week")));
weeks.add(new SelectItem(2, "2 " + JsfUtil.getStringResource("schedule_weeks")));
weeks.add(new SelectItem(3, "3 " + JsfUtil.getStringResource("schedule_weeks")));
return weeks;
}
public int getPeriod() {
return period.getDays() / 7;
}
public void setPeriod(int nWeeks) {
this.period = Period.ofWeeks(nWeeks);
timelineEnd = null;
}
public Date getTimelineStart() {
return Date.from(timelineStart.atZone(timezone).toInstant());
}
public Date getTimelineEnd() {
if (timelineEnd == null) {
timelineEnd = timelineStart.plus(period);
}
return Date.from(timelineEnd.atZone(timezone).toInstant());
}
public void setStartsOn(String startsOn) {
timelineStart = LocalDateTime.parse(startsOn + "T00:00");
timelineEnd = null;
}
public List<User> getUsers(){
return userDao.findAll();
}
public void onDrop(TimelineDragDropEvent e) {
// get dragged model object (event class) if draggable item is within a data iteration component,
// update event's start and end dates.
User user = (User) e.getData();
Date endDate = Date.from(e.getStartDate().toInstant().plus(defaultShiftDuration));
// create a timeline event (not editable)
TimelineEvent event = new TimelineEvent(user, e.getStartDate(), endDate, true, e.getGroup());
// add a new event
TimelineUpdater timelineUpdater = TimelineUpdater.getCurrentInstance(":form:timeline");
model.add(event, timelineUpdater);
}
}
The problem was a missing widgetVar attribute in the timeline component. This looks like a bug to me, since I'm not using the client side API of the component. I will file a bug in PF Extensions project.

how to get the index of data from data Table in jsf? [duplicate]

This question already has answers here:
How can I pass selected row to commandLink inside dataTable or ui:repeat?
(4 answers)
Closed 7 years ago.
I am new to java ee and dont have much idea about jsf and all. I am making a simple java web application that fetches data from database and shows in dataTable. I need to edit data selected by user from dataTable for which i need to get value of the row selected/clicked. But i havent been able to do it. Can any one please help me with my code ? I hope someone would tell me how can i do it with my following codes.
showRecords.xhtml
h:dataTable value="#{studentList.studentL()}" var="student" styleClass="studentTable"
columnClasses=",,,fixedWidth">
<h:column>
<f:facet name="header">Student ID</f:facet>
<h:outputText value="#{student.studentId}"></h:outputText>
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{student.fname}"></h:outputText>
</h:column>
Student.java
#ManagedBean(name="student")
public class student {
#Id private String StudentId;
private String Fname, Lname, Mname="noname";
/*******getters and setters** and database transaction****/
}
studentList.java
#ManagedBean(name="studentList")
#SessionScoped
public class studentList {
public List<student> studentL(){
List<student> list = new ArrayList<student>();
PreparedStatement ps = null;
ResultSet rs = null;
Connection con = null;
try{
Class.forName("org.apache.derby.jdbc.ClientDriver");
con = DriverManager.getConnection("jdbc:derby://localhost:1527/tourManager","administrator","pass");
String sql = "Select * from student";
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()){
student student1 = new student();
student1.setFname(rs.getString("FNAME"));
student1.setLname(rs.getString("LNAME"));
student1.setStudentId(rs.getString("STUDENTID"));
list.add(student1);
// return list;
}
}catch(Exception e){
e.printStackTrace();
}
return list;
}
public void editStudent() throws IOException{
int index = Integer.parseInt(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("index").toString());
System.out.println(" the selected row is "+index);
}
}
You can pass a parameter using expression language.
In your bean, have a function like
public void editStudent(String studentId)
{
// do something with id
}
Now, using expression language, you can call that method using #{yourbean.editStudent('id')}
Since you are iterating through your data using a datatable, you can access the student's id from the var variable.
<h:dataTable value="#{studentList.studentL()}" var="student" ...>
...
<h:commandButton value="Edit" action="#{studentList.editStudent(student.studentId)}" />
...
</h:dataTable>
The expression language will access the getStudentId() (getter method from studentId) method from the specific student.

List<Object []> in JSF dataTable

I have two entities , Employee and publication :
I want to show in a data table the publication title, date, and it's author stored in database :
this is my query using JPQL :
private static EntityManager em;
private static EntityManagerFactory factory;
public PublicationDAO() {
if(factory==null)
factory=Persistence.createEntityManagerFactory("mavenTest");
if(em==null)
em=factory.createEntityManager();
}
public List<Object[]> getAllPublication() {
em.getTransaction().begin();
List<Object[]> pubs = em.createQuery("SELECT c.titrePublication, p.login FROM Publication c JOIN c.employee p ").getResultList();
em.getTransaction().commit();
return pubs;
}
so I want to show this information in XHTML page's data table.
Currently the query would return Array and what you need is a Construct return type..
create custom class (this will be your return type and it must have constructor which takes result values you define in query string. )
public class publicationModel
{
public String publicationName;
public String author;
public publicationModel (String publicationName, String author)
{
this.publicationName= publicationName;
this.author= author;
}
}
use typedQuery
String queryStr ="SELECT NEW example.publicationModel (c.titrePublication, p.login) " +
"FROM Publication c JOIN c.employee p ";
TypedQuery query =
em.createQuery(queryStr, publicationModel .class);
List <publicationModel> results = query.getResultList();
m not able to format the answer.. but i hope this helps..
I wonder why you make the type of the list "array of objects". Rendering it as type of your entity class is enough :
public List<Publication> getAllPublication() {
...
List<Publication> pubs = ...
...
}
Specify a managedBean class in your presentation tier, to do the job :
#RequestScoped
#ManagedBean
public class PublicationBean {
// Inject your PublicationDAO here
private PublicationDAO publicationDao;
private List<Publication> publications;
#PostConstruct
public retrievePublications () {
try {
publications = publicationDao.getAllPublication();
} catch (Exception e) {
}
}
public List<Publication> getPublications() {
return this.publications;
}
public void setPublications(List<Publication> publications) {
this.publications= publications;
}
// getters/setters
}
Then, display the data with <h:dataTable> like this :
<h:dataTable value="#{publicationBean.publications}" var="p" rules="all">
<h:column>
<f:facet name="header">Publication title</f:facet>
#{p.titrePublication}
</h:column>
<h:column>
<f:facet name="header">Publication author</f:facet>
#{p.employee.name}
</h:column>
</h:dataTable>
hi finally I find the solution :
the correct query should be :
List<Publication>=em.createQuery("select p from Publication p",Publication.Class).getResultList();
in the managed bean I should declare The author which is The Employee entity with getter and setter.
then create a method called getAllpublications as :
public List<Publication> getAllpublications (){
publicationDao.getAllPublication();//this method is declared and specified in the DAO class
}
after that the xhtml page should look like:
<h:dataTable value="#{publicationBean.publications}" var="p" rules="all">
<h:column>
<f:facet name="header">Publication title</f:facet>
<h:outputText value="#{p.titrePublication}"></h:outputText>
</h:column>
<h:column>
<f:facet name="header">Publication author</f:facet>
<h:outputText value="#{p.employee.name}"></h:outputText>
</h:column>
</h:dataTable>
so the solution is very close to your answer Omar thanks a lot for your help.

How to get selected row of a datable in JSF 1.2 using OpenFaces?

I used data table (OpenFaces) for selecting a row in data table using the attribute o:checkboxColumn rowDatas this will filter the selected rows only.
<o:checkboxColumn rowDatas="#{tBean.srInventoryList}">
<f:facet name="header">
<o:selectAllCheckbox />
</f:facet>
</o:checkboxColumn>
When I click a button it displays all the list, but I want only other rows which are not selected whether any attributes for filter the row list.
Actually it's not possible by the API of checkboxColumn by itself, You need to add some additional logic inside your bean for example:
<o:dataTable id="bookMultipleSelection"
var="book"
value="#{BookList.books}">
<o:multipleRowSelection rowDatas="#{BookList.list}"/>
<o:selectionColumn>
<f:facet name="header">
<o:selectAllCheckbox/>
</f:facet>
</o:selectionColumn>
/**other columns here**/
</o:dataTable>
<o:commandButton execute="bookMultipleSelection" action="#{BookList.updateList}" render="bookMultipleSelection" value="Click ME"/>
End something like this in your backing bean :
private List<Book> books;
private List list = new ArrayList();
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public List<Book> getBooks() {
return books;
}
public void updateList(){
books.removeAll(list);
}

How can the dependencies between drop downs be managed?

I am using JSF2.0. I have three drop downs :
masterDropDown.
childDropDownA
childDropDownB
The business rule that needs to be enforced is :
Whenever masterDropDown changes , I need to populate childDropDownA and childDropDownB.
The contents of childDropDownA and childDropDownB are same except that when the user selects something from childDropDownA, childDropDownB should have its old contents except the one selected by user in childDropDownA. The same rule applies when the user selects childDropDownB first.
What is the cleanest way to achieve this in JSF?
Plain JSF 2:
<h:form>
<h:selectOneMenu id="ddlMaster" value="#{bean.ddlMasterSelected}">
<f:listItems value="#{bean.ddlMasterData}" />
<f:ajax listener="#{bean.fillChildren}" render="ddlChildA ddlChildB" />
</h:selectOneMenu>
<h:selectOneMenu id="ddlChildA" value="#{bean.ddlChildASelected}">
<f:listItems value="#{bean.ddlChildAData}" />
<f:ajax listener="#{bean.refillChildB}" render="ddlChildB" />
</h:selectOneMenu>
<h:selectOneMenu id="ddlChildB" value="#{bean.ddlChildBSelected}">
<f:listItems value="#{bean.ddlChildBData}" />
<f:ajax listener="#{bean.refillChildA}" render="ddlChildA" />
</h:selectOneMenu>
</h:form>
Managed bean
#ManagedBean
#ViewScoped
public class Bean {
private Map<String, String> ddlMasterData;
private Map<String, String> ddlChildAData;
private Map<String, String> ddlChildBData;
private String ddlMasterSelected;
private String ddlChildASelected;
private String ddlChildBSelected;
#PostConstruct
public void init() {
//fill initial values for the drop down lists...
//this is a raw idea, you must refine it
DDLService ddlService = new DDLService();
ddlMasterData = ddlService.getDDLMasterData();
//empty data for children ddls
ddlChildAData = new LinkedHashMap<String, String>();
ddlChildBData = new LinkedHashMap<String, String>();
}
public void refillChildB(AjaxBehaviorEvent event) {
//filling the children ddls
DDLService ddlService = new DDLService();
ddlChildASelected = ddlService.getDDLChildData();
//same method to fill child data on ddlChildBSelected because is same data
ddlChildBSelected = ddlService.getDDLChildData();
}
public void fillChildren(AjaxBehaviorEvent event) {
//when the user selects something from childDropDownA
//childDropDownB should have its old contents
//I assume it must be cleared, you can change this behavior though
ddlChildBData = new LinkedHashMap<String, String>();
}
public void refillChildA(AjaxBehaviorEvent event) {
//The same rule applies when the user selects childDropDownB first
//I assume it must be cleared, you can change this behavior though
ddlChildAData = new LinkedHashMap<String, String>();
}
}

Resources