Create table columns dynamically in JSF - jsf-2

I'm working on dashboard application where I have to retrieve a set of records and display in dynamic tables boxes. Page frame length is fixed. now of columns and rows can be initialized. It should look like this sample:
Currently I'm using data table to display but it prints all the data in one column. How would I change my code to above pattern?
<o:dataTable id="tabBlSearch" var="item"
onkeyup="handleLeftRightArrowOnDataTable('frmDashBoard:tabBlSearch')"
value="#{bLDashBoardAction.listBondLoc}">
<o:column style="width: 20px;">
<h:outputText value="#{item.awb}" />
</o:column>
</o:dataTable>

You can achieve this with standard JSF components using a <h:panelGrid> wherein <c:forEach> is been used to generate the cells during the view build time. The <ui:repeat> won't work as that runs during view render time.
<h:panelGrid columns="5">
<c:forEach items="#{bean.items}" var="item">
<h:panelGroup>
<h:outputText value="#{item.value}" />
</h:panelGroup>
</c:forEach>
</h:panelGrid>
As to component libraries, I don't see anything in OpenFaces' showcase, but PrimeFaces has a <p:dataGrid> for exactly this purpose, even with pagination support.
<p:dataGrid columns="5" value="#{bean.items}" var="item">
<p:column>
<h:outputText value="#{item.value}" />
</p:column>
</p:dataGrid>

Related

Tooltip for each row in data table

This questions screams to be a duplicate of JSF 2.0 + Primefaces 2.x: Tooltip for datatable row but since this old question has NO working/satisfying solution for me and there's no way (?) to get attention back to it I opened this new one.
It's very simple:
I have a dataTable (with JSF-standard or with primefaces) and I'd like to add a different tooltip for EACH row (not just for one field in it!).
What I tried so far:
<pe:tooltip value="This is row number #{rowIndex}"
for="#(#table1 tr[role=row][data-ri=#{rowIndex}])"
atPosition="top center" myPosition="bottom center"
shared="true" />
where #table1is the ID of my data table . This came to my mind because of this.
And both solutions from JSF 2.0 + Primefaces 2.x: Tooltip for datatable row : the first solutions works, but only for ONE field / id and not for the whole row. The second solution won't work at all for me.
And I'm 100% sure that both - primefaces & primefaces extensions - are working for me, I tested it.
I've done some test and this approach works perfectly:
<p:dataTable var="entry" value="#{....}" styleClass="myTable" rowIndex="rowIndex">
<p:column headerText="Header 1">
<h:outputText value="#{entry.value1}" />
</p:column>
<p:column headerText="Header 2">
<h:outputText value="#{entry.value2}" />
<pe:tooltip value="This is row number #{rowIndex}" forSelector=".myTable tr[role=row][data-ri=#{rowIndex}]"
shared="true" atPosition="top center" myPosition="bottom center" showDelay="500" />
</p:column>
</p:dataTable>
Note that in order to the data-ri attribute to be placed on datatable rows, you need the to add the attribute rowIndex (rowIndex="rowIndex").
It also worked with
<p:tooltip for="#(.myTable tr[role=row][data-ri=#{rowIndex}])" value="This is row number #{rowIndex}" />
You can also do it without using primefaces extensions. This example code works for me with primefaces 5.2.
Be aware that in primefaces 5.2 the p:dataTable attibute is rowIndexVar and not rowIndex as in the example above.
<h:form id="idform">
<p:dataTable var="komp"
id="idDataTable"
value="#{kompselect.listKomponenten}"
rowIndexVar="rowIndex"
selection="#{kompselect.selectedKomponente}"
rowKey="#{komp.name}">
<p:column>
<h:outputText id="otSelKomponente" value="#{komp.name}" />
<p:tooltip rendered="#{komp.displayToolTip}"
for="idForm:iddataTable:#{rowIndex}:otSelKomponente"
value="this is my Tooltip"/>
</p:column>
</p:dataTable>
according to this commment https://stackoverflow.com/a/13327334/4851983 (thaks BalusC )
Let primefaces link the objects automatically. I could show a tooltip for a textArea Primefaces 3.5 , as is show below
<p:dataTable id="commentsTable"
value="#{historyReq.commentsFromReq}" var="comment"
emptyMessage="#{localeMsg.roles_table_empty}"
rows="10"
styleClass="myTable"
rowIndexVar="rowIndex">
<p:column headerText="HEADER A">
<h:outputText value="#{bean.valorA}" />
</p:column>
<p:column headerText="#{HEADER B}">
<p:inputTextarea id="txtArea" cols="45" rows="1"
value="#{bean.valorB}"
readonly="true"
disabled="false"
autoResize="false">
<f:converter converterId="commentsConverter" />
</p:inputTextarea>
<p:tooltip for="txtArea" value="This is row number #{rowIndex}" />
</p:column>

