I need to some sort of dynamic table in my project.
I have tried to use some configurations from database to generate my table.
I have stored some JPA field names in my DB and i want to retrieve their value
at run-time.
I need to something like this:
<h:datatable value="#{someBean.data}" var="record">
<ui:repeat value="#{someBean.columns}" var="column">
<h:column>
<h:ouputText value="#{record.column}"/>
</h:column>
</ui:repeat>
</h:datatable>
But i don't know how to evaluate my stored EL (record.column) especially when column contains reference to other entities for example column=
'someEntity.anOtherEntity.property'
thanks in advance
You don't need to put a ui:repeat component into an h:dataTable component to be able to access the property of record. Simply this should do.
<h:datatable value="#{someBean.data}" var="record">
<h:column>
<h:ouputText value="#{record.column.propertyOfColumn}"/>
</h:column>
</h:datatable>
This of course assumes that:
A getter/setter property exists for data on someBean managed bean, Eg. getData setData
A getter/setter property exists for column on the class type of dataTable var record. Eg. getColumn and setColumn
A getter/setter property exists for propertOfColumn on the class type of column. Eg. getPropertyOfColumn and setPropertyOfColumn
Related
I got a list of objects displayed in a page.
This is the view:
<h:form>
<h:dataTable var="o" value="#{opleidingController.opleidingen}" border="0" >
<h:column>
<f:facet name="header">Code</f:facet>
<h:link value="#{o.opl_code}" outcome="#{opleidingController.getOpleidingByCode(o.opl_code)}" />
</h:column>
<h:column>
<f:facet name="header">Titel</f:facet>
<h:outputText value="#{o.opl_titel} "></h:outputText>
</h:column>
<h:column>
<f:facet name="header">Thema</f:facet>
<h:outputText value="#{o.opl_thema} "></h:outputText>
</h:column>
</h:dataTable>
</h:form>
This displays everything very well.
Like you can see I got the code part of the object set as a link.
With this code I get an object out of the database, from which I display the details.
The problem here is that every link displays the details of the last object of the list instead of the current object where I click the link.
This is the function I call (which works):
public String getOpleidingByCode(String code) {
this.opleiding = this.opleidingFacade.getOpleidingByCode(code);
return "details";
}
I hope any of this makes any sense?
Sorry if the solution is super clear but I am new to all of this.
Thanks in advance!
Kind regards
Deflandrex
EDIT:
This is the function that I use to call the first view (from which I provided the code)
public String getOpleidingenOpThema() {
this.opleidingen = this.opleidingFacade.getOpleidingenOpThema();
return "resultaat";
}
Both the functions are located in 1 controller.
What happens with the current code :
The outcome value is processed for each link element in the datatable sequentially by calling the opleidingController. getOpleidingByCode(o.opl_code). The backing bean method sets the this.opleiding value corresponding to the o.opl_code. Once all the links's outcome values are processed this.opleiding holds the value of the last o.opl_code. Hence, you are seeing last value from the list in the details page.
One Proposed solution:
The this.opleiding value should be set in the controller based on the o.opl_code when you process the details after clicking the link and not when the link is displayed and the outcome is set. You need to
Set outcome="details" in the h:link tag as this value is static and does not change based on any logic in the backing bean and remove method binding.
Pass the value of o.opl_code as a request parameter to the link as given below within the h:link tag.
<f:param name="opl_code" value="#{o.opl_code}"/>
Have the detail backing bean load the this.opleiding value based on the request parameter opl_code. This way you will have details for specific opl_code based on what link you click.
Is there a way to specify the order in which the inputs should be set after a submit?
Here is my case:
<h:inputText id="fieldA" value=#{myBean.myObject.fieldA}" />
<h:inputText id="fieldB" value=#{myBean.myObject.fieldB}" />
<p:autoComplete id="myObject" value=#{myBean.myObject" converter="myObjectConverter" />
<h:inputText id="fieldC" value=#{myBean.myObject.fieldD}" />
<h:inputText id="fieldD" value=#{myBean.myObject.fieldC}" />
The issue I am encountering is that, as the inputs are processed in the ordered they are declared, fieldA and fieldB are set in the initial instance of myObject, then myObject is set (with a new instance thus filedA and fieldB values are lost), and finally fieldC and fieldD are set with no problem.
If I could manage to start by setting myObject first, that would solve my problem.
I will temporarily set the fields and myObject into two different attributes of my bean, and populate myObject after clicking a save button. But it looks more like a hack than a real solution.
Needless to say that declaring the autocomplete before the inputtexts is not an option.
Thanks in advance.
In shortcut:
You can use <p:inputText> tag from primefaces. Then, you can disable all inputs. Add ajax to your autoComplete, and update other inputs after processing autoComplete. Inputs disable attribute can be set to depend on whether the autoComplete is not null. This way you will make the user to enter the autoComplet first.
you can try to set immediate="true" to p:autocomplete, so that it will be processed in the APPLY_REQUEST_VALUES phase, before all other components.
The simple solution is to update h:inputTexts when p:autocomplete item is selected to reflect its values:
<p:autoComplete id="myObject" value="#{myBean.myObject}" ...>
<p:ajax event="itemSelect" process="#this" update="fieldA fieldB fieldC fieldD" />
</p:autoComplete>
but this reverts user inputs on h:inputTexts. And since you can't move p:autocomplete on top, probably this is not acceptable too.
In case you can't/don't want to use ajax, you can force an early model update:
<p:autoComplete id="myObject" value="#{myBean.myObject}" immediate="true"
valueChangeListener="#{component.updateModel(facesContext)}" ... />
but, in my opinion, this is not very user friendly...
P.S. this time it's tested :)
There's no pretty way to get around this; your situation is already less than ideal and is hacky (re: not being able to simply reorder the fields). One workaround is for you to set fieldA and fieldB as attributes of myObject. In the converter, you could then pull the values off the components. Observe
Set attributes thus
<h:inputText id="fieldA" binding=#{fieldA}" />
<h:inputText id="fieldB" binding=#{fieldB}" />
<p:autoComplete id="myObject" value=#{myBean.myObject" converter="myObjectConverter">
<f:attribute name="fieldA" value="#{fieldA}"/>
<f:attribute name="fieldB" value="#{fieldB}"/>
</p:autoComplete>
The binding attribute effectively turns those components into page-scoped variables, allowing you to then pass them as attributes on your p:autocomplete
Get the values of those variables in your converter
//Retrieve the fields and cast to UIInput, necessary
//to retrieve the submitted values
UIInput fieldA = (UIInput) component.getAttributes().get("fieldA");
UIInput fieldB = (UIInput) component.getAttributes().get("fieldB");
//Retrieve the submitted values and do whatever you need to do
String valueA = fieldA.getSubmittedValue().toString();
String valueB = fieldB.getSubmittedValue().toString();
More importantly, why can't you just reorder the fields/logical flow of your form? You can avoid all this nasty business if you did
I am using JSF 2.0. When I am trying to use a variable in the 'id' attribute of the h:dataTable its not taking that variable value.
I have h:dataTable inside ui:repeat with id values as index of ui:repeat as mentioned below.
<ui:repeat var="planMap" value="#{planAccountMap.entrySet().toArray()}" varStatus="planMapStatus">
<h:dataTable id="planTable#{planMapStatus.index}" value="#{planMap.value}" var="accountList">
Does any one know whether we can have dynamic id generated for h:dataTable in loop?
I have a Java script which is making use of table id, but as I am not able to have the unique id for each table in the loop, its breaking.
Any component inside of a repeatable component will always have a dynamic client id. You cannot do this.
Perhaps instead you can assign a unique style class to the dataTable component and use a jQuery selector to return an array of all the dataTable objects in the ui:repeat.
jQuery('.SomeClass');
I do some thing very similar to you. i have a UI:repeat inside a datatable column. tbh, if you check in fire bug, your datatable id would be unique as you put it inside a ui:repaet.
planMap:0:yourdatatableID
This problem can be solve by using datatable inside datatable. Second datatable is kept inside the column of the first datatable as below.
<h:dataTable id="outerTable" value="#{planAccountMap.entrySet().toArray()}" var="planMap" width="100%">
<h:column>
<h:dataTable id="planTable" value="#{planMap.value}" var="accountList"
headerClass="tablehead"
rowClasses="'',altrowcoloropt1"
first="0">
<h:column>
<f:facet name="header">
<h:outputText value="Date" />
</f:facet>
<h:outputText value="#{accountList.date}"/>
</h:column>
<h:column>
<f:facet name="header" >
<h:outputText value="Account Name" />
</f:facet>
<h:outputText value="#{accountList.accountName}"/>
</h:column>
</h:dataTable>
</h:column>
</h:dataTable>
By this you would get unique id as outerTable:0:planTable, outerTable:1:planTable.This even extend the unique id to each element in datatable as outerTable:1:planTable:1:columnid , outerTable:0:planTable:0:columnid
I'm having trouble making a dataTable where each row has a inputText and a commandLink. When the link is clicked, only it's row's inputText's data is submitted.
Something like this?
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:inputText value="#{bean.value}"/>
</h:column>
<h:column>
<h:commandLink action="#{bean.save}" value="save">
<f:setPropertyActionListener target="#{bean.item}" value="#{item}" />
</h:commandLink>
</h:column>
</h:dataTable>
Bean:
#RequestScoped
public class Bean {
private Item item;
private String value;
Right now, as it is, it's using the last row's inputText to fill the value. I wrapped another h:form, but it broke other things and I've learned that nested h:form is not the right way to do it hehe
What's the correct way to do this?
Thanks.
You're binding the value of all HTML input elements to one and same bean property. This is of course not going to work if all those HTML input elements are inside the same form. All values are subsequently set on the very same property in the order as the inputs appeared in the form. That's why you end up with the last value. You'd like to move that form to inside the <h:column> (move; thus don't add/nest another one).
The usual approach, however, would be to just bind the input field to the iterated object.
<h:inputText value="#{item.value}"/>
An alternative, if you really need to have your form around the table, is to have a Map<K, V> as bean property where K represents the type of the unique identifier of the object behind #{item} and V represents the type of value. Let's assume that it's Long and String:
private Map<Long, String> transferredValues = new HashMap<Long, String>();
// +getter (no setter necessary)
with
<h:inputText ... value="#{bean.values[item.id]}" />
This way you can get it in the action method as follows:
String value = values.get(item.getId());
By the way, if you happen to target Servlet 3.0 containers which supports EL 2.2 (Tomcat 7, Glassfish 3, etc), then you can also just pass the #{req} as a method argument without the need for a <f:setPropertyActionListener>.
<h:commandLink ... action="#{bean.save(item)}" />
See also:
How and when should I load the model from database for h:dataTable
How can I pass selected row to commandLink inside dataTable?
How to dynamically add JSF components
How can i set row level rendering in datatable JSF.
<h:dataTable styleClass="tablesub" border="0" value="#{historyQuestBean.answerMasterList[row].inputTextKeySet}" var="option">
<h:column>
<h:outputText value="#{option.sectionShortName}:"/>
</h:column>
<h:column>
<h:outputText value="#{option.type}:"/>
</h:column>
</h:dataTable>
I want to render only those rows who have status true.
How can I do this?
Easier and Simplest thing is to pass the list of values with status = true
In <h:datatable> you can give a style class within rowClasses say renderer and in that class specify a condition like display:#{option.status==true}?'block':'none'. This will evaluate the EL and accordingly place the style of that <tr\> to display or not.
Another option is to use <ui:repeat> instead of <h:datatable>, Here you can place rendered condition for the <tr>.