How to correctly call method from jsf to ManagedBean - java

well I'm learning jsf/hibernate and I'm having trouble understanding how to correctly call methods to my ManagedBean
its a simple CRUD so I need to pass vía the jsf form a Ciclista object, but since the inputs are Ciclista attributes how do I pass the Object ? (how to create instance of it) here's the code:
#Override
public String create(Ciclista c) {
Session s = sFac.openSession();
s.beginTransaction();
s.save(c);
s.getTransaction().commit();
s.close();
return "Administrador?faces-redirect=true";
}
and jsf form:
<h:form class="form">
<div id="input-wrapper">
<h:inputText class="inputs" value="#{ciclistaBeanDB.nombre}" />
<h:inputText class="inputs" value="#{ciclistaBeanDB.nacionalidad}" />
<h:inputText class="inputs" value="#{ciclistaBeanDB.equipo}" />
</div>
<h:commandButton class="btn" action="#{ciclistaBeanDB.create()}" value="Create" />
</h:form>
I get error: method not found because i don't pass the Ciclista c object in crear(//here)
since i don't have the object per se, just its attributes how do I proceed ??

You are getting the MethodNotFoundException, because you wrote crear instead of Create.
But the right way to do it, would be to call a save() method without arguments, which is responsible to assemble your object you want to persist.
Since you are already binding your input fields to bean properties, all you would need to do is, use a method like this:
public String save(){
Ciclista c = new Ciclista();
c.setNombre(this.nombre);
c.setNacionalidad(this.nacionalidad);
c.setEquipo(this.equipo);
create(c);
return "Administrador?faces-redirect=true";
}
your commandbutton now should target the save() method of your bean. The input values in the form will be inserted into your baking bean properties and the save() method would assemble the instance and finally calls your persist-method.
<h:commandButton class="btn" action="#{ciclistaBeanDB.save}" value="Create" />
Usually you should not call the DatabaseBean directly, but kind of a Controller - or how ever one would like to call it. This Bean then should utilize your database-service which should only be responsible for CRUD-Functionality.
At least for big applications it would be a mess having the databasemethods and other (view-related) methods mixed in one class.

Related

Can you have a scanner input to name a database table and its fields to xhtml fields [duplicate]

