I've a tomcat application with jsf 1.1
Case:
My application has a jsp (let name it /create.jsp) that contains a form to create a Business Object (imagine type person). One of the attributes of this Business Object is a relation to itself (the BO person, has an attribute father, that is also of type person). For this porpose, in the jsp, I have a selectable, and a button. The button enables to create new Business Object (in this case, a person). Therefore, the jsp show in the popup is the same that the one shown in the main window
Problem:
I'm facing wrong behaviours in the main window.
Cause:
I've studied the case, and the reason of the problem is the ids of the views stored in the server. When the users requires a new page, the server creates a view (ViewRoot) and stores it at the session. The jsp path is used as the id of the View. When the user submits a form, it will rehuse the same view stored in the session.
The problem in my case is that the popup ViewRoot, and the main window ViewRoot share the same id. So when the main window is shown, its viewRoot will be stored (let say id /create.jsp), but, when the popup is shown, its viewRoot will overwrite the main one in session. After closing the popup, the user will try to submit the main page, but in the server, there is no such a ViewRoot.
Possible Solution:
I've been thinking on changing the ViewRoot id creation, but I thing that this is not feasible (at least if I don't modify the jsf library).
---OLD TEXT---
I have a jsp with a form (let name it /create.jsp), that opens a popup window. This popup will also use /create.jsp .
Due to that JSF view-id, is fomed by the jsp path, both pages will share same id. So when the popup is displayed, the view stored in the session for the main page is overwritten by the new one. Because of this, the application is not working properly.
Is there any way to change the ids of the views? anyone has any solution?
Thanks
You probably want to look into using a subview . You can assign a name-space within this that will essentially create a new namespace within the page. In facelets that would be:
<f:view id="main">
<ui:include "myOtherJsp.jsp" /> <!-- This containing a subview -->
</f:view>
Alternatively I think you may just need to separate the page into multiple views:
<f:view id="mainpage">
<p>Page content</p>
</f:view>
<f:view id="popup">
<p>My Popup</p>
</f:view>
I don't know the specifics of your application, but I can't see a situation where there's a reason to not have multiple views/forms. I'm guessing separation will fix your problem. You can use some elements of JSF outside the view ( so there's no reason to use a single view per page unless you're forced.
Caveat: I'm a JSF2 developer for the most part and I haven't done a JSF1.1 app in a long time.
My final solution is the following:
Create a jsp name popup_create.jsp, that only contains an inlcude to the create.jsp
Duplicate create.jsp entry in facesconfig with popup_create.jsp
Create a ViewHandler (add it in config) with an extension of ViewHandlerImpl, where createView & restoreView methods are ovewritten, so that the viewId, in case that is create.jsp, and we are in a popup, it will modify the viewId to poup_create.jsp.
As I think this may be done in a more elegant way, it is the only way I've found.
Related
Hi im working with jboss on a webapp. I got one page that is similar to forum page where you can post messages and reply to already posted ones. In my jsf i have three div tags one for adding new message one for listing all messages and one for viewing selected message. All the tags are embedded in and there is render attribute on every tag something like this:
<h:pannelGroup rendered="#{myController.shouldRender('add')}">
<!-- Here is my html for adding new message -->
</h:pannelGroup>
<h:pannelGroup rendered="#{myController.shouldRender('list')}">
<!-- Here is my html for listing messages -->
</h:pannelGroup>
<h:pannelGroup rendered="#{myController.shouldRender('view')}">
<!-- Here is my html for viewing message and its replys..
also there is hidden div with html for popup to post reply -->
<div id="reply">
<!-- This is hidden html that is shown when clicked reply
link in the message div below.
When shown users can add reply to the message -->
</div>
<div id="message">
<!-- Here is show the message itself -->
</div>
<div id="replyList">
<!-- Here is list replys for the message currently beeing viewed
For listing the replys i used ui:repeate and c:forEach from the jstl core
both resulting with same outcome.
In my message object i have list of replys which i load lazily...
-->
</div>
</h:pannelGroup>
My backing bean, stripped of all the annotations and rest of the code...
MyController{
String page;
public boolean shouldRender(String view){
return page.equals(view);
}
}
The page property i set with actionListener from list of menu items, before i redirect the user to the message.xhtml page i set myController's property page to the div name i want to view, so for e.g. if i click the add link i set the page = "add" and redirect to the message.xhtml. There the controller picks up the page set from outside and renders the add div.
Because i couldn't manage to get extended persistence context working, i set filter on /* to open user transaction and then merge the entity manager with that one, after the chain.DoFilter i commit my transaction. This i needed to enable lazy loading by hand..
The problem is that when i add reply message, the list with replies does not get refreshed immediately, i need to go back to the message list and then again open the same message in the view div to get the list of replies refreshed.. or... in the method for adding reply i tried to manually load my reply inside the list of replies owned by the message object (which are lazy loaded and mapped #OneToMany) and this way it works but i don't like that solution.
Can someone tell me weather hibernate is reloading the lazy loaded list because i manage the transaction and i assume that once it loaded my list, it doesn't refresh it on it's own.
When the list is modified in the same session, it is updated.
When the list is modified in a different session, it does not get updated.
As the session object is not multi-thread safe, in your environment probably every user has his own session instance, so you'll be in the second case. To force a refresh, you can evict() the parent instance and load() it again, or you clear() the session or you create and use a new one.
Pay attention with lazy loading. As the child elements are loaded on first usage (and not together with the parent instance), they can already reflect to a modification which was not yet made when the parent object was loaded.
My web application has two search pages - search1.jsf and search2.jsf - which share the same bean which in turn calls a result page - result.jsf.
So both search pages have a commandButton
<h:commandButton value="Commit" action="#{search.commit}" />
The "search" bean then processes the search and forwards to the result page using
target = "result?faces-redirect=true";
Now the result.jsf doesn't know which search page has been used. How can I pass the calling page so that the called page is able to render a link back to the calling page?
Using the browser back button (or Javascript code) to go back in the history has the disadvantage that the user, after browsing through the results, only would go back one page in the results instead of going 'up' to the search parameter form.
Options I see so far are:
pass the caller page name through the chain to the result page, using <f:param> or action="#{search.commit(name_of_calling_page)}
put all 'search parameter' forms in one JSF page and conditionally switch the content
Or is there a JSF functions which returns the name of the calling JSF page?
You're redirecting to the result page which suggests that you're using a session scoped bean to hold the results (a request/view scoped simply doesn't survive redirects). Ignoring the fact that this is a poor/odd approach, you could just store the search type in that bean as well?
Anyway, easiest and cleanest is to use a single master view with a single master view scoped bean and conditionally display search1.xhtml, search2.xhtml and results.xhtml using <ui:include> in the master view.
search.xhtml
<ui:fragment rendered="#{empty search.results}">
<ui:include src="/WEB-INF/search#{search.type}.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{not empty search.results}">
<ui:include src="/WEB-INF/results.xhtml" />
</ui:fragment>
As long as you return void or null in action methods, the same view scoped bean will be retained on every subsequent (and non-redirected!) request. If you intend to make it a GET instead of POST (so that it's bookmarkable and back-button-navigable such as Google), then you should actually change the forms and view parameters to make it GET instead of POST.
I would like to basically do what Jason asked for here
In one sentence, I would like the url bar to represent the state of the AJAX application so that I can allow to bookmark it as well as allow the user to return to the previous state by using the back/forward buttons in the browser.
The difference for me (From what Jason asked) is that I am using JSF 2.0.
I've read that JSF 2.0 added the ability to use get, but I am not sure what the correct way to use this.
Thanks for the help.
Further Clarification
If I understand correctly, to be able to bookmark specific states in the AJAX webapp I will have to use the location.hash. Am I correct? I'm trying to achieve a gmail-like behaviour in the sense that, while the app is complete AJAXified and no redirects occur, I can still use Back/Forward and bookmark (And that's why I would like the URL bar to be updated from the AJAX app itself and not through redirection)
Update
Just found this similar question
The difference for me (From what Jason asked) is that I am using JSF 2.0. I've read that JSF 2.0 added the ability to use get, but I am not sure what the correct way to use this.
Please note that this is not the same as maintaining the Ajax state. It usually happens by fragment identifiers (the part starting with # in URL, also known as hashbang). JSF doesn't offer builtin components/functionality for this. As far I have also not seen a component library which does that. You may however find this answer useful to get started with a homegrown hash fragment processor in JSF.
As to using GET requests, just use <h:link>, <h:outputLink> or even <a> to create GET links. You can supply request parameters in the h: components by <f:param>. E.g.
<h:link value="Edit product" outcome="product/edit">
<f:param name="id" value="#{product.id}" />
</h:link>
In the product/edit.xhtml page you can define parameters to set and actions to execute upon a GET request
<f:metadata>
<f:viewParam name="id" value="#{productEditor.id}" />
<f:event type="preRenderView" listener="#{productEditor.init}" />
</f:metadata>
In the request or view scoped bean associated with product/edit.xhtml page -in this example #{productEditor}-, you just define the properties and the listener method. The listener method will be executed after all properties are been gathered, converted, validated and updated in the model.
private Long id;
private Product product;
public void init() {
product = productService.find(id);
}
Normally you'd use AJAX to prevent complete page refreshes. AFAIK all current browsers would issue a page refresh if you change the base uri. Thus you would have to use the hash part as suggested in the question you provided.
We had a similar problem and did something like this:
We settled for the fact that users cannot bookmark the url.
For URLs that should be unique/bookmarkable we used different links that issue a redirect. Those URLs are provided in a sitemap.
For browser back, we added an intermediate page after login. This page does navigation and a redirect to the application. The navigation is stored in the session and when the server gets a navigation request (which can be a history back) the corresponding state is restored. A browser back opens that intermediate page which issues a redirect along with a navigation request on the server side.
I am writing an application in JAVA. Need advice about the menu.
I dont want to duplicate the code for menu creation in every JSP.
I want to create 1 JSP called menu.jsp and create the menu there and do a dynamic include <jsp:include... > wherever I need the menu.
This is fine till I have static menu.
Now, how would do do this for a dynamic menu.
I know it is a bad practice to connect to DB directly from JSP.
So what I want to do is this:
create a servlet
connect to DB and get the menu items and the display order
flush the menu created above to a jsp
So, my question is how do I include the above JSP wherever I need menu???
I think what you need is a templating system. Try out sitemesh for instance.
If you want to really use a java framework that helps you with good practices, i recommend to use grails
You may include servlet output by tag <jsp:include>. But it's a bad practice. See jsp tags instead
To use the menu, application wide put the generated menu either in session or application[ If and only if menu is same for every user]
Lets say menu.jsp has the code for generating the menu, get the session(or application object) and proceed with the requirement
Finally call menu.jsp using or <%#include >
Add the menu items, and a "renderMenu" boolean as request attributes.
Then include the menu.jsp and read those attributes - if renderMenu is false, don't output anything. If it is true - proceed with rendering the items (set by the servlet)
I may be missing a couple of points, but I've hacked together a jsf/richfaces app and want to be able to do the simplest ajax-based nav:
main page contains ref to my backing bean's menu
<h:form>
<rich:dropDownMenu binding="#{PrismBacking.nodeMenu}" />
</h:form>
this refers to the code for the backing bean methods
this is my main page ajax panel
<rich:panel id="content">
<a4j:include viewId="#{PrismBacking.viewId}" />
</rich:panel>
i can't work out how to get the backing bean to use the selected item from the rich:dropDownMenu to update that which is returned by getViewId.
i guess:
1) i need to ensure the menu items in the getNodeMenu method have the right payload so setViewId is called with the correct String and my rich:panel id="content" is reRendered.
any pointers as to how to do this would be greatly appreciated.
mark
You are not setting the reRender attribute anywhere in your code (in the menu items) so the panel is not going to be updated after you select an item from the dropdown.
You also have to set the ajaxSubmit attribute en each menuItem to true in order to execute an ajax request. Also check that your listener is executed.
Take a look at the example http://livedemo.exadel.com/richfaces-demo/richfaces/dropDownMenu.jsf?c=dropDownMenu . You can download the code if you want from the richfaces site.
Using binding should be avoided if possible. Take a look at the RichFaces demo - there are source codes for each example, and see how it is achieved.
(This doesn't answer your question, and for better :) )