Can't dynamically set component identifier

I have a p:inputText field inside a dataTable and I'm trying to set its identifier dynamically.
However I get the following error:
component identifier must not be a zero-length String
None of the String used as id are null or of zero-length
<h:form id="updateform">
<p:dataTable id="updatetable" value="#{EditingBean.row}" var="column"
style="width: 983px; overflow-x: auto; white-space: normal;">
<f:facet name="header">
<h:outputText value="#{EditingBean.currentStatement.statementName}" />
</f:facet>
<p:column rendered="#{column.display}" style="white-space: normal;">
<h:outputText value="#{column.alias}" />
</p:column>
<p:column rendered="#{column.display}" style="white-space: normal;">
<p:inputText id="#{column.name}" value="#{column.value}" />
</p:column>
<f:facet name="footer" style="text-align: right;">
<h:commandButton value="Update" action="#{EditingBean.update()}"
ajax="false" />
</f:facet>
</p:dataTable>
</h:form>
The id attribute must be set during view build time.
However, as #{column} is declared as <h:dataTable var>, it's only available during view render time. As it runs after view build time, it's thus null during view build time.
I'm not sure about the concrete functional requirement for which you thought that doing this would be the right solution. The code is not self-documenting enough to properly guess it. So it's hard to give a suitable answer. In any case, you've basically 2 options:
Use an iterating tag which runs during view build time, such as JSTL <c:forEach>.
<c:forEach items="#{EditingBean.row}" var="column">
...
<p:inputText id="#{column.name}" ... />
You perhaps actually don't need a dynamic ID at all. Give it a fixed ID.
<p:inputText id="name" ... />
JSF will already take care of generating unique IDs (prefixed with row index) in HTML output. Rightclick page and do View Source to see it yourself.
See also:
JSTL in JSF2 Facelets... makes sense?

Constructor of a viewScoped class invoked twice

I've been struggling with this for two days with no success and I think it's already time to ask for your help. But first of all, this is what I'm using:
JSF 2 Mojara 2.1.1
Primefaces 3.4.2
Netbeans 7.1.1
Tomcat 7.0.37
And now, the problem: I have a main page which is composed by several other pages using several <ui:include .. /> tags, like this:
<ui:composition template="/resources/templates/template1.xhtml">
<ui:define name="appData">
<p:panelGrid columns="1" id="contenidoAplicacion" styleClass="noborder">
<h:form id="fNewPerson">
<p:panel header="New employee" style="min-height:40em">
<ui:include src="./forms/personal.xhtml" />
<p:accordionPanel styleClass="noborder" activeIndex="3">
<p:tab id="tabSomeData" title="Identidad profesional" >
<ui:include src="./forms/formSomeData.xhtml" />
</p:tab>
....
....
</ui:define>
</ui:composition>
The personal.xhtm file looks like this:
<p:panelGrid>
<p:row>
<p:column >
<h:outputLabel value="Field1"/>
<p:inputText label="Field1" id="field1" value="#{dataBacking.selectedPerson.field1}" tabindex="1"
required="true" size="10" >
<f:convertNumber for="field1" integerOnly="true" groupingUsed="false"/>
</p:inputText>
<p:inputText id="field2" value="#{dataBacking.selectedPerson.field2}" tabindex="2" required="true" size="1" maxlength="1" >
<p:ajax event="keyup" listener="#{dataBacking.check}"
process="field1 field2" partialSubmit="true"
update="field1 field2 photo"/>
</p:inputText>
</p:column>
<p:column rowspan="5" >
<p:graphicImage id="photo" value="#{dataBacking.selectedPerson.photo}" width="90" />
</p:column>
</p:row>
...
</p:panelGrid>
The check() method in the dataBacking class is irrelevant because it only checks if the field1 and the field2 meet some rules and it works properly. The problem comes when the main page is loaded for the first time. In that case, the <p:ajax /> component in personal.xhtml doesn't work. I have to reload the page (simply by pressing the F5 key) and this time it works as it would be expected.
I've been changing some attributes of the component, but nothing seems to work. I really don't know what else to do. Any kind of help will be apreciated.
EDITED. After one more day, I think the problem has nothing to do with Primefaces ajax component, as the title of the question suggested. I've come to this conclusion through these two facts:
The behaviour with the <f:ajax .../> component remains the same.
I've figured out that the view relative to the first time I load the page is not persisted. I'll try to explain myself.
The DataBacking class has defined its scope as view so that the page can "see" all the attributes and methods during the time it's been shown to the user. However, I've noticed that the constructor is called twice: the first time the page is loaded (and then, none of the methods of the class are successfully invoked) and when I refresh the page. In this last case, the behaviour of both the page and the class is the expected one.

