Can't dynamically set component identifier - jsf-2

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?

Related

Primefaces data for data table is getting confused

Sorry for the title but I have to explain what I want to do and what isn't working. My web ui with JSF 2.2.10 and primefaces 5.2.6 shows a search mask and search results upon a model.
Each search instance is shown as a tab in a tabView. When a tab is clicked, its corresponding search instance is shown under the tabView in a dataTable. A search instance is created upon a search template, so different search instances can have different input fields and different result fields (which are the columns in the data table).
The user is able to execute the search for an existing search instance again with or without changed search fields. Here is my problem...he ui work until the user has executed a search instance 2nd time. Now when the tab in the tabView is changed an exception is thrown and the javascript console shows 'Request return with error:parsererror primefaces.js.jsf?ln=primefaces$v=5.2.6:1'
Now the data of for instance search instance 1 is mixed up with search instance 2. A result field (data table column) from search instance 1 is tried to get from search instance 2, but this can fail.
This only occurs if a search instance is executed the 2nd time. Without 2nd execution I can change between the tabs without problem. My data structure is ok I think.
A class SearchInstance is "behind" a tab and contains a list of SearchResult. This SearchResult is a Map with the result fields.
This is the xhtml of the tabView. The tabView is only used as trigger here. A tab does not really contain the dataTable with the components, it updates only the form and the content is included under the tabView:
<h:form id="searchInstancesFormId">
<p:tabView id="searchTabViewId" value="#{searchBL.searchInstances}" var="curSearch" activeIndex="#{searchBL.activeTabIndex}">
<p:ajax event="tabChange" oncomplete="resizeResultViews();" listener="#{searchBL.setSelectedSearch(curSearch)}"
update="#form" immediate="true" process="#this" />
<p:ajax event="tabClose" listener="#{searchBL.removeSearchInstance(curSearch)}" update="#this"
oncomplete="resizeResultViews();" immediate="true" process="#this" />
<p:tab closable="#{curSearch.isCloseable()}">
</p:tab>
</p:tabView>
<h:panelGrid id="mainSearchAreaGridId">
<ui:include
src="#{not searchBL.selectedSearch.closeable ? '/sections/search/firstSearchTab.xhtml' : '/sections/search/searchInstanceTab.xhtml'}">
<ui:param name="curSearchInst" value="#{searchBL.selectedSearch}" />
</ui:include>
</h:panelGrid>
</h:form>
The 1st tab is the search template tab from the 2nd tab on there are search instances.
Here is the dataTable xhtml. The problem occurs when curValue is retrieved. Here in 'hitlistBL' bean the result field map is queried with the current property name. Here the name from the search instance selected before and it is tried to get the value from the new selected search instance:
<p:dataTable id="searchResultTableId" scrollable="true" value="#{curSearch.getSearchResults()}" scrollHeight="300" var="curSearchResult"
sortMode="multiple" rowKey="#{curSearchResult.hashCode()}" draggableColumns="true" resizableColumns="true" styleClass="hitlistDataTable"
paginator="true" rows="#{curSearch.hitlistRowsPerPage}" rowIndexVar="rowIndex" filteredValue="#{curSearch.filteredValues}"
selection="#{curSearch.selectedSearchResults}" widgetVar="hitlistTableVar">
<p:ajax event="rowSelect" update="#(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
<p:ajax event="rowUnselect" update="#(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
<p:ajax event="toggleSelect" update="#(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
<p:ajax event="rowSelectCheckbox"
update="#(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
<p:ajax event="rowUnselectCheckbox"
update="#(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" />
<p:ajax event="contextMenu" update="#(.resultlistActionGrid) :searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId"
oncomplete="PF('searchResultTableContextMenuVar').show(currentEvent);" />
<!-- double click listener -->
<p:ajax event="rowDblselect"
listener="#{editPropertyBL.initForEdit(curSearch.selectedSearchResults.get(0), curSearch.getDataViewDefinition())}"
oncomplete="PF('editPropertyDialogVar').show();" update=":editPropertyFormId #(.resultlistActionGrid)" />
<p:column style="width: 16px;">
<p:rowToggler />
</p:column>
<p:column selectionMode="multiple" style="width: 16px; text-align:center; padding-right: 12px;" />
<p:columns value="#{curSearch.determinePrimaryPropertyNames()}" var="curPrimaryPropName"
sortBy="#{curSearchResult[curPrimaryPropName].getValue()}" filterBy="#{curSearchResult[curPrimaryPropName].getValue()}"
filterMatchMode="contains">
<f:facet name="header">
<h:outputText value="#{displayNameResolver.resolveDisplayNameOfHitlistProperty(curPrimaryPropName, curSearch)}" />
</f:facet>
<ui:param name="curValue" value="#{hitlistBL.generatePropertyValue(curSearchResult, curPrimaryPropName)}" />
<ui:param name="isDocumentTitle" value="#{hitlistBL.isDocumentTitle(curPrimaryPropName)}" />
<ui:param name="isChoice" value="#{hitlistBL.isChoice(curPrimaryPropName, curSearch)}" />
<!-- doc title -->
<h:panelGroup rendered="#{curSearchResult.isChanged() and (isDocumentTitle)}" style="padding-right: 4px;">
<i class="fa fa-refresh" />
</h:panelGroup>
<!-- <p:commandLink action="#{contentBL.showContentExtern(curSearch.getViewId(), curSearchResult)}" value="#{curValue}" ajax="false"
rendered="#{(curSearchResult.isOfDataType('STRING', curPrimaryPropName)) and (isDocumentTitle) and (not isChoice)}" target="_blank" /> -->
<!-- document title -->
<h:outputText value="#{curValue}" title="#{curSearchResult.getRepresentationsAsString()}"
rendered="#{(curSearchResult.isOfDataType('STRING', curPrimaryPropName)) and (isDocumentTitle) and (not isChoice)}" />
<!-- data type STRING -->
<h:outputText value="#{curValue}"
rendered="#{curSearchResult.isOfDataType('STRING', curPrimaryPropName) and (not isDocumentTitle) and (not isChoice)}" />
<!-- data type UUID -->
<h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('UUID', curPrimaryPropName) and (not isChoice)}" />
<!-- data type INTEGER32 -->
<h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('INTEGER32', curPrimaryPropName) and (not isChoice)}">
<f:convertNumber integerOnly="true" groupingUsed="false" />
</h:outputText>
<!-- data type DOUBLE -->
<h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('DOUBLE', curPrimaryPropName) and (not isChoice)}">
<f:convertNumber groupingUsed="false" />
</h:outputText>
<!-- data type DATETIME -->
<h:outputText value="#{curValue}" rendered="#{curSearchResult.isOfDataType('DATETIME', curPrimaryPropName) and (not isChoice)}">
<f:convertDateTime type="both" dateStyle="short" timeStyle="short" timeZone="#{settingsBL.getTimeZoneIdSet()}"
pattern="#{settingsBL.dateTimePattern}" />
</h:outputText>
<!-- CHOICE -->
<h:outputText value="#{hitlistBL.determineChoiceUiValue(curSearch.getViewId(), curSearchResult, curPrimaryPropName)}"
rendered="#{(not isDocumentTitle) and (isChoice)}" />
</p:columns>
</p:dataTable>
A search instance if executed with the following. A new search is done and the search instance member search result is exchanged with the new results:
<p:commandButton id="doSearchButtonFullMaskId" value="#{msgs['label.button.searchTemplate.search']}" icon="searchButtonIcon"
styleClass="searchButton" action="#{searchMaskBL.doSearch(curSearchInst)}" update="#form" process="#form"
oncomplete="resizeResultViews(); PF('hitlistTableVar').clearFilters();" style="margin-top: 10px;" />
Sorry this is a lot of text and it is quite difficult to explain. I don't know if this is my flaw or there is a bug somewhere. Maybe this javascript parsererror could give a hint, but I do not know how to get into/debug it.
Update: looks like a not wellformed xml of the ajax response?:
XML-Verarbeitungsfehler: nicht wohlgeformt Adresse: moz-nullprincipal: {96f3db57-4075-4d80-a250-03491a2ce33f} Zeile Nr. 90, Spalte 132: ...rrorpages/500.xhtml?dswid=-9189"></redirect>]]>]]></update></partial-response......-------------------------------------------------^
It points to the closing brackets of ></redirect>]]>]]><

