Get HashMap value by dynamic key in EL - jsf

I have a data table which contains "Package" objects and 2 columns (packageBarcode and address). I need to add a column (total number of letters in a package), but this value is not in the object. That's why, I used HashMap. I mapped the packageId and totalNumberOfLetters in this HashMap. I want to display this values in dataTable. How can I do this?
<p:column headerText="package"
sortBy="#{package.barcode}"
filterBy="#{package.barcode}"
>
<h:outputText value="#{package.barcode}" />
</p:column>

Provided a
private List<Package> packages;
private Map<Long, Integer> totalNumberOfLettersByPackageId;
you can access it as below
<h:dataTable value="#{bean.packages}" var="_package">
<h:column>#{bean.totalNumberOfLettersByPackageId[_package.id]}</h:column>
</h:dataTable>
Do note that I prefixed package with _, because package is a Java literal and a sane EL implementation would throw a runtime exception on that.

Related

Can't we give two values for one lable in JSF?

I have one label field which is license and I want give two license numbers for this..how to give two values here. I have one properties file (manageprofile) and one java class (manageprofiledatabean) which contains the license values
<h:outputLabel value="#('label.manageprofile.license')"/>
<h:outputText value="#{manageProfileDataBean.license}" />
<h:outputText escape="false" value=" "></h:outputText>
Concat both values in one string variable of manageProfileDataBean and then set it in
public class ManageProfileDataBean{
private String license = "";
private String val1 = "val1":
private String val2 = "val2";
public ManageProfileDataBean(){
license = val1+val2;
}
//setter getter
}
firstly, h:outputLabel is meant to be used for labelling input controls - it renders as the html <label> tag(e.g.)
<h:outputLabel for="myname" value="#{bean.labelValue}" />
<h:inputText id="myname" value="#{bean.name} />
If you need to specify multiple values in expression language you can do so like this:
<h:outputText value="#{bean.property1 bean.property2}"/>
so I guess in your case you would write it as
<h:outputText value="#{'label.manageprofile.license' manageProfileDataBean.license}" />
Finally, you don't need to use an h:outputText if you're not referenceing any propery so the last pair of nbsp characters don;t need to be in in outputText tag at all.

p:selectOneMenu get just first value from list primefaces JSF

