i want to know if there is a possibility in JSF or primefaces that allow to input all values of a column( from excel for example ) on a JSF page and submit it to the managed bean. thats mean getting the values in a list in the managed bean .
i designed this figure to let youunderstand what i mean :
Do you have an idea how we can do that ?
Yes, there is a possibility. Here are the necessary steps involved.
Upload an Excel file by using, for example, <p:fileUpload> component:
<h:form enctype="multipart/form-data">
<p:fileUpload value="#{bean.file}" mode="simple"/>
<p:commandButton value="Submit" ajax="false" action="#{bean.upload}"/>
</h:form>
and
public class Bean {
private UploadedFile file;//getter + setter
private List<String> data;//placeholder
public void upload() {
if(file != null) {
extractData(file.getInputstream);
}
}
}
Read the file contents in extractData method by using, for example, Apache POI library:
private void extractData(InputStream is) {
HSSFWorkbook workbook = new HSSFWorkbook(is);
HSSFSheet sheet = workbook.getSheetAt(0);
List<String> data = new ArrayList<String>();
for(Row row : sheet) {
Cell cell = r.getCell(0, Row.RETURN_BLANK_AS_NULL);
if(c != null) {
String content = cell.getStringCellValue();
data.add(String);
}
}
this.data = data;
}
Redisplay data by standard JSF means: bind the retrieved list to some iterative component, ajax-update it, etc.
Related
I am using primefaces. And my requirement is to have number of tabs which will be generated based on a list specified in the backing bean. Now the second criteria is that if the tab changes the content under that tab should also changes. So I kept the onChange event and tried to get the value through event.getTab().getTitle(), but it is returning null to the backing bean.
<p:tabView id="tabView" binding="#{dndProductsView.tabView}">
<p:ajax event="tabChange" listener="#{dndProductsView.onTabChange}"/>
</p:tabView>
Managed Bean required codes are as :-
#PostConstruct
public void init() {
user = SessionBean.getUserName();
categorylist = categoryLogics.findAllOrderedByCategoryName();
productList = productLogics.findAllOrderedByProductName();
droppedProducts = new ArrayList<Product>();
}
private TabView tabView;
#Inject
private FacesContext facesContext;
public void setTabView(TabView tabView) {
this.tabView = tabView;
}
public TabView getTabView() {
tabView = new TabView();
for (Category c : categorylist) {
Tab t = new Tab();
t.setTitle(c.getCategoryName());
tabView.getChildren().add(t);
}
return tabView;
}
public void onTabChange(TabChangeEvent event) {
String titleName = event.getTab().getTitle();
System.out.println("" + titleName);
}
The tab is getting generated properly and when the tab changes, the onTabChange() method is called but event.getTab().getTitle() returns null.
Integer index=(Integer)tabview.getActiveIndex();
It is not a name but it is index of activ tab witch in this case is the one you are interested in.
Index starts from 0 being the first tab :)
I have looked around and could not find a solution.
I am using Omnifaces listConverter in the PickList component of Primefaces. When I move an item from SOURCE to TARGET. In the backing bean i get the new item ONLY on dualList.getTarget().
However when I move an item from TARGET to SOURCE. In the backing bean I am not able to check whether an item has been removed from the TARGET.
I tried dualList.getSource() - SOURCE does not contains the item/s dropped from TARGET
And off course dualList.getTarget() will be empty (assuming that no item is moved from SOURCE to TARGET).
My question is how can i find that something has been moved from TARGET to SOURCE in the backing bean?
Previously I have created a custom converter and in that, my dualList.getTarget() gives me the updated target (ie old values + new values added + old values removed). Therefore I can figure it out which values are added, removed and are still present.
But while using Omnifaces listConverter i am not understanding how to achieve it.
My code looks like this:
XHTML
<p:pickList id="pickList" value="#{assignBenchmarkersBean.dualUserList}"
var="users" itemLabel="#{users.username}" itemValue="#{users}" >
<o:converter converterId="omnifaces.ListConverter"
list="#{assignBenchmarkersBean.dualUserList.source}" />
</p:pickList>
<p:commandButton id="update" value="#{bundle.create}"
styleClass="redButton bigFont"
actionListener="#{assignBenchmarkersBean.update()}" />
Bean
public void update(){
try{
prepareRemoveOldAndAddNewUsersList();
/**some other code **/
}catch(Exception e){
FacesMsg.error(ErrorMessage.UPDATE.getValue(), e);
}
}
private void prepareRemoveOldAndAddNewUsersList() {
for(User user : dualUserList.getTarget()){ //add users
addUsers.add(user);
}
for(User user : dualUserList.getSource()){ //remove users
if(oldUserList.contains(user)){
removeUsers.add(user);
}
}
}
User entity
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof User)) {
return false;
}
User other = (User) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.abc.model.main.User[ id=" + id + " ]";
}
NOTE:
If in the converter's list attribute, I put bean.dualList.target, then the whole thing works the other way around.
It is better to use ajax transfer event for this goal, as described in PrimeFaces User Guide.
XHTML:
<p:pickList id="pickList" value="#{assignBenchmarkersBean.dualUserList}"
var="users" itemLabel="#{users.username}" itemValue="#{users}" >
<o:converter converterId="omnifaces.ListConverter"
list="#{assignBenchmarkersBean.dualUserList.source}" />
<p:ajax event="transfer" listener="#{pickListBean.handleTransfer}" />
</p:pickList>
Bean:
public class PickListBean {
//DualListModel code
public void handleTransfer(TransferEvent event) {
//event.getItems() : List of items transferred
//event.isAdd() : Is transfer from source to target
//event.isRemove() : Is transfer from target to source
}
}
This is how I got it worked for me.
In the implementation of the Omnifaces ListConverter, the getAsObject method is using the list to find the value and update the target and source of dualList.
NOTE: you will get either a new value added in target (List=".getSource") or a new value added in source (List=".getTarget"), as per the List value you have entered.
Hence by changing the List from myBean.dualList.getSource to myBean.completeList, I get the updated target and source (ie old values + new values added + old values removed ).
If a user is only concerned with the new value added in target or source and not on if any value is removed, then he should use myBean.dualList.getSource and myBean.dualList.getTarget respectively.
However if user wants to know the final content as it is in my case, use the whole collection ie myBean.completeList.
In short it is the List which you are passing in the <o:conveter> tag is important.
Hope it will help!!
I came up with a strange problem. I tried to isolate the problem so following is my simplified code.
public class MyBean {
private List<Data> dataList;
Data selectedData;
public MyBean() {
dataList = new ArrayList<Data>();
dataList.add(new Data("John", 16));
dataList.add(new Data("William", 25));
}
public List<Data> getDataList() {
return dataList;
}
public void edit(Data data) {
selectedData = data;
}
public void newData() {
selectedData = new Data(null, null);
}
public Data getSelectedData() {
return selectedData;
}
public class Data {
String name;
Integer age;
Data(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}
xhtml:
<rich:modalPanel id="pop">
<h:form>
Name: <h:inputText value="#{myBean.selectedData.name}" required="true" id="txtName"/><br/>
Age : <h:inputText value="#{myBean.selectedData.age}" required="true" id="txtAge"/>
<a4j:commandButton value="Save"/>
<a4j:commandButton value="Close" onclick="Richfaces.hideModalPanel('pop');return false;"/>
<br/>
<rich:message for="txtName"/><br/>
<rich:message for="txtAge"/>
</h:form>
</rich:modalPanel>
<h:form>
<rich:dataTable value="#{myBean.dataList}" var="data">
<rich:column>#{data.name}</rich:column>
<rich:column>
<a4j:commandLink value="Edit" action="#{myBean.edit(data)}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</rich:column>
</rich:dataTable>
<a4j:commandButton value="New" action="#{myBean.newData()}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</h:form>
This is the path to error:
Load the page
Click the "Edit" link in first row(popup displays)
In popup, clear the "Age" field and click "Save".(Required message shown)
Click cancel(without filling "Age" field)
Click second link.
Now it shows irrelevant data(previous data). - This is the problem
Even when I click "New" button it shows incorrect data.
This happens only if a validation is failed in the popup.
Is there a solution for this?
This problem is in JSF 2 also recognized and explained in detail in the following answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur? If you were using JSF 2, you could have used OmniFaces' ResetInputAjaxActionListener or PrimeFaces' <p:resetInput> or resetValues="true" for this.
To the point, you need to clear the state of the EditableValueHolder component when it's about to be ajax-rendered, but which isn't included in the ajax-execute. To clear the state, in JSF 2 you would have used the convenience method resetValue() for this, but this isn't available in JSF 1.2 and you need to invoke the 4 individual methods setValue(null), setSubmittedValue(null), setLocalValueSet(false), setValid(true) to clear the state.
To figure out which components are to be ajax-rendered, but aren't been ajax-executed, in JSF 2 you would have used PartialViewContext methods for this, but this is not available in JSF 1.2 which hasn't standardized ajax yet. You'd need to fiddle with RichFaces specific ajax API in order to figure that. I can't tell that from top of head, so here's a kickoff example assuming that you already know the components which needs to be cleared. Imagine that the form in your popup has id="popForm" and the name input field has id="nameInput", here's how you could clear it inside the newData() method:
UIInput nameInput = (UIInput) context.getViewRoot().findComponent("popForm:nameInput");
nameInput.setValue(null);
nameInput.setSubmittedValue(null);
nameInput.setLocalValueSet(false);
nameInput.setValid(true);
do one thing on cancel action set all popup values null. now in your next click all values set to be default.
or on click set all previous values null. and set all respective values after that.
I had the same problem. if you are using Primefaces, the solution is as simple as putting resetValues="true" on your p:commandLink or p:commandButton that loads the selected item.
After validation failed if you want to remain same as input data which you have pass as submission parameter, then set value attribute as your form bean name as mention below i.e.
<input type="text" id="fname" path="fname" value="${myFormBean.fname}"/>
Let's say
I have
<h:dataTable var="s" value#{somebean.properties}>
<h:column>
<h:inputText initial=#{s.min} value=#{somebean.mintmp}/>
<h:commandButton action=#{filterbean.addProretryFilter(s.id, somebean.mintmp)} />
</h:column>
</h:dataTable>
"initail" attribute don't exit in inputText.
Is there any way to implement desired functionality?
You can bind your input text field to backing bean and initialize it in constructor or #PostConstruct and set the initial value.
#ManagedBean
public class Bean{
private HtmlInputText inputComponent = new HtmlInputText();
private String min = "5";
private String minData;
#PostConstruct
public void init(){
inputComponent.setValue(min);
}
//....get/set other logic
}
In view you can have
<h:inputText value="#{bean.minData}" binding="#{bean.inputComponent}"></h:inputText>
I think you need to rethink your design. Even without populating the default value, you have a problem. This pseudocode is roughly analogous to your logic:
//beans
SomeBean somebean = ...
DataModel model = ...
FilterBean filterbean = ...
//apply request values phase
for(int i=0; i<model.getRowCount(); i++) {
model.setRowIndex(i)
S s = model.getRowData()
//inputText's state is set to the submitted row state by the dataTable
Object submittedValue = inputText.getSubmittedValue()
somebean.mintmp = submittedValue
}
//invoke application phase
for(int i=0; i<model.getRowCount(); i++) {
model.setRowIndex(i)
S s = model.getRowData();
//commandButton's state is set to the submitted row state by the dataTable
if(commandButton.clicked()) {
filterbean.addProretryFilter(s.id, somebean.mintmp)
}
}
somebean will always be populated with the last row value.
See the JSF lifecycle and the DataModel for more details.
in your managed bean's getter you could return a default value. E.g.
private String mintmp=null;
public String getMintmp()
{
if(mintmp == null)
return "default min";
return mintmp;
}
Use primefaces! There's this really nice update attribute on buttons that update the components you want to refresh. It's magical.
I have a problem with selecting rows in the Primefaces Datatable. I use dynamic columns, so the standard row selection mechanism is not usable here, I implement checkbox selection myself.
To help, here's s simplified version of what I have in my xhtml:
<h:form>
<p:dataTable id="table"
var="result"
value="#{tableBean.results}">
<p:columns value="#{tableBean.columnNames}" var="column" columnIndexVar="colIndex">
<f:facet name="header">
#{column}
</f:facet>
<h:panelGroup rendered="#{colIndex==0}">
<h:outputLabel>#{rowIndex}</h:outputLabel>
<h:selectBooleanCheckbox value="#{tableBean.selectedRows[result[0]]}"/>
</h:panelGroup>
</p:columns>
</p:dataTable>
<h:commandButton value="Submit"></h:commandButton>
</h:form>
And here's what I have in the managed bean to select the checkboxes:
package testpackage;
import java.util.*;
import javax.faces.bean.*;
#ManagedBean
#SessionScoped
public class TableBean
{
private Map<String, Boolean> selectedRows = new HashMap<String, Boolean>();
List<List<String>> results = new LinkedList<List<String>>();
public TableBean()
{
List<String> row1 = new LinkedList<String>();
List<String> row2 = new LinkedList<String>();
row1.add("row1.ref");
row1.add("row1.id");
row1.add("row1.status");
row2.add("row2.ref");
row2.add("row2.id");
row2.add("row2.status");
results.add(row1);
results.add(row2);
//selectedRows.put("row2.ref", true);
}
public Map<String, Boolean> getSelectedRows()
{
return selectedRows;
}
public String submit()
{
List<List<String>> selectedResults = new ArrayList<List<String>>();
for (List<String> result : results)
{
if (selectedRows.get(result.get(0)) != null)
{
selectedResults.add(result);
selectedRows.remove(result.get(0));
}
}
return null;
}
public List<List<String>> getResults()
{
return results;
}
public List<String> getColumnNames()
{
List<String> columnNames = new LinkedList<String>();
columnNames.add("");
columnNames.add("REF");
columnNames.add("ID");
columnNames.add("STATUS");
return columnNames;
}
}
The getSelectedRows method works great, but the problem is that the setSelectedRows method is never called, so I don't know which checkboxes the user has selected. Maybe I overlook something very trivial, but cannot find the solution.
Any ideas on this? I would be very glad if you helped, or give any other row selection solution for the dynamic columns.
Thx in advance,
Levi
To me it looks you are rendering the wrong field in selectBooleanCheckBox.
You should be using variable or field from the result variable.
My solution:
In your situation you are rendering an object from List as a form of table row so if you want to make some changes and retrieve the status of that row then you should be using the variable from that object only.
I understand you are submitting the whole form and want to pickup all updated rows, in that case you will have to loop through the whole List and find all the rows which have been updated by checking the status in Request Handler(Action) bean.
Hope that helps.
The setter is never called for nested objects. You're the one who's responsible for creating them, not JSF. JSF just gets the nested object and then calls the setter on it (which is the put() method in case of a Map). You just need to determine the selected rows in the action method. Add an action method to the commandbutton:
<h:commandButton value="Submit" action="#{bean.submit}"></h:commandButton>
which is definied like follows (guessing/assuming that var="result" is in essence an Object[]):
public String submit() {
List<Object[]> selectedResults = new ArrayList<Object[]>();
for (Object[] result : results) {
if (selectedRows.get((String) result[0])) {
selectedResults.add(result);
selectedRows.remove(result[0]); // Reset.
}
}
// Now selectedResults contains all selected results.
}