I can't update from within a facet

I'm using primefaces 3.3 with JSF 2.1. In the code below, I have a primeFaces dataTable that contains rows of data drawn from the database which is correctly activated from a tree component on the left part of my page. The dataTable displays and behaves correctly. I have a delete functionality that calls "update" which refreshes my dataTable and reflects my changes after the database was updated. My problem is with with f:facet (id="header"). Contained in that facet is a commandLink that creates a new row in my dataTable. It works in the sense that my database is correctly updated. The dataTable is not refreshed after this. In order to refresh my dataTable, I have to click on another node in my tree component (on the left of the page) and then return to the original treeNode to see my dataTable perfectly updated. What can I add to my code to update the dataTable dynamically?
Unfortunately, I can't add all my permutations that I've tried here - I've spent a long time on this problem - and your inputs will be greatly appreciated!
<h:form id="formRight" >
<p:dataTable var="material" value="#{entityCrudTreeBean.materialList}" id="materials" editable="true" paginator="true" rows="10" sortBy="#{material.name}">
<p:ajax event="rowEdit" listener="#{entityCrudTreeBean.onEditRow}"/>
<f:facet id="header" name="header">
In-Cell Material Editing
<br />
<p:commandLink id="create" value="Add new material" action="#{entityCrudTreeBean.createNewMaterial}" update=":formRight"/>
</f:facet>
<p:column headerText="Name" style="width:125px">
<p:cellEditor>
...
</p:cellEditor>
</p:column>
<p:column headerText="Options" style="width:10px" >
<p:rowEditor />
<p:commandLink id="delete" action="#{entityCrudTreeBean.deleteRow(material)}" update=":formRight">
<h:graphicImage value="#{resource['icons:Delete-icon.png']}" />
</p:commandLink>
</p:column>
</p:dataTable>
</h:form>
edit:
changing the line to
<p:commandLink id="create" value="Add new material" action="#{entityCrudTreeBean.createNewMaterial}" update=":formRight:materials"/>
doesn't work either
edit:
changing to :
<f:facet id="header" name="header">
In-Cell Material Editing
<br />
<p:commandLink id="create" value="Add new material" ajax="true" process="#this" action="#{entityCrudTreeBean.createNewMaterial}" update="#form"/>
</f:facet>
doesn't solve the problem either.
I had a similar issue as you a while back.
My working code looks like:
<f:facet name="header">Product List
<p:commandLink id="create" value="Add new product" ajax="true" process="#this"
action="#{modelBean.save}" update="#form"/>
</f:facet>
Stephen, you're on the right track!
It was solved in a simpler way: I updated my dataTable list in managed bean - which I did for the delete but not for the insert. Massive oversight there.
This code works:
<p:commandLink id="create" value="Add new material" action="#{entityCrudTreeBean.createNewMaterial}" update=":formRight"/>
Tip for people after me: Primefaces 3.3 has a known issue concerning updating within the dataTable. You need to wrap the dataTable with another component like a layout of a form. Calling update on the wrapper works.
According to the primefaces blog from Aug 15, this has been fixed in 3.4.RC1. But they changed the tree components. I'll wait for the 3.4 final release before upgrading.