When to use :(colon) in rendering in jsf components

i have read that, we should use :(colon) to render components in other form. but in my case
<h:form id="form">
<p:growl id="messages"></p:growl>
<p:dataTable var="e" value="#{employees.eList}" id="elist1"
editable="true">
<f:facet name="header">
In-Cell Editing
</f:facet>
<p:ajax event="rowEdit" listener="#{employees.onEdit}" update=":form:messages"/>
<p:ajax event="rowEditCancel" listener="#{employees.onCancel}" />
<p:column headerText="name" style="width:30%">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{e.name}" />
</f:facet>
<f:facet name="input">
<h:inputText value="#{e.name}" style="width:100%" />
</f:facet>
</p:cellEditor>
</p:column>
.......... ...........
</p:datatable>
i want to update messages(growl) from datatable component why i have to use colon update=":form:messages"
All relative client IDs (the ones not starting with :) are searched relative to the parent component which implements the NamingContainer interface. As you can see in the linked javadoc, that are at least all UIForm and UIData components. The <h:form> is such one. The <p:dataTable> is another one.
In your particular case, the <p:ajax> is enclosed in <p:dataTable>. So, the <p:ajax update="messages"> would look for a child component with ID messages inside the context of <p:dataTable>. However, since there is none, it won't find anything. You actually need to use an absolute client ID instead because it's outside the context of the current NamingContainer parent.
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

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.

Create table columns dynamically in JSF

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>

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