I am building a JSF application. I defined the GUI and did the select statements query the database using select.
Now I must do the insert statements, but I don't know how to read the value of a JSF input component like <h:inputText> and send it to my bean which performs the insert.
Should <h:inputText> value be mapped through faces-config.xml, so I can have it in my Java code?
You need to put all <h:inputXxx>/<h:selectXxx> components in a <h:form> and bind their value attribute to a bean property via an EL expression like #{bean.property}, backed by a getter/setter pair. When properly set, JSF will automatically set the values in the bean when the form is submitted via a <h:commandXxx> component in the very same form. You can specify a bean action method in action attribute of the <h:commandXxx> component via an EL expression like #{bean.action}, which points to the bare method action(). All submitted values are available right away there the usual Java way.
Given this JSF form example with one input field and one select field:
<h:form>
<h:inputText value="#{bean.text}" required="true" />
<h:selectOneMenu value="#{bean.choice}" required="true">
<f:selectItem itemValue="#{null}" />
<f:selectItem itemValue="One" />
<f:selectItem itemValue="Two" />
<f:selectItem itemValue="Three" />
</h:selectOneMenu>
<h:commandButton value="submit" action="#{bean.submit}" />
<h:messages />
<h:outputText value="#{bean.result}" />
</h:form>
The following bean prints the submitted values to the stdout, proving that JSF has already set the values long before the moment you access it in the action method.
package com.example;
import javax.inject.Named;
import javax.enterprice.context.RequestScoped;
#Named // Use #javax.faces.bean.ManagedBean on outdated environments.
#RequestScoped // Use #javax.faces.bean.RequestScoped on outdated environments.
public class Bean {
private String text;
private String choice;
private String result;
public void submit() {
result = "Submitted values: " + text + ", " + choice;
System.out.println(result);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getChoice() {
return choice;
}
public void setChoice(String choice) {
this.choice = choice;
}
public String getResult() {
return result;
}
}
That's all. Turning the regular form into an ajax form is a matter of nesting a <f:ajax> in the command component as below.
<h:commandButton value="submit" action="#{bean.submit}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
You can find another example and valuable links at bottom of our JSF wiki page.
Do note that whatever you intend to do with the submitted values is beyond the responsibility of JSF. For example, manipulating it, passing into another class, saving it in database, etc. None of this all is related to JSF. It has as being a HTML form based framework already done its job of providing you the submitted values in flavor of usable Java variables. The remainder is up to you.
To investigate the next step, you should at this point just be doing as if you've already a bunch of prepared / hardcoded variables instead of a whole JSF based user interface. For example, in order save to the values in a database, people usually use a business service layer framework like EJB which in turn uses a persistence layer framework like JPA. Some people even use "plain vanilla" JDBC for that. For more links to concrete examples, start here: JSF Controller, Service and DAO.

Primefaces cannot update p:tree

I'm working with primefaces 4.0 and JSF 2.2 and I'm currently trying to update a form with a p:tree on it. The commandButton works correctly but it does not update the form or call the init() method until I manually refresh the page. I don't know what I'm doing wrong since the same code does work for a DataTable element.
Here's the code:
<h:form id="preferenciasForm">
<div id="panelTree">
<p:panel id="defTree" style="margin-bottom: 20px">
<p:tree value="#{dtPreferencesBuilder.root}" var="node"
selectionMode="checkbox"
selection="#{dtPreferencesBuilder.selectedNodes}"
style="width:100%; height:100%;" animate="true">
<p:treeNode>
<h:outputText value="#{node.label}" />
</p:treeNode>
</p:tree>
<p:commandButton value="Add preferences"
icon="ui-icon-pencil"
actionListener="#{dtPreferencesBuilder.insertPrefNodes()}"
update=":preferenciasForm" ajax="true" />
</p:panel>
</div>
</h:form>
And here's is the java class.
#ManagedBean(name="dtPreferencesBuilder")
#ViewScoped //I've tried with or without the ViewScoped, neither work
public class PreferencesBuilderBean {
private TreeNode root;
private TreeNode prefRoot;
private TreeNode[] selectedNodes;
#PostConstruct
public void init() {
System.out.println("Building Tree");
selectedNodes=null;
root=null;
prefRoot=null;
root=getStandardTree();
prefRoot=getPreferedTree();
}
The init() is not called as the print is only show on manual reload so the tree is not updated nor the selectedNodes refreshed. Any ideas why it doesn't work?
As I cannot describe bean scopes better than excellent answers already given for similar questions I'll just refer you to the answers by BalusC and Kishor P here.
The init-method (or any method with the #PostConstruct-annotation) will be called by the framework only when the bean is created, after injections and therefore after the constructor has run as rion18 said. It would not be normal to use the method for anything else than initializing work. So create other methods, and call those from actions and actionListeners.
If you want the bean to be the same when you call it with ajax (as you do) it needs to be at least ViewScoped. If you really do want to call the init() every time it should be RequestScoped, but then the bean will be new when you call it with ajax and not remember a thing.

ui:include dependent on viewParam

I have a page where I want to include a part of the page (footer in this instance) dependant on values given from a view parameter.
I have my ViewScoped backing bean initializing on preRenderView
<f:metadata>
<f:viewParam name="racecode" value="#{displayResults.racecode}" />
<f:event type="preRenderView" listener="#{displayResults.init}" />
</f:metadata>
This queries the database to get the name of the footer to be included. This then, is used in this fashion :
<h:panelGroup id="customFooter" display="block">
<ui:include src="#{displayResults.customFooter}" />
</h:panelGroup>
This always gives me a missing page. But if I enter the page name manually it works. Same if I replace the ui:include with an h:outputText.
I understand that it has something to do with the phases of JSF and that at the time the ui:include is done, the value is not set yet. (reading up and better understanding the phases is something on my TODO list).
The question remains. How can I get something of the sort done. Have a bean use the viewParam, query the database and use that value in a ui:include?
#wemu has already explained the cause. The <ui:include src> is evaluated before init() method is called. His proposed <f:phaseListener> solution is however clumsy.
Just use #ManagedProperty/#PostConstruct on a #RequestScoped bean.
#ManagedProperty("#{param.racecode}")
private String racecode;
#PostConstruct
public void init() {
// ...
}
PreRenderView listeners are called within the RenderResponsePhase, before components are rendered BUT AFTER the TagHandlers are called. This means that TagHandlers will NOT see data initialized within a PreRenderView event.
If you are using a <ui:include value="#{myBean.myViewId}" /> to dynamically switch an include you can't use a PreRenderView event listener to set the myViewId property of myBean.
If you need to do that use a <f:phaseListener>.

Elegant handling of attributes without a session bean

I'm working on an application using JSF 2.0 and Richfaces 4, that consists of many tables that display elements and of course, the usual View/Edit/Delete options. After some SO browsing and Google search I've decided to post a question because the answers I found did not solve my problem.
Right now, and going straight to the point, my application is having issues when handling certain attributes that are stored in request beans and, on certain points, are lost due to successive requests.
For example, when I want to edit an object, the object is sent (f:propertyActionListener) to a request bean that displays the data on a form, then it is discarded as that request ends. When saving, a new object is created and the attributes on the form are setted to it and the item gets saved instead of updated, since it has no id (JPA + Hibernate).
I've investigated many options and this is what I've did so far and the results:
f:param + h:link or h:commandLink: With #ManagedProperty the param is null, and I can't find it on the Context to look it up through JNDI.
f:setPropertyActionListener + h:commandLink + Request Bean: Works... but I'm losing some data. The form that displays the data has some conditionally rendered fields and I can't hold that info, so the form is messed if the validation phase finds invalid data.
f:viewParam + h:commandLink + View Scoped Bean: Weird stuff here. This one doesn't directly work because the bean seems to get discarded before rendering the form, because the form is rendered with no information since the bean is clean.
Using a session bean: Works like a charm, but I don't want to make a session bean for every form just because I'm still learning things about the JSF lifecycle, I want to do it the proper way.
If I want to keep the Request session approach, is there a way to store a parameter (either an object or a plain string) and obtain later on a request bean?.
Dunno if this helps but I'm using a master page through ui:insert and ui:define.
Use a view scoped bean. It should work. The problems which you describe there suggests that you're binding it to JSTL tags or id or binding attributes. You should not do that on a view scoped bean. See also #ViewScoped fails in tag handlers. Another possible cause is that you're using CDI's #Named to manage the bean instead of JSF's #ManagedBean. That would also explain why #ManagedProperty doesn't work in one of your attempts as it also requires the bean to be managed by JSF's #ManagedBean.
As to the master-detail page approach, use a <h:link> with <f:param> in the table page to create view/edit links in the master page.
E.g. user/list.xhtml
<h:dataTable value="#{userList.users}" var="user">
<h:column>#{user.id}</h:column>
<h:column>#{user.name}</h:column>
<h:column>
<h:link value="Edit" outcome="edit">
<f:param name="id" value="#{user.id}" />
</h:link>
</h:column>
</h:dataTable>
The bean can be just request scoped.
Then, in the defail page, which is in this case an edit page, use <f:viewParam> to convert, validate and set the id as User.
E.g. user/edit.xhtml
<f:metadata>
<f:viewParam name="id" value="#{userEdit.user}"
converter="#{userConverter}" converterMessage="Bad request. Unknown user."
required="true" requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:messages />
<h:link value="Back to all users" outcome="users" />
<h:form id="user" rendered="#{not empty userEdit.user}">
<h:inputText value="#{userEdit.user.name}" required="true" />
...
<h:commandButton value="Save" action="#{userEdit.save}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
Use a #ViewScoped bean to hold the data, service and action methods:
#ManagedBean
#ViewScoped
public class UserEdit {
private User user;
#EJB
private UserService service;
public String save() {
service.save(user);
return "users";
}
// Getter+setter.
}

How to preserve a object through multiple pages

I have an ArrayList of objects and I use them as follow:
<ui:repeat value="#{BookReview.books}" var="book" >
<li>
<h:commandLink value="#{book.bookName}" action="detail" />
</li>
</ui:repeat>
in the detail page I show the book's comments, and I have a form to register a new comment:
<h:form>
Name:<h:inputText value="#{Comment.author}" />
Rate:<h:inputText value="#{Comment.rate}" />
Text:<h:inputText value="#{Comment.comment}" />
<h:commandButton action="#{book.addComment(Comment)}" value="Add Comment" />
</h:form>
My problem is that book isn't preserved until the next Request and #{book.addComment(Comment)} results in Target Unreachable, identifier 'book' resolved to null.
I have tried annotate the book as RequestScoped, didn't work, then I've modified to ViewScoped, didn't work either, then I tried to use a <inputHidden > to keep the object around, but it just uses a .toString() and I can't reuse the object.
I don't want to use session to store the object because I need it only once, and I don't think I want to use a converter because Book has a ArrayList of comments (also I think it is to cumbersome and complicated)
Put your BookReview bean to the session scope (or, if you're on JSF-2.0 - then let it have the view scope).
You've got to keep a handle of the current book somewhere and relate the new comment with it.
Create a new bean, BookDetail.
#ManagedBean
#ViewScoped
public class BookDetail {
private Book book;
private Comment comment = new Comment();
public String addComment() {
book.getComments().add(comment);
// You need to persist book here if necessary.
return "list";
}
// Add/generate getters/setters the usual way.
}
Set the selected book as follows (could be done nicer if you were using an UIData component like h:dataTable or t:dataList instead of ui:repeat):
<h:commandLink value="#{book.name}" action="detail">
<f:setPropertyActionListener target="#{bookDetail.book}" value="#{book}" />
</h:commandLink>
Rewrite the detail form as follows:
<h:form>
Name:<h:inputText value="#{bookDetail.comment.author}" />
Rate:<h:inputText value="#{bookDetail.comment.rate}" />
Text:<h:inputText value="#{bookDetail.comment.comment}" />
<h:commandButton action="#{bookDetail.addComment}" value="Add Comment" />
</h:form>

Categories