How to add specific attributes to JSF datatable header - datatable

I am using JSF 2.2 and want to add some specific attributes to the datatable header row. The end result in HTML should look something like this.
<table>
<th my-attribute="myattributevalue"> Header Column </th>
....
Is this possible in JSF?

Use the <f:passThroughAttribute/> to set custom attributes. The th can be rendered by setting rowHeader="true" on an <h:column/>
<h:dataTable>
<h:column rowHeader="true">
<h:outputText value="Header Column"/>
<f:passThroughAttribute name="my-attribute" value="myattributevalue"/>
</h:column>
</h:dataTable>

Related

JSF PrimeFace: p repeat ajax update with class not working

totalListSumA is an ArrayList inside java. Inside debug mode, the arraylist work just fine. New value assigned into this list.
When user input a new value in a box, program will recalculate new sum and display inside the code shown below.
<p:inputNumber
class="caseType1"
rendered="#{inputFormTemplateView.allowEdit}"
inputStyle="text-align: center"
minValue="0"
maxValue="99999999"
decimalPlaces="0"
thousandSeparator=""
emptyValue=""
value="#{inputFormView.selectedInputFormDetail.data[dataField]}" >
<p:ajax update="dataField, #{inputForm4_1View.getColTotal()}"/>
<p:ajax update="#(.totalRow3)"></p:ajax>
</p:inputNumber>
<tr>
<td align='center'>Total</td>
<p:repeat var="item" value="#{inputForm4_1View.totalListSumA}" class="totalRow3">
<td class="cell_cal" style='text-align:center;' >
<h:outputLabel
class="totalRow3"
value="#{item}" />
</td>
</p:repeat>
</tr>
I have tried
h:panelGroup id='...'
ui:repeat id='....'
Still the value remain unchanged inside p:repeat. Any method I can try to get and show the latest value inside totalListSumA?
This is wrong
<p:ajax update="dataField, #{inputForm4_1View.getColTotal()}"/>
<p:ajax update="#(.totalRow3)"></p:ajax>
1) Ajax should have event="change" or other events, but most wrong thing is that calling bean method inside update.
2) Use listener="#{inputForm4_1View.getColTotal()}"
3) Don't use 2 same ajaxes.
Solution:
<p:ajax event="change" update="dataField, #(.totalRow3)" listener="#{inputForm4_1View.getColTotal()}"/>
If this doesn't solve your problem, try update form like update="#form" or update="yourFormId"

Working with custom components and getting javax.faces.FacesException: java.io.IOException: Cannot add the same component twice

I'm working on old system which has a lot of code written back in the days using jsf1.2. Now I have the task to dynamically add/remove group of input elements via ajax on button click.
I was guided by this post on how to add input fields dynamically, made little tweaks to support ajax and made prove of concept which works perfectly fine.
Now the problem occurs when instead of <h:inputText> .. </h:inputText> or other form fields I use our own custom tag component.
When using the custom tag I get the page displayed on page load, but if I try to remove an item, for the first component in the list I get the error java.io.IOException: Cannot add the same component twice: editform:parentTable:0:fieldsTable:0:HTML_TITLE_INPUT_en
I believe the problems is due to the component already being in the component tree when the custom tag tries to add it again on postback, but still I don't know how to fix the issue.
Note 1: I have to use our custom tag since it has a lot of logic inside and it is used to display every type of form field (inputText, textarea, checkboxes etc)
xhtml code:
<h:dataTable id="parentTable" value="#{bean.groups}" var="group" styleClass="parentTableStyleClass">
<h:column>
<h:dataTable id="fieldsTable" value="#{group.fields}" var="field">
<h:column>
<h:outputLabel value="#{field.label}" styleClass="col-sm-2 control-label" />
</h:column>
<h:column>
<customTag:propertyValue
name="#{field.name}"
operation="edit"
instance="#{bean.instance}"
styleClass="form-control"
inputWrapperClass="col-sm-5"/>
</h:column>
</h:dataTable>
</h:column>
<h:column>
<p:commandButton value="Remove Group"
styleClass="btn btn-secondary btn-sm"
action="#{bean.removeGroup(group)}"
process="#(.parentTableStyleClass)"
update="#(.parentTableStyleClass)" />
</h:column>
</h:dataTable>
The tag class:
public void encodeBegin(FacesContext context) throws IOException {
getChildren().clear();
...
// bunch of logic
...
HtmlPanelGroup wrapper = new HtmlPanelGroup();
HtmlInputText inputText = new HtmlInputText();
...
// bunch of code creating input text field
...
wrapper.setStyleClass(getInputWrapperClass() + " input-group");
wrapper.getChildren().add(inputText);
getChildren().add(wrapper);
}