Getting the filtered list in datatable

I am trying to filter a datatable using filter field in the column and get the filtered list (which populates datatable) and update another component (Toplam TL Teminati and Toplam Dolar Teminati) according to the filtered list's values in my page.
Is there anyway to do this in Primefaces 2.2.1 and JSF 2? If not can you rec commend a workaround for this case?
Thanks in advance.
To give you an example of how I achieved custom filter logic in my Primefaces 2.2.1 dataTable, I am giving you a scaled version of my code.
<p:dataTable value="#{listBeans.beans}" var="bean" dynamic="true" paginator="true" rows="20" paginatorPosition="bottom"
emptyMessage="No Beans" loadingMessage="Loading. . ." selectionMode="single" selection="#{listBeans.selectedBean}"
id="beanList" widgetVar="beanTable">
<f:facet name="header">
<h:panelGrid columns="4">
<h:outputText value="Bean List" />
<p:outputPanel>
<h:outputText value="Year Filter: " />
<h:selectOneMenu value="#{listBeans.yearFilter}"
onchange="yearFilterBtn.jq.click(); refreshFilters();">
<f:selectItems value="#{listBeans.years}" />
</h:selectOneMenu>
<p:commandButton id="yearFilterBtn" widgetVar="yearFilterBtn" action="#{listBeans.filterYears}"
update="listBeansForm:beanList" style="display:none;" />
</p:outputPanel>
<p:outputPanel>
<h:outputText value="Filter By Beanchild: " />
<p:inputText value="#{listBeans.beanchildFilter}" style="width: 150px; margin-right: 4px;" />
<!-- refreshFilters forces the visitor filter to refresh the selection if column filters are selected. -->
<p:commandButton oncomplete="refreshFilters();" value="Filter"
action="#{listBeans.filterBeanchildren}" update="listBeansForm:beanList" />
</p:outputPanel>
<p:commandButton value="Export to XLS" ajax="false">
<p:dataExporter target="beanList" type="xls" fileName="BeanReport"
excludeColumns="0,5,6" postProcessor="#{listBeans.postProcessExcelReport}" />
</p:commandButton>
</h:panelGrid>
</f:facet>
<p:column style="width:16px">
<p:rowToggler />
</p:column>
<p:column filterStyleClass="filtertag" filterBy="#{bean.beanDateDisplay}" filterMatchMode="startsWith">
....
</p:dataTable>
Without really going into too much detail about the managed bean code, the actions of the command button are essentially passing filter arguments to my BO layer that requery the database for the new list of beans. The explicit update of the dataTable component is needed to refresh the data.
You will notice that on the explicit Beanchild Filter button that is not hidden, I have an oncomplete attribute that references a javascript function called refreshFilters(). I can't remember exactly the problem I had, but I think it is a bug in the 2.2.1 version of Primefaces when a column filter value exists and an asynchronous update occurs within the dataTable itself. Here is the javascript function:
function refreshFilters() {
var filters = jQuery('.filtertag');
var uppedOnce = false;
filters.each(function(idx) {
var curEl = jQuery(this);
if (curEl.val() != '') {
curEl.keyup();
uppedOnce = true;
}
});
if (!uppedOnce) {
jQuery(filters[0]).keyup();
}
}
You can see here that I am locating every DOM element that has the class filtertag, which would be the column filters. I am saying that if a value exists in that field after the server action is complete, then I am manually triggering a keyup event as this will "refilter" the column with the previous value from before.
I am not sure if it is necessary in later versions of Primefaces, I am not even sure it is necessary now, so I suggest trying to do this without the Javascript workaround and if you run into problems cooridnating the two then you can consider using the Javascript.

Resources