JSF 2.0 implicit navigation, different views - view

I'm looking for a good explanation to JSF 2.0 implicit navigation and how it works with views. To be more precise, I understand that from an action method I can return a string which is the outcome of the action. If there's a JSF view whose file name matches the outcome, then this is implicit navigation.
Now... my question, what if the action is invoked from a view that's inside a folder but the view that I want to navigate to next is in a different folder? I.e., from /manager/edit.xhtml an action is invoked. What String should that action return so that navigation can safely go to /user/list.xhtml or to /index.xhtml or to /manager/index.xhtml?

As far as my knowledge goes, JSF looks for a matching view only within the current context. You probably have to define a navigation rule in your faces-config.xml to handle an outcome in a special way. Here is an example:
<navigation-rule>
<from-view-id>/profiles/viewkeypages.xhtml</from-view-id>
<navigation-case>
<from-outcome>editkeypage</from-outcome>
<to-view-id>/users/editkeypage.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
-Praveen.

You can use implicit navigation to get to views in other folders.
Just do something like this in a view:
<h:link value="Move" outcome="#{request.contextPath}/users/editkeypage.xhtml?faces-redirect=true" />
or
<h:link value="Move" outcome="/users/editkeypage.xhtml?faces-redirect=true" />

Related

Add action to AjaxBehaviorEvent event

Currently I am working on a spring migration project. Since a4j:support is no longer supported I had to change those tags to a4j:ajax tags, but a4j:ajax tags do not have the action attribute. The systems is currently very heavily based on a seam pageflow which depend heavily on actions for it's navigation rules.
I was wondering if anyone knew an easy way in which I could just add an action to a AjaxBehaviorEvent so that I could pass in a value for the pageflow navigation? I have attempted to call the seam navigation handler directly and I keep getting a pageflow not initiated exception.
Here is an example of one of our pageflow pages if that helps
<page view-id="/customerProfileSetup.xhtml"
name="readProfile">
<redirect/>
<transition name="readProductProfileSetup"
to="productProfileSetup">
<action
expression="#{profileSetup.load}" />
</transition>
</page>
Ajax tag:
<a4j:ajax event="change" render="#all" listener="#{pageflowUtil.processPageflowAjaxBehavior}"/>
Method:
public void processPageflowAjaxBehavior(AjaxBehaviorEvent event) {}

Which View implementation handles JSPs in Spring MVC?

In the SpringMVC documentation I see this for AbstractView:
Direct Known Subclasses:
AbstractExcelView, AbstractFeedView,
AbstractJackson2View, AbstractJExcelView,
AbstractPdfView, AbstractUrlBasedView,
AbstractXlsView, MarshallingView
Which implementation handles regular JSP Views?
The reason for my question is that I want to extend SpringMVC's JSP View, to support a Read-Only mode for a form. The regular view would be the normal JSP, but a Read-Only View would be an extension of the JSP where all fields are converted to labels, i.e. they can't be modified.
Any advice on this approach appreciated.
What I understand is you need to get a JSF component root, iterate over all elements, find input fields and replace them with non-input - labels instead?
JSP does not 'like' modifying it's components at runtime. In JSF I could suggest you implement a TagHandler to modify the component tree based on some parameter returned in the View Model.
In your case - a simple solution would be to either disable inputs based on parameter value
<h:inputText value="${inputValue}" disabled="${formDisabled}" />
or render different inputs based on parameter value
<c:if test="${formDisabled}">
<div><h:outputText value="${inputValue}" />
</c:if>
<c:if test="${!formDisabled}">
<h:inputText value="${inputValue}" />
</c:if>

JSF2 and custom components - how to call action from Javascript code?