SelectOneRadio set time on selection

I've been raking my brain trying to figure this one out. I have a really simple requirement that's turning out to be a very interesting problem.
The requirement is to update a time stamp when the user chooses a selection in a radio button list.
So I have a radio button list:
...
<h:selectOneRadio value="#{mybean.myvalue}" >
<f:selectItem itemLabel="A" itemValue="A"/>
<f:selectItem itemLabel="B" itemValue="B"/>
<f:selectItem itemLabel="C" itemValue="C"/>
<f:selectItem itemLabel="D" itemValue="D"/>
<f:ajax render="timeBox" listener="#{measurements.captureTime('timeBox')}"/>
</h:selectOneRadio>
...
And a text box a little further down the page:
...
<h:outputText id="timeBox" value='#{measurements.timeBox}'>
<f:convertDateTime pattern="HH:mm:ss"/>
</h:outputText>
...
And then in the backing bean I have the listener defined:
...
public void captureTime(String id){
if(id.equals("timeBox"){
timeBox = new Date(System.currentTimeMillis());
}
}
...
But when I change the radio button, the value is not updating. I'm pretty sure this is to do with the various phases of JSF (ie. it's not being updated because of the problem in this post: http://balusc.blogspot.ca/2012/03/reset-non-processed-input-components-on.html) but I'm not entirely sure how to fix it.. I'd really like to avoid including another library if possible.
As always let me know if you need more info and I will be happy to oblige.
Thanks!
Edit
The structure of these components is:
<h:form>
<table>
<tr>
<td>
<h:select.../>
</td>
</tr>
<tr>
<td>
<h:output.../>
</td>
</tr>
</table>
</h:form>
The given construct suggests that you've duplicate components with the same ID. Make sure that you don't actually have duplicate components with the same ID.

Is there a way to add columns datatable without rerendering the entire table

I'm using both JSF 2.0 and jQuery/javaScript, where needed.
I'm trying to add and remove column from a datatable in a dynamic manner.
Problem is - As far as I know I have to re-render the entire table to add or remove columns and that entails a fetch for all the data in the table when in fact, in most cases it isn't neccessary.
For example (typing this for the purpose of problem illustration, syntax errors might exist but assume they don't):
<h:dataTable id="table">
<h:column id="cul1" rendered="#{mrBean.isCul1_rendered} >
...
</h:column>
<h:column id="cul2" rendered="#{mrBean.isCul2_rendered} >
...
</h:column>
</h:dataTable>
<f:ajax render="table" />
<h:commandButton action="#{mrBean.switchIsCul1}" >Switch Cul1</h:commandButton>
<h:commandButton action="#{mrBean.switchIsCul2}" >Switch Cul2</h:commandButton>
</f:ajax>
As illustrated, when rendering and un-rendering a column, the whole table gets re-rendered. Is there a way to only render the changing column? (As far As i know, render="cul1, won't work)
Thanks!
Unfortunately no, that's not possible. A table column can't be represented by a single HTML element. It's actually a collection of loose <td> elements. Technically, you'd need to reference every single <td> individually in order to be able to ajax-render it with JSF. As you can't give each <td> a client ID with JSF, it stops here. You can give them each a common class name, but the JSF ajax render attribtue doesn't work with class names.
Your best bet is to show/hide them with pure CSS/JS. Set a display: none; on the <td> elements of one column and then use JS to toggle it to display: block; and set display: none; on the <td> elements of the other column. You can give the <td>s of an individual column a specific classname using columnClasses attribute.
Kickoff example:
<h:dataTable id="table" binding="#{table}" columnClasses="col1,col2">
<h:column>...</h:column>
<h:column>...</h:column>
</h:dataTable>
<f:ajax>
<h:commandButton ... onclick="switchToCol1('#{table.clientId}')" />
<h:commandButton ... onclick="switchToCol2('#{table.clientId}')" />
</f:ajax>
(actually, if no bean action needs to be invoked, then a plain <button> is also sufficient)
with this CSS
.col1 {
display: none;
}
and this JS/jQuery:
function switchToCol1(tableId) {
var $table = $("[id='" + tableId + "']");
$('.col1', $table).show();
$('.col2', $table).hide();
}
function switchToCol2(tableId) {
var $table = $("[id='" + tableId + "']");
$('.col1', $table).hide();
$('.col2', $table).show();
}
primefaces seems to achieve this though i haven't looked at the underlying code.
primefaces datatable

JSF2 ajax events not triggered in dynamically included pages

I have a AdminHome.xhtml page which has a dynamic include as below:
<h:form id="masterform">
<table class="DEFTABLE">
<tbody>
<tr>
<td class="CREATESTYLE">Create
<h:selectOneMenu styleClass="SELECTBOX" id="createBox" value="#{adminWindowController.actionSelection}">
<f:ajax event="change" execute=":masterform:workspace" listener="#{adminWindowController.invokeAction}" render=":masterform:workspace :masterform:taskbar createBox"/>
<f:selectItem itemValue="NONE" itemLabel="Select one..."/>
<f:selectItem itemValue="CREATE_ENTITY_DEFINITION" itemLabel="Entity Definition"/>
<f:selectItem itemValue="CREATE_ENTITY_GROUP" itemLabel="Entity Group" />
<f:selectItem itemValue="CREATE_USER" itemLabel="User" />
<f:selectItem itemValue="CREATE_USER_GROUP" itemLabel="User Group" />
</h:selectOneMenu>
</td>
</tr>
</tbody>
</table>
<h:panelGroup id="workspace">
<table class="DEFTABLE">
<tr>
<td class="WSHEIGHT" valign="top">
<ui:include src="#{adminworkspace.workspaceContent}"/>
</td>
</tr>
</table>
</h:panelGroup>
</h:form>
The above include will get page names dynamically during various ajax events triggered on AdminHome.xhtml page.
Below is one of the dynamic pages that gets loaded when the selectOneMenu changes.
<ui:composition>
<h:form id="entdefcreateform">
<h:panelGroup id="entdefpanel">
<table>
</table>
<table cellspacing="0">
<tr>
<ui:repeat value="#{adminEntityDefnController.entDefTabList}" var="tab">
<td class="#{tab == uIUtil.getRequestMapValue('activetab','General') ? 'TABBUTTONCTIVE' : 'TABBUTTON'} ">
<h:commandLink action="#{adminWindowController.TabChange}" style="border: none;">
<f:ajax execute=":masterform:entdefcreateform:entdefpanel" render=":masterform:entdefcreateform:entdefpanel"/>
<f:param name="activetab" value="#{tab}"/>
<h:outputText value="#{tab}"/>
</h:commandLink>
</td>
</ui:repeat>
</tr>
</table>
<table class="TABCONTENTTABLE">
<tr valign="top">
<td class="TABCONTENT">
<ui:include src= "#{adminEntityDefnController.entDefTabTable.get(uIUtil.getRequestMapValue('activetab','General'))}"/>
</td>
</tr>
</table>
</h:panelGroup>
</h:form>
</ui:composition>
In JSF2, <ui:include>s are evaluated during restore view phase, not during render response phase. Therefore, they do not work dynamically (anymore). I have had the same problem after migrating from JSF 1.2 to 2.1.
I got it working by changing the action method of the bean. The trick is to return to the same page that fires the ajax request. I'm using PrimeFaces 2.2.1 and the menu fires in ajax way.
The first problem i see in your code is that you could NOT have 2 <form> : one nested in another.
I guess that's why your events don't fire.
I had the same problem in may code !
BTW BalusC could you explain more precisely what you did by
"The trick is to return to the same page that fires the ajax request. I'm using PrimeFaces 2.2.1 and the menu fires in ajax way"
This is not clear for Me
E.g. you have <ui:include src="#{bean.value}", where bean is view scope bean.
It is possible to still use dynamic page loading. You can use either of these 2 solutions:
Set javax.faces.PARTIAL_STATE_SAVING to false in web.xml for you project. It will trigger the jsf1.2 way of state saving.
When <ui:include/> evaluates the value - new instance of view scope bean is created and not taken from context. As a result, the default value for src taken. If you put the bean within the session scope (which is not good) or create new session scope bean which will contain only your page path string (to minimize session size), it will resolve the issue.
Here's another tip if you want to reset this session bean value from navigation from page to page. One of the ways is to create fake method "reset()" and put <c:if test="#{bean.reset}"></if> before <ui:include/> to make this initialization for your page. Reset can look like:
private String lastViewId;
public boolean isReset() {
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
if (!viewId.equals(lastViewId)) {
lastViewId = viewId;
//make any clean here
}
return false;
}

Resources