empty ui:repeat, is the component created? - forms

I am trying to debug an issue with the following code:
<h:panelGroup id="items">
<ui:repeat value="#{itemController.items}" var="item">
<h:form>
<h:inputText id="title" value="#{item.fields['Title']}"/>
<a4j:commandButton action="#{dao.storeItem(item)}" value="Save" render="#form"/>
</h:form>
</ui:repeat>
</h:panelGroup>
The above works if a collection is displayed in the view directly. However, if the ui:repeat starts empty, and items are added through an AJAX request, and the ui:repeat rerendered, the forms break. Specifically the model is not updated, nor actions triggered. I want to understand why.
Right now my guess is that if the ui:repeat starts empty, the form component is not created at all. Can anyone verify this, or provide the correct explanation?
ADDITIONAL INFO
Here are relevant parts of the controller, I have also tried ViewScoped, and long-running conversations:
#Named
#ConversationScoped
public class ItemController implements Serializable
{
private static final long serialVersionUID = 1L;
#Inject
private HibernateDAO dao;
public List<Item> getItems()
{
return dao.getItems();
}
public void uploadListener(final FileUploadEvent event)
{
final UploadedFile item = event.getUploadedFile();
final FacesContext context = FacesContext.getCurrentInstance();
final Application application = context.getApplication();
final String messageBundleName = application.getMessageBundle();
final Locale locale = context.getViewRoot().getLocale();
final ResourceBundle resourceBundle = ResourceBundle.getBundle(messageBundleName, locale);
final String msg = resourceBundle.getString("upload.failed");
final String detailMsgPattern = resourceBundle.getString("upload.failed_detail");
try
{
CSVImporter.doImport(item.getInputStream(), dao, item.getName());
}
catch (ParseException e)
{
final Object[] params = {item.getName(), e.getMessage()};
final String detailMsg = MessageFormat.format(detailMsgPattern, params);
final FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, detailMsg);
context.addMessage("uploadForm:uploader", facesMsg);
}
catch (TokenMgrError e)
{
final Object[] params = {item.getName(), e.getMessage()};
final String detailMsg = MessageFormat.format(detailMsgPattern, params);
final FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, detailMsg);
context.addMessage("uploadForm:uploader", facesMsg);
}
}
}
The dao simple fetches the items from a database. Here is the relevant fileupload code:
<h:form id="uploadForm" enctype="multipart/form-data">
<h:message id="message" showDetail="true" for="uploader" errorClass="error" warnClass="warning" infoClass="info" fatalClass="fatal"/>
<rich:fileUpload id="uploader"
fileUploadListener="#{itemController.uploadListener}"
maxFilesQuantity="1"
acceptedTypes="csv"
render="items message" />
</h:form>

