I'm creating a webshop and I have it taking info from a SQL database and putting in into an array of items in a bean called MySQLBean. So far so good.
private void doSelect() {
try {Connection conn = ds.getConnection();
try {PreparedStatement dbQuery = conn.prepareStatement("SELECT * from item");
ResultSet resultset = dbQuery.executeQuery();
results.clear();
while(resultset.next()){
results.add(new Item(resultset.getInt("id"),
resultset.getString("name"),
resultset.getDouble("price"),
resultset.getString("description")));
}
}
finally {conn.close();
}
}
catch (SQLException e){e.printStackTrace();}
}
Now I have a button on the site which sends the ID from the item intended for purchase to another bean called ShoppingCartBean.
<h:form prependId="false">
<h:commandLink id="addToCart"
action="#{shoppingCartBean.addToCart(item.id)}"
styleClass="btn btn-default">
<i class ="icon-search"></i> #{msgs.addToCart}
</h:commandLink>
</h:form>
After having sent the item.id data to my shoppingCartBean, I wish to select the item with the corresponding id from the array I loaded earlier and add that entire item to a new array so that I can print the list of items to my user at a later time. But I'm completely stumped on how to do this.
EDIT: Formatted wrong
EDIT: Attempted to clarify question
Just send the entire item #{item} instead of only its ID #{item.id}.
In other words, instead of
action="#{shoppingCartBean.addToCart(item.id)}"
do
action="#{shoppingCartBean.addToCart(item)}"
with
public void addToCart(Item item) {}
Related
I have a simple form using primefaces and JSF. On clicking save, it displays another jsf page where I have a primefaces datatable. It should display the newly created record in the datatable which is not the case. In order to see the new record, I have to go back to another page, then reopen the page where I have the datatable. And I can see the new record. How to solve this issue such that on clicking save I can see the new record?
<p:dataTable id="dta" value="#{CarComponent.listCars}" var="current" rows="15" paginator="true" paginatorPosition="bottom">
</dataTable>
//method where listCars is populated
public String carLists(){
listCars = new arrayList(carDao.findAll());
return "/jsf/listOfcars.xhtml";
}
//save method - on clicking save it should display the datatable
public String save(Cars car){
carService.save(car);
return "/jsf/listOfcars.xhtml";
}
public String getlistCars() {
return listCars;
}
public void setlistCars(String listCars) {
this.listCars = listCars;
}
I can only guess, but I assume that the CarService class is at least ViewScoped or even SessionScoped? In either way, as Fritz said in the comment, the list of cars is obviously not updated since the view is not re-rendered.
You can either do a redirect with return "/jsf/listOfCars.xhtml?faces-redirect=true" if the bean is #ViewScoped, or you have to add the newly generated car to the list of cars like
public String saveCar(Car car) {
carService.save(car);
listCars.add(car);
return "/jsf/listOfCars.xhtml";
}
I spent already more time as is good about some saving or updating issue in inputtext field, i go right to the point:
i have basic single input text with some basic attributtes
<h:inputText id="name" value="#{salesController.selectedSalesName}" />
here is a getter for inputText value
public String getSelectedSalesName(){
for(DealerListView dealer : dealerList){
if(dealer.getDealerId() == getSelectedDealerId()){
return dealer.getName();
}
}
return "";
}
nested in there i use ajax tag
<f:ajax event="change" render="name" listener="#{salesController.updateSelectedSalesName()}" />
a here is back bean method for updating a input text field
public void updateSelectedSalesName() {
DealerData dealDat = BeanFactory.getHotelDAOService(DealerData.class).findOne(selectedDealerId);
dealDat.setName(name);
BeanFactory.getHotelDAOService(DealerData.class).update(dealDat);
}
whole result of this is stack trace which say
value="#{salesController.selectedSalesName}": Property 'selectedSalesName' not writable on type sk.hotel.web.controller.SalesController
I know that something changes is need for that getter method but try some combinations without result which make corect update of value to database.
(I dont use any commands buttons for submit,update only response on pressing Enter in that inputText field.)
I want some guide how can be modified this save/update process whether on back-bean or jsf layout
or maybe someone solved similar situation already,and can share his solution.
Thanks all of you for advice posts.
Regards and nice day
First, add a field:
String selectedSalesName;
Add a setter and setter:
public String getSelectedSalesName() {
return selectedSalesName;
}
public void setSelectedSalesName(String selectedSalesName) {
this.selectedSalesName = selectedSalesName;
}
Add a ajaxListener(AjaxBehaviurEvent event) to create a new Dealer or Update current Dealer
public void ajaxListener(AjaxBehaviorEvent event) {
Dao dao = BeanFactory.getHotelDAOService(DealerData.class)
if (selectedDealerId == null) {
DealarData dealerData= new DealerData();
dealerDate.setName(getSelectedSalesName());
dao.add(dealerData);
setDealer(dealerData);
} else {
DealerData dealDat = dao.findOne(selectedDealerId);
dealDat.setName(name);
dao.update(dealDat);
}
}
A setter to the current dealer
int selectedDealerId;
public void setDealer(DealerData dealer) {
selectedDealerId = dealer.getId();
selectedSalesName = dealer.getName();
}
And the xhtml page:
<h:inputText value="#{salesController.selectedSalesName}" id="idSalesInput">
<a4j:ajax event="keyup" listener="#{salesController.ajaxListener}"
execute="idSalesInput"/>
</h:inputText>
Change "keyup" for the event you want to listen.
When you press a key, the listener is called, and the value of idSalesInput is submitted (the setSelectedSalesName() method is called here, for this reason you got the Property 'selectedSalesName' not writable exception),and the listener create or update a new DealerData.
Have a nice Day and sorry for my bad english!
Binding value in your inputText is two way, when it is rendered than getter is called to calculate value, when it is submited (like in your AJAX event) setter is called for that property to set value in your backing bean. So JSF tries to call setSelectedSalesName(String value). JSF can't write your property, which means can't call setter.
See also:
AJAX listener not being fired for inside
I use <h:dataTable> to list data from database. We have many records in page, now I would like to select multiple records with a checkbox in each row. How can I achieve this?
I assume that your entity is that well-designed that it has an unique technical identifier, for example the auto increment sequence from the DB.
public class Entity {
private Long id;
// ...
}
If not, you'll need to add it.
Then, add a Map<Long, Boolean> property to the bean which is tied to the table.
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
(preinitialization can also happen in (post)constructor, take your pick, at least JSF won't do it for you; oh, give it a getter as well, a setter is not necessary)
Then, add a column with a checkbox which maps to the boolean value by entity ID as key.
<h:dataTable value="#{bean.entities}" var="entity">
<h:column>
<h:selectBooleanCheckbox value="#{bean.checked[entity.id]}" />
</h:column>
...
</h:dataTable>
<h:commandButton value="Delete" action="#{bean.delete}" />
Now, in the action method associated with the delete button, you can collect and delete the checked items as follows:
public void delete() {
List<Entity> entitiesToDelete = new ArrayList<Entity>();
for (Entity entity : entities) {
if (checked.get(entity.getId())) {
entitiesToDelete.add(entity);
}
}
entityService.delete(entitiesToDelete);
checked.clear();
loadEntities();
}
I'm trying to create a paginated, sortable datatable using MyFaces. The sorting works fine; I can click on a column header and it will sort the data based on the column. Also the pagination works fine for the most part. The datatable will split itself appropriately with some number of items per page. In addition, I want the user to be able to change the number of items displayed per page. Again, this seems to be working until I want all of the items displayed on one page.
According to this reference (also here), if you set the "rows" attribute of t:datatable to "0", it will display the remaining rows in the table. However, when I try this, I get an exception that includes this message:
javax.faces.FacesException - You need to set a value to the 'rows' attribute of component 'myComponent'
I'm trying to set the number of items per page using an attribute in a backing bean. My t:datatable looks like this:
<t:dataTable id="myComponent" var="cur"
value="#{backingBean.list}" sortAscending="#{backingBean.ascending}"
sortColumn="#{backingBean.sortColumn}" sortable="true"
styleClass="myClass" rowClasses="oddRow,evenRow"
rows="#{backingBean.itemsPerPage}" preserveDataModel="false">
<!-- data here -->
</t:datatable>
Later, I have a t:dataScroller to control the pagination:
<t:dataScroller id="pageNavigation" for="myComponent"
paginatorActiveColumnStyle="font-weight:bold;"
renderFacetsIfSinglePage="false"
binding="#{backingBean.scroller}"
paginator="true" >
<!-- facets here -->
</t:dataScroller>
Then, I have a h:selectOneMenu to select the number of items per page
<h:selectOneMenu id="myScroller"
value="#{backingBean.itemsPerPage}"
required="true" onchange="this.form.submit();"
valueChangeListener="#{backingBean.updateItemsPerPage}">
<f:selectItems value="#{backingBean.itemsPerPageArray}" />
</h:selectOneMenu>
My backing bean looks something like this:
public class BackingBean {
private boolean ascending;
private Long itemsPerPage;
private String sortColumn;
private ArrayList<SelectItem> itemsPerPageArray;
private ArrayList<SomeObject> list; // data for table
private HtmlDataScroller scroller;
// constructors, getters, setters, and other stuff here
public void updateItemsPerPage(ValueChangeEvent valueChangeEvent) {
itemsPerPage = (Long) valueChangeEvent.getNewValue();
resetScrollerIndex();
}
private void resetScrollerIndex() {
if (scroller!=null && scroller.isPaginator())
scroller.getUIData().setFirst(0);
}
// called in constructor
private void constructItemsPerPageArray() {
itemsPerPageArray = new ArrayList<SelectItem>();
itemsPerPageArray.add(new SelectItem(new Long(10), "10"));
itemsPerPageArray.add(new SelectItem(new Long(50), "50"));
itemsPerPageArray.add(new SelectItem(new Long(100), "100"));
itemsPerPageArray.add(new SelectItem(new Long(0), "All"));
}
}
To sum up, when I select the "All" item from the h:selectOneMenu, I get the exception mentioned above. Hopefully, I've included an appropriate level of detail. Thanks!
Alright, I think I found the answer...
If I remove the first line from the updateItemsPerPage method, the problem is fixed. The method now looks like:
public void updateItemsPerPage(ValueChangeEvent valueChangeEvent) {
resetScrollerIndex();
}
It thought I had tried that...
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.
}