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";
}
Related
I need to create a custom component that either extend or include a Primefaces SelectOneMenu. This is done so that I can deliver the select items based on the field (for now, they are hardcoded in the example below and the tag is properly registered).
The component is rendered and the select items are also displayed fine. However, when I save, the record's field is not updated with the selected item's value. Is there some primeface method I should override to actually set the value?
Are there any tutorials on how to extend primeface (or atleast jsf) components? I could hardly find any. Thank you in advance
#FacesComponent(value = ComponentRegistry.INPUT_SELECTDROPDOWN_COMPONENT_TYPE)
public class InputSelectDropdown extends SelectOneMenu {
#Override
public void encodeBegin(FacesContext context) throws IOException {
this.setValueExpression("value", this.getValueExpression("value"));
UISelectItem select1 = new UISelectItem();
select1.setItemLabel("item 1");
select1.setItemValue("item1");
select1.encodeAll(context);
this.getChildren().add(select1);
UISelectItem select2 = new UISelectItem();
select2.setItemLabel("item 2");
select2.setItemValue("item2");
select2.encodeAll(context);
this.getChildren().add(select2);
super.encodeBegin(context);
}
}
My Idea/Requirement is to render dynamically generated jsf page and bind/capture the user filled data and save into db. Dynamically rendering part is working fine but not able to capture the user filled data back to my managedbean. I am using Jsf 2.1.
LoginManagedBean.java (requestscoped)
private String fieldName;
//getters and setters
public String trytry()
{
HtmlInputText inputText = (HtmlInputText) FacesContext.getCurrentInstance().getApplication().createComponent(HtmlInputText.COMPONENT_TYPE);
inputText.setId("it");
inputText.setValueExpression("value", FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(FacesContext.getCurrentInstance().getELContext(),"#{loginmb.keyValueMap['" + inputText.getId() + "']}", String.class));
panelGroupChilds.add(inputText);
grid.getChildren().add(panelGroupTextbox);
return "done";
}
public String save() {
System.out.println("fieldName --- " + this.fieldName);
return "save";
}
done.xhtml (dynamically rendered page)
<h:panelGrid binding="#{loginmb.docGridElems}"></h:panelGrid>
<h:commandButton id="cndB" value="SAVE" action="#{loginmb.save()}"></h:commandButton>
I am able to see the rendered textbox in done.xhtml but on submit the save button, I am not able to get the value of "feildName" (it is null). I am not able to find where i went wrong.
I even tried to bind the Map but could not able to get it.
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'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...
JSF view code:
<f:view>
<h:form>
<h:panelGrid>
<h:inputText id="key" value="#{myManagedBean.key}"/>
<h:selectBooleanCheckbox id="rerun" value="#{myManagedBean.rerun}" rendered="#{myManagedBean.displayRerun}"/>
<h:commandButton id="check" action="#{myManagedBean.check}"/>
</h:panelGrid>
</h:form>
<f:view>
JSF model code:
public class MyManagedBean {
private boolean displayRerun;
public void setDisplayRerun(boolean aDisplayRerun) {
this.displayRerun = aDisplayRerun }
public boolean getDisplayRerun() {
return this.displayRerun;
}
private String key;
public void setKey(String aKey) {
this.key = aKey
}
public String getKey() {
return this.key;
}
private boolean rerun;
public void setRerun(boolean arerun) {
this.rerun = arerun
}
public boolean getRerun() {
return this.rerun;
}
public String check() {
//do data validation
setDisplayRerun(true);
System.out.println(getRerun());
}
}
This always prints false regardless of whether the checkbox is checked or not.
Additional Information on my requirement:
Nick/BalusC, my managed bean is of request scope. It is indeed simplified code snippet that I presented. My page has couple of user input controls along with a command button. On submit of command button, I call action method of backing bean, in which I do data validation (in this case I lookup database and see if the inputs are already registered.) If already registered, I come back to the same page, this is when I display the singleBooleanCheckBox for the user to select and hit the command button again.
I am toggling the display of the checkbox based on a managedbean property (a boolean flag set during data validation).
When I re-submit the page with checkbox checked, I do not receive this data.
For further verification, I replace the selectBooleanCheckbox, with a command button with similar behavior (basically do not render it initially, but only show it on data validation). I mapped its #action to my managedbean's action method. To my surprise, when I hit the button, the action method is not executed. Instead, the page is refreshed like in a "immediate" scenario or a redirect.
I have been struggling on this for almost 6 hrs. Appreciate your experienced insights.
Thanks.
So, you've actually a rendered attribute on the checkbox (that was not present in your initial question) and the bean is request scoped (it would have worked when it was session scoped). The submitted checkbox value will not be gathered during apply request values phase when this attribtue evaluates false at that point.
You basically need to retain the condition responsible for the rendered attribute in the subsequent request as well. This can be done in several ways: putting bean in session scope, using Tomahawk's t:saveState or h:inputHidden with a bean binding. Each is outlined in detail in this answer.