Okay posting it here because it will be longer than comments .
It works for me which is probably not what you wanted to hear :( but I had to teak few minor things . Firstly in controller add
public void storeItems(Item item)
{
dao.storeItems();
}
then change this
<a4j:commandButton action="#{dao.storeItem(item)}" value="Save" render="#form"/>
to
<a4j:commandButton action="#{itemController.storeItem(item)}" value="Save" render="#form"/>
That however is probably not the real issue and I think that is around here
CSVImporter.doImport(item.getInputStream(), dao, item.getName());
basically I am expecting that the method above would have uploaded data from where dao.getItems(); can fetch it. So put a breakpoint at public List<Item> getItems() and once file has been upload and render="items message" renders the items panel group again it should will hit this method and at that time see if dao.storeItems() is bringing any data back which it should. Reply back then and we will take it from there.
Update below to avoid running dao fetch twice.
You can not avoid two calls to your get thats part of JSF lifeCycle and is normal.
How ever you can avoid hitting the database twice as you should too but refactoring your code along the lines of
private List<Item> items;
public List<Item> getItems()
{
return items;
}
#PostConstruct
public void init()
{
this.items = dao.getItems();
}
public void uploadListener(FileUploadEvent event) throws Exception{
......
CSVImporter.doImport(item.getInputStream(), dao, item.getName());
this.items = dao.getItems();
.....
}

Related

Value is not valid using entryset

This issue arrived when I tried to use a LinkedHashMap to save entries from a database. I don't know to what extent the xhtml code is working, but superficially looks well.
The issue is in this part of the xhtml:
<tbody>
<tr>
<td>Movie:</td>
<!--td>
<h:selectOneMenu id="foundmovieid" value="#{webRental.idmovie}">
<f:selectItems id="movieid" value="#{webMovie.get_all_movies()}"></f:selectItems>
</h:selectOneMenu>
</td-->
<td>
<h:selectOneMenu value="#{webRental.idmovie}">
<f:selectItems value="#{webMovie.availableMovies.entrySet()}" var="entry"
itemValue="#{entry.key}" itemLabel="#{entry.value}" />
</h:selectOneMenu>
</td>
</tr>
</tbody>
</table>
<h:commandButton value="Submit" action="#{webRental.save()}"></h:commandButton>
Here is the WebRental.java:
public class WebRental {
#EJB
private RentalsFacade rf;
private String iduser;
private String idmovie;
//getters and setters
public List<Rentals> get_all_rents() {
return rf.findAll();
}
public void save() {
try {
rf.Save(iduser, idmovie);
} catch (Exception e) {
}
}
}
and the WebMovie.java, whose MoviesFacade has an EntityManager and a way to persist new pbject Movies (id, title, director's name and length):
#Named
#RequestScoped
public class WebMovie {
#EJB
private MoviesFacade mf;
private String id;
private String title;
private String director;
private int length;
private Map<String, String> availableMovies;
//geters and setters
public List<Movies> get_all_movies() {
availableMovies = new LinkedHashMap<>();
List<Movies> found = mf.findAll();
found.forEach((m) -> {
String first = m.getId();
String second = m.getTitle() + ", " + m.getDirector() + ", " + m.getLength() + " minutes.";
availableMovies.put(first,second);
});
return mf.findAll();
}
public void save() {
try {
mf.Save(id, title, director, length);
} catch (Exception e) {
}
}
}
In the xhtml, theres a muted section, which is just what I have to do (get id's and submit them) but in a way that you only see the id's. The unmuted section is the part im having trouble with, since it says that the value is invalid.
To solve this do I have to use "converters"? If so, how do I implement it? If not, what is my error?
Also, in the muted section there is a call to "get_all_movies()", but since it's muted, it shouldnt be called. How do I call that function outside of that muted section so I can delete the whole section after I get the SelectOneMenu with the map working?
Turns out using Maps is very strange...
How I solved this was by removing most of the SelectItems so that it just is:
<f:selectItems value="#{webMovie.availableMovies}" />
And then changing the way I insert everything to the Map like so:
#PostConstruct
public void init() {
availableMovies = new HashMap<>();
mf.findAll().forEach((m) -> {
availableMovies.put((String) m.getTitle() + ", " + m.getDirector() + ", " + m.getLength() + " minutes.",(String) m.getId());
});
//Turns out that, for the selectItems to read properly the map, you have to insert the text you want to be displayed as the key, and then the value as value. I was doing it backwards.
}
That way I dont have to depend on the !--'d section that calls get_all_movies() and I could delete it!

From an select item in the list, create another listbox ZK

I had a headache with this. I want to choose a book from the 1st list and with that book create a second list to be able to show the details of the book (title, number of pages)
Here is the code:
public class Book {
private int numBook;
private String nameBook;
private String author;
public Book(int numBook, String nameBook, String author) {
super();
this.numBook = numBook;
this.nameBook = nameBook;
this.author = author;
}
public int getNumBook() {
return numBook;
}
public void setNumBook(int numBook) {
this.numBook = numBook;
}
public String getNameBook() {
return nameBook;
}
public void setNameBook(String nameBook) {
this.nameBook = nameBook;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
Class BookData: Load the info in array
public class BookData {
private List<Book> books = new ArrayList<Book>();
public BookData() {
loadBooks();
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public void loadBooks() {
Book b;
for(int i = 0; i<4;i++){
b = new Book(i+1, "Libro "+i+1, "Author "+i+1);
books.add(b);
}
}
}
Class BookViewModel: ViewModel of Listbox
public class BookViewModel {
private static Book selectedBook;
private List<Book> booksData = new ArrayList<Book>(new BookData().getBooks()); // Armo los libros
public List<Book> getBooksData() {
return booksData;
}
public void setBooksData(List<Book> booksData) {
this.booksData = booksData;
}
//Getters and Setter the SelectedCar
#NotifyChange("selectedBook")
public Book getSelectedBook() {
if(selectedBook!=null) {
//setSelectedBook(selectedBook);
new DetailData(selectedBook);
//new ArrayList<>(new DetailData().getDetailsFilterByBook());
//Then here pass the Book Selected
}
return selectedBook;
}
public void setSelectedBook(Book selectedBook) {
this.selectedBook = selectedBook;
}
}
Class Detail: Detail Model of the choose Book
public class Detail {
private int idBook;
private String title;
private int numPages;
public Detail(int idBook, String title, int numPages) {
this.idBook = idBook;
this.title = title;
this.numPages = numPages;
}
public int getIdBook() {
return idBook;
}
public void setIdBook(int idBook) {
this.idBook = idBook;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getNumPages() {
return numPages;
}
public void setNumPages(int numPages) {
this.numPages = numPages;
}
#Override
public String toString() {
return "Detail [idBook=" + idBook + ", title=" + title + ", numPages=" + numPages + "]";
}
}
Class DetailData: Load the data in array
//Clase que se ecarga de manejar la data
public class DetailData {
private List<Detail> details = loadAllDetails();
private List<Detail> detailsFilterByBook;
private static Book bookSelected;
/*public DetailData(){
//Previously all the data is loaded
System.out.println(bookSelected);
detailsFilterByBook = new ArrayList<>();
filterDetailsByBook();
}*/
public void setBookSelected(Book bookSelected){
this.bookSelected = bookSelected;
}
public DetailData(){
this(bookSelected);
}
public DetailData(Book b){
bookSelected = b;
System.out.println(bookSelected);
detailsFilterByBook = new ArrayList<>();
filterDetailsByBook();
}
public List<Detail> loadAllDetails(){
List tmp = new ArrayList<Detail>();
//Libro 1
Detail d1b1 = new Detail(1, "Preview", 15);
Detail d2b1 = new Detail(1, "Inicio", 10);
Detail d3b1 = new Detail(1, "Zk Bind", 50);
//Libro 2
Detail d1b2 = new Detail(2, "Introduccion", 15);
Detail d2b2 = new Detail(2, "JAVA", 100);
Detail d3b2 = new Detail(2, "CSS", 25);
//Libro 3
Detail d1b3 = new Detail(3, "HTML", 35);
Detail d2b3 = new Detail(3, "Javascript", 40);
Detail d3b3 = new Detail(3, "Ajax", 25);
//Libro 4
Detail d1b4 = new Detail(4, "Android", 100);
Detail d2b4 = new Detail(4, "IOS", 100);
tmp.add(d1b1);
tmp.add(d2b1);
tmp.add(d3b1);
tmp.add(d1b2);
tmp.add(d2b2);
tmp.add(d3b2);
tmp.add(d1b3);
tmp.add(d2b3);
tmp.add(d3b3);
tmp.add(d1b4);
tmp.add(d2b4);
return tmp;
}
private void filterDetailsByBook() {
for(Detail d:details){
if(d.getIdBook() == bookSelected.getNumBook())
detailsFilterByBook.add(d);
}
print();
}
public void print(){
System.out.println("Imprimiendo detalles del libro escogido");
for(Detail d: detailsFilterByBook){
System.out.println(d);
}
}
public List<Detail> getDetails() {
return details;
}
public void setDetails(List<Detail> details) {
this.details = details;
}
public List<Detail> getDetailsFilterByBook() {
return detailsFilterByBook;
}
public void setDetailsFilterByBook(List<Detail> detailsFilterByBook) {
this.detailsFilterByBook = detailsFilterByBook;
}
}
Class: DetailViewModel:ViewModel of the second ListBox
public class DetailViewModel {
private List<Detail> detailsData = new ArrayList<>();
#NotifyChange("detailsData")
public void refreshList(){
System.out.println("REFRESH");
detailsData = new ArrayList<>(new DetailData().getDetailsFilterByBook());
}
public List<Detail> getDetailsData() {
return detailsData;
}
#NotifyChange("detailsData")
public void setDetailsData(List<Detail> detailsData) {
this.detailsData = detailsData;
}
}
Here is the zul file
<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer" viewmodel="#id('vm') #init('book.BookViewModel')">
<listbox model="#bind(vm.booksData)" selecteditem="#bind(vm.selectedBook)" emptymessage="No car found in the result">
<listhead>
<listheader label="Num Libro"/>
<listheader label="Libro"/>
<listheader label="Autor"/>
</listhead>
<template name="model" var="book">
<listitem>
<listcell label="#bind(book.numBook)"/>
<listcell label="#bind(book.nameBook)"/>
<listcell label="#bind(book.author)"/>
</listitem>
</template>
</listbox>
<separator height="100px"/>
<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('detail.DetailViewModel')">
<listbox model="#bind(vm.detailsData)" emptyMessage="No existen datos que presentar">
<listhead>
<listheader label="Num Capitulos"/>
<listheader label="Titulo del Cap"/>
</listhead>
<template name="model" var="detail">
<listitem>
<listcell label="#bind(detail.idBook)"/>
<listcell label="#bind(detail.title)"/>
<listcell label="#bind(detail.numPages)"/>
</listitem>
</template>
</listbox>
</window>
</window>
I try in the second listbox (At begin have to be empty), show the details of the book everytime when a book in the 1st listbox is selected. I get the correct info. When I choose a book, I get the correct details of that book, but my second listbox does'nt show anything. I will apreciate all the help. PD: Sorry for the english
Oke, there are more points to say on this code then you imagine.
Never use static for a user/session variable.
In your VM you have the following code :
private static Book selectedBook;
Imagine that I select Book 1 and you select 2 seconds later Book 2.
Because it's static, I'm also having Book 2 selected, while mine view isn't aware of it.
This means the GUI and server side are out of sync => never a good thing.
If you could be able to sync the view with the selected item, this means that you select book 2 for me and I'll be searching the number of the Ghost Busters.
With ZK, always use ListModel interface to give collections to GUI.
While returning List<Book> works pretty good, you need to understand the consequences of this action.
A List or Grid expect an implementation of ListModel and if you don't give it, there will be one created every time you notify the list of a change.
While this is a nice to have feature it also removes the intelligence of a listmodel and the GUI rendering will be a lot more.
An example is always more clear :
We have a Collection of 9 items and we will append 1 to it.
Adding 1 Object to the List and notifying it implies that all the content rendered of the Listbox will be removed and then adding all the content again to the Listbox.
This means that we are removing and adding 9 lines who aren't changed.
Adding 1 Object to a ListModel, even without notifying the ListModel of a change will result in an action where there is only 1 item appended to the Listbox. This is the intelligence of a ListModel => adding and removing items will be persisted to the GUI without overhead.
So your code should be looking like this :
private Book selectedBook;
private final ListModelList<Book> booksData = new ListModelList<Book>(new BookData().getBooks()); // Armo los libros
Why not working to the interface and why final?
So I just told you about the interface ListModel and yet, I'm setting an implementation of ListModel as code, even while we learn to work against interfaces.
The simple reason is that ListModel doesn't have methods for appending and removing items while the implementation do have it.
So I make a decision to work against that object in stead of casting it when I need the methods.
Remember, the global getter for the booksData can look like this :
public ListModel<Book> getBooksData() {
return booksData;
}
So here we hide the implementation of ListModelList to the outside.
The reason for final is that you will forcing yourself or other people who are going through the code to use the clear() method in stead of making a new ListModelList.
It's just not needed to create a new instance of it.
Using 2 viewmodel's
Your making yourself difficult of using 2 VM's.
But while it's sometimes a good idea to do this I'll be helping you to get your problem solved.
Your first problem is one of a naming kind.
Viewmodel 1 => called vm in the zul.
Viewmodel 2 => called vm in the zul.
You see it coming? who will listen when I cry to vm?
let's call the viewmodel of the details detailVM
viewModel="#id('detailVM') #init('detail.DetailViewModel')"
The second problem is that your detail viewmodel doesn't have any clue of the first listbox.
What do I want to say is that your second viewmodel should be holding the correct info of the selected item of the first listbox.
Zul code should be looking like this :
<window title="" border="none" height="100%" apply="org.zkoss.bind.BindComposer" viewmodel="#id('vm') #init('book.BookViewModel')">
<div apply="org.zkoss.bind.BindComposer"
viewModel="#id('detailVM') #init('detail.DetailViewModel')">
<listbox model="#init(vm.booksData)" selecteditem="#bind(detailVM.selectedBook)" emptymessage="No book found in the result">
<listhead>
<listheader label="Num Libro"/>
<listheader label="Libro"/>
<listheader label="Autor"/>
</listhead>
<template name="model" var="book">
<listitem>
<listcell label="#load(book.numBook)"/>
<listcell label="#load(book.nameBook)"/>
<listcell label="#load(book.author)"/>
</listitem>
</template>
</listbox>
<separator height="100px"/>
<listbox model="#init(detailVM.detailsData)" emptyMessage="No existen datos que presentar">
<listhead>
<listheader label="Num Capitulos"/>
<listheader label="Titulo del Cap"/>
</listhead>
<template name="model" var="detail">
<listitem>
<listcell label="#load(detail.idBook)"/>
<listcell label="#load(detail.title)"/>
<listcell label="#load(detail.numPages)"/>
</listitem>
</template>
</listbox>
</div>
</window>
So I set you up with the correct zul, and now it's up to you to modify the viewmodels.
Remember that I set selectedBook in detailVM so now it's not needed in the first viewmodel.
I don't write everything for you, otherwise you wouldn't learn from it.
Some small things left to say.
You see I change the listbox model to #init and not #bind.
A model is always read only, so please NEVER NEVER NEVER use #bind.
#load is the highest annotation you could use, and this is only the case when you will create a new instance for the ListModel, witch is hardly needed.
Labels, are also not updatable in your GUI.
Again #bind is over the top, #load should be used in normal situations (when the value can change, so most commonly) or #init when the value will never change, but if you use #load I'll be happy already.
Hope this could set you to the right direction.
If you have any other question, just comment below.

AEM 6.1 Sightly basic form submit and redirect to same page

I am trying to do the following on AEM 6.1:
Develop a simple form (3 input fields)
Process the submitted values,
And redirect to the same page with processed values/result
I am able to submit the values to a servlet, and process them (business logic), and the result to a requestparamter so i can retrieve them on the UI. But i am stuck at these:
Redirecting to the same page
And retrieving the request parameters and display them using Sightly.
Code Snippets:
Servlet
#SlingServlet(
methods = { "POST","GET" },
name="com.tti.tticommons.service.servlets.LeadTimeTrendsServlet",
paths = { "/services/processFormData" }
)
public class TTICommonServlet extends SlingAllMethodsServlet{
...
#Override
protected void doPost(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
String result;
try {
Enumeration<String> parameterNames = request.getParameterNames();
Map<String, String> formParametersMap = new HashMap<String, String>();
while (parameterNames.hasMoreElements()) {
paramName = parameterNames.nextElement();
paramValue = request.getParameter(paramName);
.......
.......
}
request.setAttribute("result",result);
response.sendRedirect("/content/ttii/en/**posttest.html**");
}
}
Can anyone please help on ho to retireve the above "result" in posttest.html using sightly.
After lot of research and several trials, i finally had the code working. I had to pick up related info from several answers in stackoverflow. Thanks to all the authors. Posting my solution here so beneficial for others.
Result Form with response from webservice:
Process flow
Submit form data to Servlet's POST method
In Servlet, get the values entered by the user from the request
Make the necessary webservice calls. Get the response(json)
I added the response-json as a parameter to the request
Using Wrapper, forward to the necessary page
Define a WCMUse class for use with Sightly.
Assign the 'request' to the Use-class and process it there
Use the assigned values from the Use-class to the UI using sightly
Code snippets - HTML
<form name="userRegistrationForm" method="post" action="/services/processFormData">
<input type="hidden" name=":redirect" value="posttest.html" />
<input type="submit" title="Submit" class="btn submit btn-success" value="Submit" tabindex="25" name="bttnAction">
<div data-sly-use.model="${'com.abccommons.service.helpers.PostServiceHelper' # slingreq=request }">
**${model.getRawJson}**
</div>
Code snippets - Servlet
#SlingServlet(
label = "ABC - Common Servlet",
metatype = true,
methods = { "POST" },
name="com.abccommons.service.servlets.ABCPostServlet",
paths = { "/services/processFormData" }
)
public class ABCPostServlet extends SlingAllMethodsServlet{
#Override
protected void doPost(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
log.info("\n\n----- ABCPostServlet POST: ");
String paramName;
String paramValue;
String osgiService="";
try {
Enumeration<String> parameterNames = request.getParameterNames();
Map<String, String> formParametersMap = new HashMap<String, String>();
while (parameterNames.hasMoreElements()) {
paramName = parameterNames.nextElement();
paramValue = request.getParameter(paramName);
if (paramName.equals("osgiService")) {
osgiService = paramValue;
} else if (paramName.equals(":cq_csrf_token")) {
//TODO: don't add to the map
} else if (paramName.equals("bttnAction")) {
//TODO: dont' add to the map
} else {
//log.info("\n---ParamName="+paramName+", value="+paramValue);
formParametersMap.put(paramName, paramValue);
}
}
String parametersInJSON = JSONHelper.toJson(formParametersMap);
log.info("\n\n----------- POST paramters in json="+parametersInJSON);
String json = webServiceHelper.getJSON(osgiService, parametersInJSON, request, response);
log.info("\n\n----------- POST json from web service="+json);
request.setAttribute("jsonResponse",json);
//String redirectPage = request.getParameter(":redirect");
//RequestDispatcher dispatcher = request.getRequestDispatcher("/content/en/"+redirectPage);
RequestDispatcher dispatcher = request.getRequestDispatcher("/content/en/postformtest.html");
GetRequest getRequest = new GetRequest(request);
dispatcher.forward(getRequest, response);
} catch (Exception e) {
log.error("SlingServlet Failed while retrieving resources");
} finally {
//TODO
}
}
/** Wrapper class to always return GET for AEM to process the request/response as GET.
*/
private static class GetRequest extends SlingHttpServletRequestWrapper {
public GetRequest(SlingHttpServletRequest wrappedRequest) {
super(wrappedRequest);
}
#Override
public String getMethod() {
return "GET";
}
}
Code snippets - PostServiceHelper - WCMUSe class
public class PostServiceHelper extends WCMUse {
protected final Logger log = LoggerFactory.getLogger(PostServiceHelper.class);
private SlingHttpServletRequest httpRequest;
private String rawJson;
#Override
public void activate() throws Exception {
log.info("\n\n========= PostServiceHelper.activate():"+get("slingreq", SlingHttpServletRequest.class));
this.httpRequest = get("slingreq", SlingHttpServletRequest.class);
//this.resourceResolver = getResourceResolver();
//log.info("\n\n========= getRequest()="+getRequest());
SlingHttpServletRequest tRequest;
Set<String> keys = new HashSet<String>();
Enumeration<?> attrNames = this.httpRequest.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attr = (String) attrNames.nextElement();
//log.info("\n--- Key="+attr);
if (attr.equals("jsonResponse")) {
this.setRawJson((String)this.httpRequest.getAttribute(attr));
//log.info("\n---rawJson is SET with : "+this.rawJson);
}
}
}
public void setRawJson(String json) {
this.rawJson = json;
}
public String getRawJson() {
return this.rawJson;
}
}
This is actually a rather tricky pattern to achieve in Sling. You may be better served by submitting the form asynchronously and updating your HTML dynamically via JavaScript.
If you do need to submit your form in the manner you specify, then your servlet needs to produce the HTML response. To produce a response made up of a rendering of the page identified by the requested path your servlet will need to dispatch the request to the appropriate rendering mechanism. You can reference Get JSP output within Servlet in AEM for information concerning how that can be accomplished. Upon dispatch your page and its components should have access to the submitted form values as well as the attributes set on the request.

primefaces does not render f:selecteditems

here is mycode: there might be some mistakes but I am doing right, I am thinking my problem is in Java code can you please throw some light, I am trying to render radio values.
<p:selectOneRadio id="firstBill" value="#{myClass.myfee}" label="what to do?">
<f:verbatim>
<f:selectItems value="#{myClass.listMyFee}"/>
</f:verbatim>
</p:selectOneRadio>
#Name("myClass")
public class MyClass
{
private String fee;
private Map<String, String> listMyFee;
public Myclass(){
//constructor
listMyFee = new LinkedHashMap<String, String>();
listMyFee;.put("Yes", "Yes");
listMyFee;.put("No", "No");
}
public Map<String, String> getListMyFee()
{
return this.listMyFee;
}
get and set for fee are written
your bean-code is wrong, you need for f:selectItems a list of List<SelectItem>.
It would look like this:
List<SelectItem> list = new LinkedList<SelectItem>();
list.add(new SelectItem(<returnValue>, <displayValue>));
In your xhtml-file:
<p:selectOneRadio id="firstBill" value="#{myClass.myfee}" label="what to do?">
<f:selectItems value="#{myClass.list}" />
</p:selectOneRadio>

Search form that redirects to results page

Hello i have the following problem.
I have a search page lets call it search.xhtml and you can search for a bar-code. This value is unique so the result is always one or zero objects from the database
<p:panelGrid columns="1" style="margin:20px;">
<h:form>
<p:messages id="messages" globalOnly="true" showDetail="false" />
<p:message for="barcode" />
<p:inputText id="barcode" value="#{searchForm.barCode}"
required="true" requiredMessage="Value needed" />
<p:commandButton value="search"
action="#{searchForm.searchBarcode}" id="search"/>
</h:form>
</p:panelGrid>
This is the backingbean:
#ManagedBean
#ViewScoped
public class SearchForm extends BasePage {
private Long barCode;
#ManagedProperty("#{daoManager}")
public DaoManager daoManager;
public void setDaoManager(DaoManager daoManager) {
this.daoManager = daoManager;
}
public Long getBarCode() {
return barCode;
}
public void setBarCode(Long barCode) {
this.barCode = barCode;
}
public String searchBarcode() {
//request to dao to get the object
DataList<Data> data = daoManager.findbybarcode(barCode);
if (data.size() == 0) {
this.addMessage(FacesMessage.SEVERITY_ERROR,
"Not Found: " + barCode);
return null;
} else {
getFacesContext().getExternalContext().
getRequestMap().put("id", data.getId());
return "details";
}
}
So if i go to my details page which expect the parameter id this isnt send to the detail page.
backing bean details page:
#ManagedBean
#ViewScoped
public class DetailBean extends BasePage implements Serializable {
#PostConstruct
public void init() {
if (id != null) {
//Go on with the stuff
} else {
addMessage(FacesMessage.SEVERITY_ERROR,"Object not found");
}
}
}
What am i doing wrong? And is this wrong use of JSF? I know i can generate a list and the click on the result but thats not what i want. Also i can take the barcode from the first bean and pass it as a parameter but i want the details page only to accept the id from the objects. So is my thinking wrong? Or is there a solution to get it like this?
If I understand correctly, you wish to pass the ID of the barcode to the details page and yes this is possible.
getFacesContext().getExternalContext().getRequestMap().put("id", data.getId());
The following line is putting the ID parameter into the request that the client just sent you, but the navigation action to details will result in a different request. Try this instead:
return "details?faces-redirect=true&id=" + data.getId();
This will return an HTTP GET navigation action with the ID of the barcode passed as a request parameter in the request.