i have p:selectOneMenu, all values are viewed correctly but just first on my list can be chosen for example, on my list i have e-mail addresses, i can choose everyone but mail is sending just on first of them on list. My JSF code:
<p:dataTable value="#{additionalOrdersBean.additionalOrdersList}"
var="additionalOrders" rowIndexVar="lp" id="myTable" editable="true>
<p:column>
<p:selectOneMenu id="recipient" value="#{additionalOrdersBean.mailTo}" converter="#{mailConverter}" required="true" requiredMessage="#{loc['fieldRequired']}">
<f:selectItems value="#{buildingBean.buildingList2}" var="mail" itemLabel="#{mail.mail1}" itemValue="#{mail.mail1}" />
<f:selectItems value="#{buildingBean.buildingList2}" var="mail" itemLabel="#{mail.mail2}" itemValue="#{mail.mail2}" />
<f:selectItems value="#{buildingBean.buildingList2}" var="mail" itemLabel="#{mail.mail3}" itemValue="#{mail.mail3}" />
</p:selectOneMenu>
<h:message for="recipient" style="color:red"/>
<h:commandButton value="#{loc['send']}" action="#{additionalOrdersBean.sendProtocol()}" onclick="sendProtocolDialog.hide()"/>
</p:column>
</p:dataTable>
My bean:
private String mail1;
private String mail2;
private String mail3;
public List<Building> getBuildingList2() {
buildingList2 = getBldRepo().findByLocationId(lid);
return buildingList2;
}
Can anyone know how to fix it? I wont to send e-mail on choosen address not just on first on my list. Thanks
You seem to expect that only the current row is submitted when you press the command button in the row. This is untrue. The command button submits the entire form. In your particular case, the form is wrapping the whole table and thus the dropdown in every single row is submitted.
However, the value attribute of all those dropdowns are bound to one and same bean property instead of to the currently iterated row.
The consequence is, for every single row, the currently selected value is set on the bean property, hereby everytime overriding the value set by the previous row until you end up with the selected value of the last row.
You've here basically a design mistake and a fundamental misunderstanding of how basic HTML forms work. You basically need to move the form to inside the table cell in order to submit only the data contained in the same cell to the server.
<p:dataTable ...>
<p:column>
<h:form>
...
</h:form>
</p:column>
</p:dataTable>
If that is design technically not an option (for example, because you've inputs in another cells of the same row, or outside the table which also need to be sent), then you'd need to bind the value attribute to the currently iterated row instead and pass exactly that row to the command button's action method:
<p:dataTable value="#{additionalOrdersBean.additionalOrdersList}" var="additionalOrders" ...>
<p:column>
<p:selectOneMenu value="#{additionalOrders.mailTo}" ...>
...
</p:selectOneMenu>
...
<h:commandButton value="#{loc['send']}" action="#{additionalOrdersBean.sendProtocol(additionalOrders)}" ... />
</p:column>
</p:dataTable>
It's by the way not self-documenting and quite confusing to have a plural in the var name. Wouldn't you rather call it additionalOrder? Or is the javabean/entity class representing a single additional order really named AdditionalOrders?
Unrelated to the concrete problem: doing business logic in getter methods is killing your application. Just don't do that. See also Why JSF calls getters multiple times.

How to evalute JSF EL Expressions which readed from DB

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

How to save h:inputText values of a h:dataTable? My attempt only saves the value of last row

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

jsf primefaces datatable filtering issues

I am using primefaces and its datatable. A few columns are dates or currencies. If I try to filter those, there are awkward behaviours. When I start typing the filter works until the first delimiter (dot for date for example, so it only filters for 11. the next character let the table to display no entry).
Is it possible to apply a dateconverter?
Here is my code for now:
<p:column filterBy="#{cou.startDate}"
headerText="#{text['date']}"
filterMatchMode="contains"
sortBy="#{cou.startDate}" >
<h:outputText value="#{cou.startDate}" >
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
</p:column>
Instead of directly using the cou.startDate from the model, you can instead do the following:
Create a new transient property in the model class.
#Transient
private String dateForFilter;
public String getDateForFilter() {
return dateForFilter;
}
public void setDateForFilter(String dateForFilter) {
this.dateForFilter = dateForFilter;
}
Create the logic below before returning the data model.
public List<Item> getDataModel() {
List<Item> lstItem = serviceClass.loadItem(userid);
for (Item item : lstItem) {
DateFormat dateFormat = null;
Date date = item.getDate;
dateFormat = new SimpleDateFormat("MM/dd/yyyy kk:mm");
item.setDateForFilter(dateFormat.format(date));
}
return lstItem;
}
Update your XHTML to use the dateForFilter property.
<p:column filterBy="#{item.dateForFilter}">
<f:facet name="header">
Transaction Date
</f:facet>
<h:outputText value="#{item.dateForFilter}" />
</p:column>
Note: You can only use this if you're not using the date to update the content of the model class.
HTH.
As far as I know, you can't use a converter for the filter value. You can, however, deal with that in your bean/service/dao logic.
You could hardcode your logic and use SimpleDateFormat to parse the value if the filter column matches certain name like startDate or endDate. A more generic approach would be to use reflection to get the Class associated with the column and use SimpleDateFormat if it's Date, DecimalFormat if it's a number and so on.
Naturally if you're propagating that query to a database, you won't be able to use the like operator. If you're using a number you'll need to compare for equality (same applies to dates). If you're looking for stuff that's in memory you'll have to change you logic a little bit. But it shouldn't be too bad. If you could post some of your backing bean/service code, I guess I could be a little more helpful ;)
There is no ready-made date filter mechanism in primefaces yet, but there is a possibility to filter by date using a custom filter. You will have to define a header facet for your column and use ajax calls for "manual" filtering, but it does work:
<f:facet name="header">DateRange
<div>
<p:calendar id="from" value="#{bean.from}" styleClass="calendarFilter">
<p:ajax event="dateSelect" listener="#{ctrlr.filterDates()}" update="dataTableId"/>
</p:calendar>
<p:calendar id="to" value="#{bean.to}" styleClass="calendarFilter">
<p:ajax event="dateSelect" listener="#{ctrlr.filterDates()}" update="dataTableId"/>
</p:calendar>
</div>
</f:facet>

Resources