I'm modernizing a JSF web application I took over from someone who retired and is not available for questions.
Current job is to simplify a h:dataTable. Each record has a commandLink to go to the corresponding details page.
Old version: action method openDetail(), determined the selected record by binding of the dataTable and looping trough the records to get the row.
New version: action method is now openDetail(Long id) and of course I added the parameter to the command link as well.
My action method is called with the correct parameter, I verified this by adding some log output. But the navigation-rule is not effective anymore. Although the action method returns the correct outcome, it stays on the page with the table.
The navigation-rule in faces-config.xml looks like this:
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-action>#{myBean.openDetail}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/mysks/detail.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
Do I need to adapt the navigation-rule ? Does JSF make a difference for overloaded action methods ?
The <from-action> has to exactly match the literal string as defined in action attribute.
So if it currently looks like this:
<h:commandButton ... action="#{myBean.openDetail(detail.id)}">`
Then the <from-action> must be exactly that literal string:
<from-action>#{myBean.openDetail(detail.id)}</from-action>
However, the whole navigation rule system has not proven to be really useful in JSF and has become de-facto deprecated since release of JSF 2.0 in 2009 which introduced the new support for immediately returning the <to-view-id> as return value, called "implicit navigation". Essentially, XML-based navigation rules are really a "leftover" of the jurassic JSF 1.x and you'd best just get rid of them.
So if you simply adjust the openDetail() method from
public String openDetail(Long id) {
// ...
return "success";
}
to
public String openDetail(Long id) {
// ...
return "/mysks/detail.xhtml?faces-redirect=true";
}
then you can get rid of the entire <navigation-rule> bloat from the faces-config.xml.
See also:
JSF implicit vs. explicit navigation
Related
i am new in JSF.I wonder one point at JSF/navigation rules.i have four pages, index,p1,p2,p3.When i am trying to navigate to a page with action="#{bean.gotoP1()}", it is giving error like that ;
"Unable to find matching navigation case with from-view-id '/index.xhtml' for action '#{bean.gotoP1()}' with outcome 'success'"
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
My codes are below;
index.xhtml
<h:body>
<h:form>
<h:commandButton action="#{mybean.gotoP1()}" value="P1"/>
<h:commandButton action="#{mybean.gotoP2()}" value="P2"/>
<h:commandButton action="#{mybean.gotoP3()}" value="P3"/>
</h:form>
</h:body>
mybean.java
#ManagedBean
#RequestScoped
public class Mybean implements Serializable{
private static final long serialVersionUID=1L;
public Mybean() {
}
public String gotoP1(){
return "success";
}
public String gotoP2(){
return "success";
}
public String gotoP3(){
return "positive";
}
}
faces-config.xml
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{mybean.gotoP1}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p1.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP2}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p2.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP3}</from-action>
<from-outcome>positive</from-outcome>
<to-view-id>/p3.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
Thanks....
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
Because the EL syntax doesn't match with the navigation case. You defined #{bean.gotoP1} instead of #{bean.gotoP1()} as from-action in navigation case. Simple as that.
Those argumentless parentheses are actually unnecessary. They started to spread over JSF pages since introduction of EL 2.2, because the average EL 2.2 aware IDE thinks to be smarter than it is and unnecessarily auto-completes the method expressions with parentheses and all, confusingly making the JSF starter to think that they are actually required. I've even seen code snippets coming along from starters who actually used #{bean.getProperty()} instead of #{bean.property} to output a property, which would then later fail with a javax.el.PropertyNotWritableException when used in an input component.
Just leave out those argumentless parentheses. It's not true that this syntax is required and "normal" in JSF. Moreover, navigation rules are very JSF 1.x-ish. Also, performing navigation using POST requests is very JSF 1.x-ish. Maybe you're just learning and playing around. That's OK, but to learn about the right ways and a bit of history, carefully read below links:
Invoke direct methods or methods with arguments / variables / parameters in EL
Differences between action and actionListener
JSF implicit vs. explicit navigation
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between JSP EL, JSF EL and Unified EL
Last but not least, our JSF wiki page is a great place to start.
i am new in JSF.I wonder one point at JSF/navigation rules.i have four pages, index,p1,p2,p3.When i am trying to navigate to a page with action="#{bean.gotoP1()}", it is giving error like that ;
"Unable to find matching navigation case with from-view-id '/index.xhtml' for action '#{bean.gotoP1()}' with outcome 'success'"
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
My codes are below;
index.xhtml
<h:body>
<h:form>
<h:commandButton action="#{mybean.gotoP1()}" value="P1"/>
<h:commandButton action="#{mybean.gotoP2()}" value="P2"/>
<h:commandButton action="#{mybean.gotoP3()}" value="P3"/>
</h:form>
</h:body>
mybean.java
#ManagedBean
#RequestScoped
public class Mybean implements Serializable{
private static final long serialVersionUID=1L;
public Mybean() {
}
public String gotoP1(){
return "success";
}
public String gotoP2(){
return "success";
}
public String gotoP3(){
return "positive";
}
}
faces-config.xml
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{mybean.gotoP1}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p1.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP2}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/p2.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{mybean.gotoP3}</from-action>
<from-outcome>positive</from-outcome>
<to-view-id>/p3.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
Thanks....
My question is simple; why can not I navigate with #{bean.gotoP1()} , and i have to remove parenthesis , #{bean.gotoP1} ?
Because the EL syntax doesn't match with the navigation case. You defined #{bean.gotoP1} instead of #{bean.gotoP1()} as from-action in navigation case. Simple as that.
Those argumentless parentheses are actually unnecessary. They started to spread over JSF pages since introduction of EL 2.2, because the average EL 2.2 aware IDE thinks to be smarter than it is and unnecessarily auto-completes the method expressions with parentheses and all, confusingly making the JSF starter to think that they are actually required. I've even seen code snippets coming along from starters who actually used #{bean.getProperty()} instead of #{bean.property} to output a property, which would then later fail with a javax.el.PropertyNotWritableException when used in an input component.
Just leave out those argumentless parentheses. It's not true that this syntax is required and "normal" in JSF. Moreover, navigation rules are very JSF 1.x-ish. Also, performing navigation using POST requests is very JSF 1.x-ish. Maybe you're just learning and playing around. That's OK, but to learn about the right ways and a bit of history, carefully read below links:
Invoke direct methods or methods with arguments / variables / parameters in EL
Differences between action and actionListener
JSF implicit vs. explicit navigation
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between JSP EL, JSF EL and Unified EL
Last but not least, our JSF wiki page is a great place to start.
I'working on a enterprise application that uses JSF 2.0, with Netbeans 7.0 and Glassfish 3.1
I have a managed bean that is ViewScoped. this is the declaration of the class:
#ManagedBean(name = "myBean")
#ViewScoped
public class MyMBean implements Serializable {
Inside its #PostConstruct, it has the following:
String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
if (id == null) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("home.xhtml");
FacesContext.getCurrentInstance().responseComplete();
} catch (Exception e) { }
return;
}
if I go to the page that uses this managed bean, and the id is null, everything works fine, and I get redirected to home page.
The problem is that when I navigate to a different page that does NOT use this managed bean (lets say for example "otherpage.xhtml") the PostConstruct method is executed, and it shouldn't! And it gets worse: since the url of this other page doesn't have the "id" parameter, the bean tries to redirect to home page; and I get a IllegalStateException.
Any idea of why a viewscoped managed bean is constructed when navigating to a page that does not use it?
Edit:
If in order to navigate to "otherpage.xhtml" I use the commandlink in "home.xhtml", 6 extra beans are created.
But, if instead of using the link, I type the url in the browser; it works fine. No extra bean is created. Maybe there's something wrong in how I implemented the link. This is the code:
<h:form>
<h:commandLink value="Go to other page" action="otherPage" />
</h:form>
And this is the navigation rule in faces-config:
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>otherPage</from-outcome>
<to-view-id>/views/otherPage.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
Is there anything wrong there?
Thanks!
Damian
You surely have a #{myBean} somewhere in the view or one of its templates/include/tag/composite files, or as a #ManagedProperty of the beans referenced by the view. Putting a breakpoint in the (post)constructor and investigating the stacktrace should give enough insights who/what has triggered the bean's construction.
Unrelated to the concrete problem, the ExternalContext#redirect() already implicitly calls FacesContext#responseComplete(), you don't need to call it yourself. See also the method's javadoc.
Update: a <h:commandLink> submits its parent POST <form> to the current page (and thus creates all its related beans!) and then depending on the navigation outcome, it will forward/redirect to the result page. You shouldn't be using commandlinks/commandbuttons for plain page-to-page navigation. Use <h:link> instead.
<h:link value="Go to other page" outcome="views/otherPage" />
You can eventually also get rid of that <navigation-case>. If you really insist in keeping that navigation case, then use outcome="otherPage" instead.
See also:
When should I use h:outputLink instead of h:commandLink?
Communication in JSF 2.0 - Implicit navigation
HI,
We are navigating, for example from page A to C. When we are in page C, user clicks the back button of the browser and goes back to the previous application which is used for invoking the page A. Again, when user trying to invoke the page A, he directly navigating to the page C, not page A.
Here what I felt the problem was, may the JSF context is taking to the current page. How we can solve this problem. When every user clicks to enter page A, he should be able to see the page A.
Anyone has the solution for my problem.
Just check the nav. rules
Examples
JSF 2
<h:commandButton action="/PageA.xhtml" or action="/PageA.xhtml?faces-redirect=true" ... />
JSF 1 you need to configure faces-config.xml
faces-config.xml:
<navigation-rule>
<from-view-id>Page.xhtml</from-view-id>
<navigation-case>
<from-outcome>goToA</from-outcome>
<to-view-id>/PageA.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>goToC</from-outcome>
<to-view-id>/PageC.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<from-view-id> = the page whos "firing" the nav. rule. Use * to make it global (<from-view-id>*</from-view-id>)
<from-outcome> = navigation string
<to-view-id> = target page
Page.xhtml:
<h:commandButton action="goToA" or action="goToC" ... /> <!-- Navigation string -->
Action should be the nav string (from-outcome) or a method wich returns a valid nav. string, example:
Bean
//Returns the nav. string
public String navA() { return "goToA"; }
public String navC() { return "goToC"; }
Page
<h:commandButton action="#{bean.navA}" or action="#{bean.navC}" ... />
Do not use HTTP POST requests for navigation, but use HTTP GET requests.
In JSF terms, don't use <h:commandLink> for navigation, but use <h:outputLink>, <h:link> or even plain vanilla <a>.
Can someone tell me how to catch parameters passed from URI in JSF's managed bean?
I have a navigation menu all nodes of which link to some navigation case. And i have two similar items there: Acquiring products and Issuing products. They have the same page but one different parameter: productType. I try to set it just by adding it to URL in "to-view-id" element like this:
<navigation-case>
<from-outcome>acquiring|products</from-outcome>
<to-view-id>/pages/products/list_products.jspx?productType=acquiring</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>issuing|products</from-outcome>
<to-view-id>/pages/products/list_products.jspx?productType=issuing</to-view-id>
</navigation-case>
But i can't get this "productType" from my managed bean. I tried to get it through FacesContext like this:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("productType")
And like this:
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
request.getParameter("productType");
And i tried to include it as a parameter of managed bean in faces-config.xml and then getting it through ordinary setter:
<managed-bean>
<managed-bean-name>MbProducts</managed-bean-name>
<managed-bean-class>my.package.product.MbProducts</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>productType</property-name>
<value>#{param.productType}</value>
</managed-property>
</managed-bean>
...
public class MbProducts {
...
public void setProductType(String productType) {
this.productType = productType;
}
...
}
But neither of these ways have helped me. All of them returned null. How can i get this productType? Or how can i pass it some other way?
The navigation rule by default does a forward. I.e. it reuses the initial request. Whatever way you try to access the request parameters in the forwarded resource, it will always try to grab them from the initial and already-processed request.
To fix this, you need to fire a redirect instead of forward. It creates a brand new request (you also see this reflecting back in the browser address bar).
In JSF, adding
<redirect/>
to the navigation case should do.