I have a little issue regarding submit of forms in jsf 2:
In my webapp I got a function that updates entities in my db. This function gets the relative data out of a managed bean.
So, my issue is that changes in my view are not passed to the managedBean. To make that clear for you, here an example:
public String updateProject() {
projectService.updateProject(projectData.getProjectDTO());
return ("overview.xhtml");
}
prjectData is my ManagedBean. This one doesn't work! No updates are been made.
public String deleteProject() {
projectData.getProjectDTO().setDeleted(true);
projectService.updateProject(projectData.getProjectDTO());
return ("overview.xhtml");
}
Here, when I change a value by code it works! So I guess my values out of the view are not passed to my managedBean.
Where could be a mistake? Is there maybe an action I have to invoke to make the data pass my view to the managedBean?
Answer to Gabor's comment:
My page looks like:
<h:form>
<h:commandLink action="#{controller.updateProject}" value="Edit" />
<h:outputLabel for="title" value="Titel" />
<h:inputText id="title" value="#{projectData.projectDTO.title}" />
</h:form>
If I change the title here and press update nothing happens ;-)
My Controller looks like:
#ManagedBean
#RequestScoped
public class Controller {
#ManagedProperty(value = "#{projectData}")
private ProjectData projectData;
...
For unknown reason my debug mode in eclipse doesn't work anymore it ignores my breakpoints all the time. I gonna fix that and then I'll check about the instances. Sry -.-
Either projectData or projectDTO is not the right instance as you expect it to be. It's a completely different instance. Aren't you eagerly recreating/overriding beans? Don't you have multiple beans in the scope? Shouldn't it for example be #{controller.projectData.projectDTO.title}? Shouldn't the projectData instance in the controller be a managed property?
Is your projectData bean also RequestScoped? Try to change to ViewScoped. RequestScoped beans are recreated for each request, also ajax request. And what is scope of projectService?
Related
I have a ManagedBean that is Session Scoped that injects another two Session Scoped Beans, they both have their proper getter and setters.
My class is as follows:
#ManagedBean(name="oneClass")
#SessionScoped
public class OneClassController implements Serializable {
#ManagedProperty(value="#{myOtherBean}")
public AnotherClass another;
#ManagedProperty(value="#{requestBean}")
public RequestClass request;
public String foo() {
another = getAnotherService(request);
return "page?faces-redirect=true";
}
//getters and setters for AnotherClass and RequestClass
}
Now, the request class holds all the values for a web service request. Those values are filled within a form in a xhtml page.
When the user finishes filling up the request and fires the action from a button, it enters the foo method. The debug shows the request with the correct data, and when I call it, another gets filled up correctly.
Now, page.xhtml looks like this:
<h:outputText value="#{requestBean.agentId}" />
<h:outputText value="#{myOtherBean.name}" />
<h:outputText value="#{myOtherBean.lastname}" />
When page is rendered, all the values from the requestBean are showed correctly, but all the anotherBean values show up empty. Even refreshing the page won't help.
If I trigger a button in page.xhtml to print out in the action method the values from anotherBean:
log.info("Another name: " + another.getName());
they print out fine.
I have in web.xml the saving method set for the server.
By the way, this is not the real naming convention I am using, but right now I'm in another computer without any IDEs nor JDK whatsoever, so I'm trying to replicate the code the best I can.
How can I show the correct values in page?
Try using,
<h:outputText value="#{oneClass.another.name}" />
<h:outputText value="#{oneClass.another.lastname}" />
To view all the variables in sessionScope you can do a:
<h:outputText value="#{sessionScope}" />
This will confirm if "myOtherBean" is in session scope or not.
Sorry, really really basic question...
I've got a list of 'messageboard threads' that I display on a page. I want to be able to click on one of them and redirect to a page which displays the details for that thread. I'm struggling despite googling it for a while...
(I'm using PrimeFaces by the way)
Here's the relevant code from my 'list' page:
<p:commandLink value="#{thread.title}" action="#{messageboardBean.showThread()}">
<f:param name="threadId" value="#{thread.id}" />
</p:commandLink>
(it's in an h:form element)
This is part of my named bean (other methods work fine)
...
#ManagedProperty(value="#{param.threadId}")
private Long threadId;
...
public String showThread() {
System.out.println("id is " + getThreadId());
return "messageboard/list";
}
...
As you can see my method isn't implemented yet, but it's not even being called. Please can someone tell me why?
I tried with an h:link too by the way, same (or similar) problem.
Thanks!
UPDATE - Solved
Thanks to the help below, here is my solution (I've renamed 'messageboard' to 'discussion').
The link is generated using this code
value: what to display on the page, in my case the title of my discussion
outcome: refers to edit.xhtml, the faces file I want to go to
...and the [request] param is going to be called 'threadId' and has a value of the id attribute in my 'thread' object.
In the edit.xhtml page, I've got this
<f:metadata>
<f:viewParam name="threadId" value="#{viewDiscussionBean.threadId}" />
<f:event type="preRenderView" listener="#{viewDiscussionBean.loadDiscussion}" />
</f:metadata>
Note that 'threadId' is the same as the param name in the first page, and it is bound to my viewDiscussionBean's threadId property.
Then once the params are all set on my bean, I call the loadDiscussion method of my viewDiscussionBean. Since it now has the threadId property, it's able to do this (see below)
My viewDiscussionBean has the following managed property (I think the viewParam tag sets this, rather than the other way around).
#ManagedProperty(value="#{param.threadId}")
private Long threadId;
private Discussion thread;
So once that's set, this method is able to run (because it now has an ID)
public String loadDiscussion() {
thread = mbDao.find(threadId);
return "edit";
}
This just uses a DAO (using Hibernate) to look up the discussion thread with that ID, and set it in the bean. And then...
In my edit.xhtml page, I can access values in the discussion thread using things like
<h:outputText value="#{viewDiscussionBean.thread.message}" />
Voila! Thanks.
There are many possible caused for an UICommand action not being invoked. You can find them all here: commandButton/commandLink/ajax action/listener method not invoked or input value not updated Among others a missing form, a nested form, or a conversion/validation error elsewhere in the form, being in a datatable whose datamodel is not properly preserved, etcetera.
As to your particular functional requirement, better is to use a <h:link>. A command link issues a POST request which does in your particular case not end up with a bookmarkable URL with the thread ID in the URL. A <h:link> creates a fullworthy link which is bookmarkable and searchbot-indexable.
E.g.
<h:link value="#{thread.title}" outcome="messageboard/list">
<f:param name="threadId" value="#{thread.id}" />
</h:link>
This doesn't require a form nor an action method. You only need to move that #ManagedProperty to the bean associated with messageboard/list, or maybe replace it by <f:viewParam> in the messageboard/list view which allows for finer-grained validation/conversion.
See also:
Communication in JSF2 - Processing GET request parameters
When should I use h:outputLink instead of h:commandLink?
ViewParam vs #ManagedProperty(value = "#{param.id}")
Your best bet it probably to go with BalusC's answer and use <h:link>. However, I have some thoughts about the behavior you're seeing.
Primefaces <p:commandLink> (like <p:commandButton>) uses ajax by default. Therefore, there won't be any actual navigation resulting from returning an outcome from your action. This could make it look like your action isn't being invoked. Try adding ajax=false to your <p:commandLink>.
When using <h:link>, navigation is resolved when the link is rendered rather than when it's clicked. Modifying your example:
<h:link value="#{thread.title}" outcome="#{messageboardBean.showThread()}">
<f:param name="threadId" value="#{thread.id}" />
</h:link>
showThread() will be called (I think) when the view containing the link is being rendered. If you're not checking at the right time, this may also make it look like the method is being called.
In both cases, this doesn't explain why you wouldn't see the message to System.out at all, but I know I've tried that thinking it was fail-safe and still not seen the output, which all depends on your container, configuration, how you launched it, etc.
Im trying to use dynamic validationGroups
<h:inputText id="id" value="#{bean.char}" maxlength="8" alt="#{bean.displayName}">
<f:validateBean
validationGroups="#{bean.validationGroup}" />
</h:inputText>
However the #{bean.validationGroup} is always called before the
<f:event type="preRenderView" listener="#{bean.initView}" />
Is this a bug in Myfaces? I need to have #{bean.validationGroup} called after the prerenderview because preRender loads data from the db and validationGroups will be different. Im using Myfaces 2.1.5 with richfaces 4.1.
This is indeed specified behaviour. The <f:xxx> tags run during view build time. If you like to initialize properties before the view is been built, then you need to do the job in the (post)constructor method of the bean. The pre render view event runs right before the view is to be rendered, but long after the view is been built.
Remove the <f:event> altogether and make the initView a #PostConstruct method instead.
#PostConstruct
public void initView() {
// ...
}
It will run directly after bean's construction and finishing of all dependency injections like #ManagedProperty, #Inject, #EJB and so on.
#ManagedBean
#XScoped --sessionScope,viewScope
Public class Bean{
public void initView(){
if (!FacesContext.getCurrentInstance().isPostback(){
//put initView codes here
}
}
}
I had a problem, which I solved, but I feel like my solution is a bad hack. Is there a better way?
I have a page, on which I placed the form, which shows properties of some object, as in example (obvious details omitted).
Ticket.java:
#Entity
public class Ticket {
#Id
private Long id;
private String title;
private byte priority;
// Getters, setters...
}
TicketController.java
#RequestScoped
public class TicketController {
private Ticket ticket = new Ticket();
// Getters, setters...
public String doUpdateTicket() {
Ticket t = ticketEJB.getTicketById(ticket.getId());
t.setTitle(ticket.getTitle());
t.setPriority(ticket.getPriority());
ticketEJB.updateTicket(t);
ticket = t;
return "view.faces";
}
}
edit.xhtml (just the form, everything else is boilerplate)
<h:form>
<h:inputHidden value="#{ticketController.ticket.id}" />
<h:panelGrid columns="2">
<h:outputLabel value="ID"/>
<h:outputLabel value="#{ticketController.ticket.id}"/>
<h:outputLabel value="Title: "/>
<h:inputText value="#{ticketController.ticket.title}"/>
<h:outputLabel value="Priority: "/>
<h:inputText value="#{ticketController.ticket.priority}" />
<h:commandButton value="Submit"
action="#{ticketController.doUpdateTicket}" />
</h:panelGrid>
</h:form>
Also there is TicketEJB, which is responsible for fetching those tickets, persisting, etc.
So I create a hidden input in the form, then (in managed bean) I find ticket, using provided id, then manually copy all the fields from ticket object of managed bean to the fetched ticket, then persist it... It involves the violation of DRY principle (I already stumbled on a bug when I added a field to Ticket, but forgot to copy it in the doUpdateTicket().
So, maybe there is a better way to do this?
Just get the original ticket from the EJB during preRenderView of a view scoped bean instead of creating a new one yourself. Assuming that the ticket ID is been passed as a request parameter with name id:
edit.xhtml
<f:metadata>
<f:viewParam name="id" value="#{ticketController.id}" />
<f:event type="preRenderView" listener="#{ticketController.preLoad}" />
</f:metadata>
...
TicketController
#ManagedBean
#ViewScoped
public class TicketController {
private Long id;
private Ticket ticket;
#EJB
private TicketEJB ticketEJB;
public void preLoad() {
ticket = ticketEJB.getTicketById(id);
}
public String doUpdateTicket() {
ticketEJB.updateTicket(ticket);
return "view.faces";
}
// ...
}
The only difference is that the input fields don't blank out. But isn't that just the whole idea behind an "edit" form? That issue is then also immediately fixed that way.
Oh and your
<h:outputLabel value="#{ticketController.ticket.id}"/>
really needs to be a
<h:outputText value="#{ticketController.ticket.id}"/>
You could add the Ticket as a ManagedBean in its own right but use #SessionScoped. This way the Ticket Domain Object keeps its id between requests and JSF can update it directly. Of course you lose the advantage of keeping data short lived with this approach, which you currently get via the Request scope. And you open a debate about binding to the Domain Object itself.
With JSF 2 you also have the View Scope where you can store attributes against the UIViewRoot, which may be highly desirable in your case to avoid using the hidden fields i.e. store the Ticket or Controller which HAS-A Ticket in viewScope - so while the user postbacks to the edit page the Ticket is kept in scope. Some folk may say you should be using a Transfer Object here to decouple the Service entities from the presentation tier - so update a TO, pass that to the EJB and let the EJB handle the update and persistence of the Entity.
Alternatively you could store just the Long id server side in #SessionScoped or #ViewScoped, as it may be insecure to store this as a hidden field as the client could change it to update another ticket. If you do use another instance of Ticket to capture UI Inputs then you could provide a Copy Constructor on the Ticket object, so the doUpdateTicket method itself does not include the tedious copy fields from one Ticket to another code.
To avoid repetition I would prefer binding directly to the JPA Entity AKA Domain Object. And I would use #ViewScoped.
I'm getting deeper into JSF 2.0 at the moment and lacking a bit of understanding about the "transport" of managed bean properties from one view to the other. I searched a bit but haven't found a really good example, so if anyone could point me to a tutorial or explain the things a little bit I'd really grateful.
So here is my scenario:
I'm developing a small playground calendar application. The first view select.xhtml contains the calendar selector, where the user can pick a specific date:
<html>
...
<h:form>
<!-- Calendar selector from primefaces -->
<p:calendar value="#{calendarSelect.date}" mode="inline" navigator="true" />
<p:commandButton value="Show entries for date" action="day" />
...
My corresponding backing bean looks like this:
#ManagedBean(name="calendarSelect")
#RequestScoped
public class CalendarSelectComponent {
private Date date = null;
... // Getters and setters
Now when I submit the form from select.xhtml I'm forwarded to day.xhtml
<html>
...
<h:form>
The current day ist:
<h:outputText value="#{calendarEdit.date}">
<f:convertDateTime pattern="dd.MM.yyyy" />
</h:outputText>
The backing bean now looks like this:
#ManagedBean(name="calendarEdit")
#ViewScoped
public class CalendarEditComponent implements Serializable {
private Date date = null;
private CalendarEntryBean currentEntry = null;
private List<CalendarEntryBean> allEntries = null;
....
I am now trying to solve the problem: How do I transfer the date parameter from the selector to the editor?
I've tried a number of options, one was this:
<p:commandButton value="Show entries for date" action="day" />
<f:setPropertyActionListener target="#{calendarEdit.date}" value="#{calendarSelect.date}" />
</p:commandButton>
A debugger shows, that indeed, the date property of the calendarEdit is populated with the value from calendarSelect, but since day.xhtml is a new view, a new CalendarEditComponent backing bean is being created and not the one I've populated with the date from the selector in the select view.
I've read that one solution would be to create a SessionScoped backing bean that does retain all it's values. But this is not the way I think it's supposed to work, because I don't really need the information in the session, I simply want it to "travel" from A to B. Another downside with the session based approach is that I can only use one selector and one editor per session - which I think isn't acceptible if you think of multi window browsing and so on.
I really don't think I'm the first one encountering such a scenario and I'm sure that JSF provides an elegant solution for this but I haven't been able to find that solution.
So once again, if anyone knows how to approach this - I'm listening! ;-)
The <f:setPropertyActionListener> is executed during invoke action phase of the form submit. So it expects that the value is still there at that point. But since your select bean is request scoped, it isn't there during form submit anymore. You want instead to pass a request parameter which get inlined in the output during render response. You can do this with <f:param>.
<p:commandButton value="Show entries for date" action="day" />
<f:param name="date" value="#{calendarSelect.dateAsString}" />
</p:commandButton>
It'll be available as request parameter (note that it only understands Strings, due to the nature of HTTP). You could let JSF set request parameters as managed properties, but since your edit bean is view scoped, this isn't possible with #ManagedProperty. You've got to gather it yourself by ExternalContext.
String dateAsString = externalContext.getRequestParameterMap().get("date");
True, that's clumsy. I would just have used the same bean and view for this and toggle visibility of select/edit forms by rendered attribute. The edit view is after all not directly openable/bookmarkable by a simple GET, isn't it? ;)