I have adapted a Pie chart JS object to use with JSF; in order to do so, I've created a custom component that outputs the appropriate markup and JS calls on the page, rendering the graph correctly. For reference's sake, this is the link for the tutorial I've followed for the JS part.
The next step is listening to clicks on the slices, and calling an action from a backing bean. The JS object for the chart already contains a placeholder function that listens to such clicks, so I believe the JS part of it is good. However, the JSF side bugs me still; I've read the Java EE tutorial, Jim Driscoll's blog posts, and all over the internet, and still can't get my head around it.
So, could anyone be so kind as to give a little example, of how I could bind a JS function call to an event listener in JSF, so that my backing bean would be nicely informed of which slice index had been clicked by the user?
It would be something close to:
function myChartObject() {
function onSliceClick() {
// This will somehow trigger JSF ajax event listener with slice data
}
}
class MyCustomChart extends UIComponentBase implements ClientBehaviorHolder {
// Is the decode() method the place to bind JS calls to JSF actions?
}
The closest I've found to my problem is something like this. However, I'd like to have this support in my own component, using the standard JSF API. Something perhaps close to this?
Thank you all in advance!
The JSF Javascript API to do AJAX calls is itself standardized (resource library "javax.faces", resource name "jsf.js") but adding full AJAX support in your own Java based custom component is a little elaborate.
The quickest way I can think of is following the blog by Jim Driscoll that you cited, and re-use the existing AJAX machinery offered by the <f:ajax> tag by wrapping your own Java based custom component in a composite component.
In Jim's example, I guess the following code from line 22 in his example is what you should render inside your onSliceClick function:
String click = behaviors.get("click").get(0).getScript(behaviorContext);
It would then look a little like this:
<ui:component
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:cu="http://javaserverfaces.dev.java.net/demo/custom-taglib"
>
<cc:interface shortDescription="Some Description">
<cc:attribute name="render" required="false" />
<cc:attribute name="clickAction" method-signature="java.lang.Object action" required="true" shortDescription="The click action method" />
</cc:interface>
<cc:implementation>
<cu:custom id="customId">
<f:ajax render="#{cc.attrs.render}" listener="#{cc.attrs.clickAction}"/>
</cu:custom>
</cc:implementation>
</ui:component>
Note that I haven't tested this, but it's the general idea. Of course it's also possible to do all of it directly in Java code but that surely takes some more work.
It looks like you want the ability to encode ajax style behaviors in your java compiled code, while integrating this with a J2ee stack.
The framework that comes to mind is JBOSS's Seam
Seam integrates directly with JSF by design, (GWT is more of a lightweight, standalone, statefull web-application framework - it doesn't have a lot of embedded features for direct integration with JMS and other modern J2ee features)...
Seam directly supports GWT-style ajax enabled components.
There is a good tutorial here : http://www.ibm.com/developerworks/java/library/j-seam3/

UIForm with prependId="false" breaks <f:ajax render>

I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
How to select JSF components using jQuery?
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable ids, which are incompatible with css part of web standards

h:commandLink action doens't fire within the same snippet that is to be replaced

In the Question commandButton/commandLink/ajax action/listener method not invoked or input value not updated there are 7 issues mentioned.
Now, I have the same problem, but I don't see which of the issues mentioned are causes the problem I'm having... nor did I manage to find the solution in any articles I've read.
I have an h:commandLink inside a snippet, which is in :main:profileContentSnippet in regard to the project:
...
<h:commandLink action="#{usersController.prepareModel}" value="ViewDetails" immediate="true">
<f:param name="pageViewId" value="EditDetails"/>
<f:ajax render=":main:profileContentSnippet" />
</h:commandLink>
...
Now, it is supposed to render :main:profileContentSnippet and modify it to present another snippet (which the commandLink is not a part of...). It renders EditProfilePersonalDetails, as sent by parameter.
The commandLink action doesn't fire.
Now if I remove it from the snippet that holds it, it works, but the h:commandLink is still there - and I wish it to disappear, as the snippet it resided on did... I wonder why's that? How can a control modify its own appearance if it is inside the snippet that is about to be replaced by another snippet using AJAX?
Thanks in advance.
Additional code:
The snippetFileName should change (and it is) after clicking on the h:commandLink from above.
Now, the file that contains the h:commnandLink is replaced by:
<h:panelGroup id="messagePanel" layout="block">
<h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
</h:panelGroup>
</ui:composition>
Note: the h:commnadLink is in a ui:composition too.
The Action in the managed bean that should be fired is:
#ManagedBean (name="usersController")
#RequestScoped
public class UsersController {
public String prepareConnected() {
//need to add getting user id from session
System.out.println("in prepareConnected");
current = ejbFacade.find( (long)2);
if (current == null){
System.out.println("in prepareConnected is null");
JsfUtil.addSuccessMessage("User Deleted in other request");
return null;
}
return "viewPersonalDetails-snippet";
}
}
...
This include part holds the commandLink from above:
<h:panelGroup id="profileContentSnippet" >
<ui:include src="#{snippetsProfileLinkerBean.snippetFileName}"/>
</h:panelGroup>
basically, the snippet is modified, but the current variable stays null since the preapareConnected doesn't fire. If I remove it from the snippet to other part in the site that is not in the include part it works. The problem is that I wish the h:commandLink part will disappear as well.`
It seems that there is a web.xml definition that should have been made for this to work:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
The problem was in the JSF 2 flow. First time the page is rendered, JSF builds a component tree, which means that only one of the snippets was in that tree at the time of the creation of the component tree. Therefore, in other requests (of the same page) only that component could have an action and an action listener registered. The other component didn't, because it was not in the component tree that was built from the start (though I could see it in the view).
Now, modifying the definition of javax.faces.PARTIAL_STATE_SAVING to false, makes JSF 2 flow create on every request the component tree. It is not the best solution, but I didn't find any documentation on how inserting dynamically a component to the compont tree after it tree has already been built, other than build it again for each request.

Resources