I have a mySql table of PROJECTS, which I am displaying as a list in the index.xhtml. The projectid column contains hyperlinks. When they're clicked I would like the specific projectid row selected to be passed as the query argument into another jsf file (ListProjects.xhtml) which displays all the project values referring to the projectid selected in the index.xhtml. The index.xhtml page seems to pass the values correctly (when hovering over the selection the url displays the right id value). When actually clicking the selction I get a blank page in the resulting ListPprojects.xhtml:
I'm not sure if it's my choice of tags on index.xhtml where should be replaced by another tag like CommandLink which maps to a bean action.
Alternatively, is tag in the result page (ListProject.xhtml) the right tag to use to retrieve the projectid value as the query argument?
Also if the projectid is an int, should this first be converted to String by using parseInt or other method?
Is the problem in one of the session beans where projectid is resulting in a null value which causes the result page to render blank records? Any advice is greatly appreciated. Thanks in advance!
The named query in the entity bean (projects.java) is:
#NamedQuery(name = "Projects.findByProjectid", query = "SELECT p FROM Projects p WHERE p.projectid = :projectid")
In the index.xhtml I use the following tag to display the hyperlink:
<h:link value="#{item.projectid}" outcome="ListProject">
<f:param name="projectid" value="#{item.projectid}"/>
</h:link>
The ListProjects.xhtml is the page where I would like to display the project details based on the projectid selected in the index.xhtml (and here's where I start getting confused):
<h:column>
<f:facet name="header">
<h:outputText value="Countryid"/>
</f:facet>
<h:commandLink action="#{selProjectMgtBean.selProjectList}" value="#{item.projectid}"/>
</h:column>
My session bean:
#Stateless
public class ProjectSelectedBean implements ProjectSelectedBeanLocal {
#PersistenceContext(unitName = "QueryTrialNoMavenPU")
private EntityManager em;
#Override
public List<Projects> getSelectedProjects(String projectid) {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
projectid=request.getParameter(projectid);
return em.createNamedQuery("Projects.findByProjectid", Projects.class).setParameter ("projectid", projectid).getResultList();
}
}
Finally the calls the methods for rendering the selection:
package com.manaar.beans;
imports....
#Named(value = "selProjectMgtBean")
#RequestScoped
public class SelProjectMgtBean {
#ManagedProperty(value="#{item.projectid}")
private String projectid;
private List<Projects> selProjectList;
#EJB
private ProjectSelectedBeanLocal projectSelectedBeanLocal;
#PostConstruct
public void init() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance ().getExternalContext().getRequest();
projectid=request.getParameter("projectid");
selProjectList = projectSelectedBeanLocal.getSelectedProjects();
}
public List<Projects> getSelProjectList() {
return selProjectList;
}
public void setSelProjectList(List<Projects> selProjectList) {
this.selProjectList = selProjectList;
}
}
you didn't set :projectId in query:
you can change code as follow:
public List<Projects> getSelectedProjects(String projectId) {
return em.createNamedQuery("Projects.findByProjectid", Projects.class).setParameter("projectId" , projectId).getResultList();
}
Regarding one of your questions:
Use h:link for pure navigational purposes (with the outcome parameter) and h:commandLink to invoke an action directly (with the action parameter). The called method in this case should return a String telling JSF where to navigate next.
Related
I have started learning JSF, but sadly most tutorials out there present only a log in or a register section.
Can you point me to some more in depth examples? One thing I'm interested in is a page presenting a list of products. I'm on page home and I press on page products so that I can see the latest products added. And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
One way to solve this would be to create a session scoped managed bean in which I would place different entities updated through other managed beans. I found this kind of approach in some tutorials, but it seems quite difficult and clumsy.
Which would be the best approach to solve a thing like this? What is the correct usage of session scope in two-page master-detail user interface?
What is the correct usage of session scope
Use it for session scoped data only, nothing else. For example, the logged-in user, its settings, the chosen language, etcetera.
See also:
How to choose the right bean scope?
And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
Typically you use the request or view scope for it. Loading of the list should happen in a #PostConstruct method. If the page doesn't contain any <h:form>, then the request scope is fine. A view scoped bean would behave like a request scoped when there's no <h:form> anyway.
All "view product" and "edit product" links/buttons which just retrieve information (i.e. idempotent) whould be just plain GET <h:link> / <h:button> wherein you pass the entity identifier as a request parameter by <f:param>.
All "delete product" and "save product" links/buttons which will manipulate information (i.e. non-idempotent) should perform POST by <h:commandLink>/<h:commandButton> (you don't want them to be bookmarkable/searchbot-indexable!). This in turn requires a <h:form>. In order to preserve the data for validations and ajax requests (so that you don't need to reload/preinitialize the entity on every request), the bean should preferably be view scoped.
Note that you should basically have a separate bean for each view and also note that those beans doesn't necessarily need to reference each other.
So, given this "product" entity:
#Entity
public class Product {
#Id
private Long id;
private String name;
private String description;
// ...
}
And this "product service" EJB:
#Stateless
public class ProductService {
#PersistenceContext
private EntityManager em;
public Product find(Long id) {
return em.find(Product.class, id);
}
public List<Product> list() {
return em.createQuery("SELECT p FROM Product p", Product.class).getResultList();
}
public void create(Product product) {
em.persist(product);
}
public void update(Product product) {
em.merge(product);
}
public void delete(Product product) {
em.remove(em.contains(product) ? product : em.merge(product));
}
// ...
}
You can have this "view products" on /products.xhtml:
<h:dataTable value="#{viewProducts.products}" var="product">
<h:column>#{product.id}</h:column>
<h:column>#{product.name}</h:column>
<h:column>#{product.description}</h:column>
<h:column>
<h:link value="Edit" outcome="/products/edit">
<f:param name="id" value="#{product.id}" />
</h:link>
</h:column>
</h:dataTable>
#Named
#RequestScoped
public class ViewProducts {
private List<Product> products; // +getter
#EJB
private ProductService productService;
#PostConstruct
public void init() {
products = productService.list();
}
// ...
}
And you can have this "edit product" on /products/edit.xhtml:
<f:metadata>
<f:viewParam name="id" value="#{editProduct.product}"
converter="#{productConverter}" converterMessage="Unknown product, please use a link from within the system."
required="true" requiredMessage="Bad request, please use a link from within the system."
/>
</f:metadata>
<h:messages />
<h:form rendered="#{not empty editProduct.product}>
<h:inputText value="#{editProduct.product.name}" />
<h:inputTextarea value="#{editProduct.product.description}" />
...
<h:commandButton value="save" action="#{editProduct.save}" />
</h:form>
#Named
#ViewScoped
public class EditProduct {
private Product product; // +getter +setter
#EJB
private ProductService productService;
public String save() {
productService.update(product);
return "/products?faces-redirect=true";
}
// ...
}
And this converter for <f:viewParam> of "edit product":
#Named
#RequestScoped
public class ProductConverter implements Converter {
#EJB
private ProductService productService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
Long id = Long.valueOf(value);
return productService.find(id);
} catch (NumberFormatException e) {
throw new ConverterException("The value is not a valid Product ID: " + value, e);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
if (value instanceof Product) {
Long id = ((Product) value).getId();
return (id != null) ? String.valueOf(id) : null;
} else {
throw new ConverterException("The value is not a valid Product instance: " + value);
}
}
}
You can even use a generic converter, this is explained in Implement converters for entities with Java Generics.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
JSF Controller, Service and DAO
JSF Service Layer
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Communication in JSF 2.0 - Contains several examples/hints
As a small improvement to what BalusC recommended, sometimes you can remove the required / requiredMessage part from the <f:viewParam> of your "details" screen and instead use the conditional rendering of the editing form (as BalusC did) with a reverse condition for recommending a specific link for the "list/master" screen or, even use a viewAction that would test the param and force a redirect to that list.
I am building a JSF form which includes a primefaces p:autoComplete component.
The following is an extract from my xhtml page, showing the relvant information about the autoComplete component.
<p:autoComplete
value="#{curAttribute.value}"
completeMethod="#{newBacking.lookupActivated}"
var="curEntry"
itemLabel="#{curEntry.classname}"
itemValue="#{curEntry.id}"
emptyMessage="Start typing..."/>
Please notice that curAttribute is an instance of the CosmoAttribute class, and that the CosmoAttribute.value is a String (of course, CosmoAttribute has all the getters and setters for its fields).
The method newBacking.lookupActivated() returns a List<CosmoCard>.
CosmoCard.classname and CosmoCard.id are both Strings.
I know that I'm woirking with POJOs, but since all my values are String fields from a POJO, I don't think that I need a converter. Anyway, my autoComplete field works fine, but when i select an item, i get the following exception:
SEVERE: Error Rendering View[/test.xhtml]
javax.el.PropertyNotFoundException: /test.xhtml #98,68 itemLabel="#{curEntry.id}": The class 'java.lang.String' does not have the property 'id'.
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
at org.primefaces.component.autocomplete.AutoComplete.getItemLabel(AutoComplete.java:148)
.
.
Caused by: javax.el.PropertyNotFoundException: The class 'java.lang.String' does not have the property 'id'.
at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:730)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:351)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
.
.
Has anyone a clue of what am I doing wrong? You can find a very similar question here, but it was unfortunately unanswered. I am willing to provide more details about my code.
UPDATE:
Actually, everything is working fine: I see the correct value in the dropdown of the p:autocomplete. As i select a value, the data in the backing bean (newBacking) is updated accordingly. I just can't get rid of the exception, which, however, does not have any effect on the execution of my page.
I am respecting the constraints of the tag, i.e. the value attribute and the itemValue are of the same type (both Strings). The only thing that is not properly ok is that the system tries to convert a List in a List, I don't know why, or when, but the failure in the conversion (and the subsequent exception) does not have any effect on the behaviour of my page.
UPDATE:
Here is the link to a very simplified version of the project (netbeans). The relevant files of the project are also listed below.
test.xhtml
<h:body>
<h:form id="form">
<p:dataTable var="curAttribute" value="#{newBacking.card.attributes}">
<p:column >
THE CURSED FIELD <br /><br />
<p:autoComplete
value="#{curAttribute.value}"
completeMethod="#{newBacking.lookupActivated}"
var="curEntry"
itemLabel="#{curEntry.code}"
itemValue="#{curEntry.id}">
</p:autoComplete>
</p:column>
</p:dataTable>
</h:form>
newBacking.java
#Named()
#SessionScoped
public class NewBacking implements Serializable {
private CosmoCard card;
private String currentCardClassname = "";
#PostConstruct
public void init() {
Random randomGenerator = new Random();
card = new CosmoCard();
card.setId("ID" + randomGenerator.nextInt(1000));
CosmoAttribute myLA = new CosmoAttribute();
myLA.setLabel("LookupAttributeLabel");
myLA.setValue("LookupAttributeValue");
card.getAttributes().add(myLA);
}
public CosmoCard getCard() {
return card;
}
public String getCurrentCardClassname() {
return currentCardClassname;
}
public void setCurrentCardClassname(String currentCardClassname) {
this.currentCardClassname = currentCardClassname;
}
public List<CosmoCard> lookupActivated(String tgtQuery) {
Logger.getLogger(NewBacking.class.getName()).info("[NewBacking.lookupActivated()] Query: " + tgtQuery);
return CosmoCardList.generateCardList(10).getCards();
}
}
Your complete method is returning an instance of a complex class and thereby you need a converter. Without the existense of a converter, your component is thinking that its working with a string and trying to give reference to it when getting value and label attributes. Try using this and see if it works but I strongly recommend creating your own converter based on your needs:
#FacesConverter("anySelectConverter")
public class AnySelectConverter implements Converter{
private static Map<Object, String> entities = new ConcurrentHashMap<Object, String>();
#Override
public String getAsString(FacesContext context, UIComponent component, Object entity) {
// TODO : Fix
if(entity == null)
return "";
synchronized (entities) {
if (!entities.containsKey(entity)) {
String uuid = UUID.randomUUID().toString();
entities.put(entity, uuid);
return uuid;
} else {
return entities.get(entity);
}
}
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String uuid) {
for (Entry<Object, String> entry : entities.entrySet()) {
if (entry.getValue().equals(uuid)) {
return entry.getKey();
}
}
return null;
}
}
I have a problem with taking names of tUsers and print them on the screen. May be i dont call the method for getting names properly () because when i call the function listAgencies, it prints them correctly in the Eclipse console. Thanks for any advices!
In .xthml file, I have:
<h:panelGrid id="panel2" columns="2" cellpadding="5">
<c:forEach items="${agencyBean.listAgencies()}" var="inputBoxes">
<h:outputText value="${inputBoxes.gettUser().name}" />
<h:inputText />
</c:forEach>
</h:panelGrid>
My bean class:
#ManagedBean(name = "agencyBean")
#SessionScoped
public class AgencyBean {
private TAgency tEventType = new TAgency();
public void listAgencies() {
EntityManager em = HibernateUtil.getEntityManager();
// read the existing entries and write to console
Query q = em.createQuery("select u from TAgency u");
List<TAgency> agencyList = q.getResultList();
for (TAgency agency : agencyList) {
System.out.println("NAme: " + agency.gettUser().getName());
}
}
public TAgency gettEventType() {
return tEventType;
}
public void settEventType(TAgency tEventType) {
this.tEventType = tEventType;
}
}
TUser is another entity from where i want to get the name. I have getName() method which is public.
The problem is here:
<c:forEach items="${agencyBean.listAgencies()}" ... >
It should look for a getter method for listAgencies attribute, but instead it is a void method that will be executed and there's nothing to access to.
The best bet would be:
Creating an attribute in your class called List<TAgency> listAgencies.
Define proper getter and setter methods for listAgencies attribute. NEVER define business logic in managed bean getters. Related: Why JSF calls getters multiple times
Probably, change the scope of the bean to #RequestScope to load this list every time users access to this view. Related: How to choose the right bean scope?
Load the list using #PostConstruct method.
Based on these advices, the code would look like this:
#ManagedBean(name = "agencyBean")
#RequestScoped
public class AgencyBean {
private TAgency tEventType = new TAgency();
private List<TAgency> listAgencies;
#PostConstruct
public void init() {
EntityManager em = HibernateUtil.getEntityManager();
// read the existing entries and write to console
Query q = em.createQuery("select u from TAgency u");
List<TAgency> agencyList = q.getResultList();
for (TAgency agency : agencyList) {
System.out.println("NAme: " + agency.gettUser().getName());
}
}
public TAgency gettEventType() {
return tEventType;
}
public void settEventType(TAgency tEventType) {
this.tEventType = tEventType;
}
public List<TAgency> getListAgencies() {
return listAgencies;
}
public void setListAgencies(List<TAgency> listAgencies) {
this.listAgencies = listAgencies;
}
}
And your JSF code:
<!-- Note: no parenthesis usage -->
<c:forEach items="#{agencyBean.listAgencies}" var="inputBoxes">
<!-- no need to call the getter verbosely, Expression Language call it for you automatically -->
<h:outputText value="#{inputBoxes.user.name}" />
<!-- what you want to do here? -->
<h:inputText />
</c:forEach>
Also, probably you don't want to use <c:forEach> but <ui:repeat> instead. Related: JSTL in JSF2 Facelets... makes sense?
I am trying to learn Web Programming using JSF and Hibernate.
I have a table called mytable in my MySQL server which has 2 columns: name, surname
I also have a MyTable.java which is mapped to this table, it looks like this:
// Listing 1
public class MyTable {
private String name;
private String surname;
public MyTable() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
This is mapped via Hibernate, thus this code ( which I have used for testing purposes ) successfully inserts data to mytable:
//Listing 2
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
MyTable myTable = new MyTable();
myTable.setName("Name");
myTable.setSurname("Surname");
session.save(myTable);
session.getTransaction().commit();
And this is what my form on my index.xhtml looks like:
// Listing 3
<h:form id="registirationForm" prependId="false">
<h:outputLabel for="name">Name:</h:outputLabel>
<h:inputText id="name"></h:inputText>
<h:outputLabel for="surname">Surname:</h:outputLabel>
<h:inputText id="surname"></h:inputText>
</h:form>
My question is:
How do I tie my form to the code above?
Should I make the class MyTable a managed bean, and put a method called saveRecord and put the above code in there?
Should it be mapped to some other class? If so what should it be called? Should I change the name of the current MyTable.java to something like MyTableDao.Java ?
So when the user enters some name, and surname, what method should be called?
Where exactly should I put the code found in Listing 2?
I hope my question is clear, thanks for helping.
You have a basic model-view-controller pattern here. MyTable is your model and index.html is your view. To tie them together I'd suggest adding a controller class like RegistrationController.
The controller would be a managed and the view fields would be using its' properties like this:
<h:outputLabel for="name">Name:</h:outputLabel>
<h:inputText id="name" value="#{registrationController.userName}"></h:inputText>
the controller would contain also the save method. You may also add a DAO object like you suggested to separate the persistence details from the buisness logic (which should be in the controller).
So when the user enters name and surname values, these set the properties on the controller (which may be directly translated to your MyTable object). Then when save is clicked, a save method is called on the controller which uses the 'DAO' to persist 'MyTable' to the DB.
You may also want to look a this tutorial.
I have a JSF page where users can enter their car into my database. The form has three input fields:
Manufacturer
Model
Registration
I am using PrimeFaces 3.0.M2 and both the Manufacturer and Model field are autocomplete input fields:
<p:autoComplete id="manufacturer"
minQueryLength="3"
completeMethod="#{carController.completeManufacturer}"
forceSelection="true"
value="#{carController.manufacturer}" />
The field for the model looks the same, with slightly different values obviously.
The managed bean looks as follows (slightly abbreviated):
private String manufacturer;
private String model;
private String registration;
public List<String> completeManufacturer(String query) {
List<String> ms = new ArrayList<String>();
for (Manufacturer m : manufacturerFacade.findAllByName(query)) {
ms.add(m.getLongName());
}
return ms;
}
public List<String> completeModel(String query) {
List<String> ms = new ArrayList<String>();
for (Model m :
modelFacade.findAllByManufacturer(manufacturerFacade.findByName(manufacturer))) {
ms.add(m.getShortName());
}
return ms;
}
The problem lies in completing the model field. I need this field to only display autocompletion results based on the selected manufacturer, but the manufacturer String in the managed bean does not get populated until the entire form is submitted, so I cannot look the models up that are associated with the selected manufacturer.
How would I go about submitting only the manufacturer field, without submitting the entire form, so I can look the models of the selected manufacturer up?
Thanks!
Just add a selectListener, like so:
<p:autoComplete id="manufacturer"
minQueryLength="3"
completeMethod="#{carController.completeManufacturer}"
forceSelection="true"
selectListener="#{carController.manufacturerSelected}"
value="#{carController.manufacturer}" />
and then in the controller:
public void manufacturerSelected(SelectEvent vce) {
String nameOfSelected = vce.getObject().toString();
// whatever logic comes to your mind
}
You could add an extra ajax handler to the manafucturer input field and then handle the onchange event. In the server-side handler, simply remember the new value in your backing bean.
If you then put your backing bean in the view scope, the ajax requests originating from the model input field will get the same instance and you have direct access to the manufacturer field that you previously remembered.