How to change the standard href="#" attribute of h:commandLink? - jsf-2

I am maintaining a JSF2 Ajax application and we are heavily using h:commandLinks and f:ajax tags for all actions - always only rerendering what is needed.
This does of course break the expected behaviour for the user when performing a right click on the links and choosing "Open Link in New Tab" etc.
I understand that f:ajax forces the href atribute of the resulting a element to be # and does all the magic post request trickery in the onclick function - I now want to provide fallback support for the "Open Link..." action by putting some meaningful link in the href attribute of the resulting <a> tag.
This would not break the "normal" onclick behaviour as the generated javascript always finishes with return false; but would allow me to send my users to some page using a normal GET request in case they want to open the link in a new window.
Is there a build in way to do this? Or could somebody point me in the right direction on where in the JSF lifecycle I would have to jump in to do this maybe using a phase listener?

Simplest would be to extend com.sun.faces.renderkit.html_basic.CommandLinkRenderer and override the renderAsActive() method accordingly. Mojarra is open source, just copy the method and edit the line where it says writer.write("href", "#", "href"). Replace the "#" string accordingly to your insight.
public class MyCommandLinkRenderer extends CommandLinkRenderer {
#Override
protected void renderAsActive(FacesContext context, UIComponent command) throws IOException {
// ...
}
}
To get it to run, register it as follows in faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>javax.faces.Link</renderer-type>
<renderer-class>com.example.MyCommandLinkRenderer</renderer-class>
</renderer>
</render-kit>
Note that this tight couples your renderer to Mojarra. To be JSF implementation independent, you'd need to create a whole new renderer instead of extending a Mojarra specific renderer class.
Unrelated to the concrete problem, consider reading When should I use h:outputLink instead of h:commandLink?

Related

How to render view component after being altered in the managedbean?

I have an outputtext showing the number of services on the screen:
<h:outputText
value="Services #{bean.counterManager.serviceCounter}">
</h:outputText>
and below it an accordionpanel that calls the getServices() method:
<p:accordionPanel value="#{bean.services}" var="service">
In the getServices() method I increment the counter and when I debugged at the return point it was 143.
public List<Service> getServices()
{
if (this.services.isEmpty())
{
//Does other stuff, fills this.Services
this.counterManager.incrementServiceCounter(someValue); //
}
return this.services;
}
But it appears 0 on screen, because getServices() is called after outputText calls getCounterManager() probably because the outputtext is above the accordionpanel on my XHTML.
I'd like for serviceCounter to show 143 and not 0, but I don't how to make it render after getLinhasStruct() is called, I can't put it the outputtext below accordion panel because that would mess with the layout of the page so how can I do that?
Never do business logic in getters. You need to make sure that all your getters (and setters) are pure getters (and setters).
public List<Service> getServices() {
return services;
}
After your IDE autogenerates them in the very bottom of the bean class, just ignore them forever. Do not touch them. Do as if they do not exist. You're supposed to perform business logic in action event listeners.
Your concrete problem is caused because those getter methods are during render response phase called in the same order as the components appear in the tree, and your code is incorrectly relying on something which is not controllable from inside the backing bean.
You did nowhere state the concrete functional requirement in the question, so it's a bit hard to point out the right approach, but there are in general the following approaches depending on when exactly you'd like to perform the business logic.
During initial GET request? Use <f:viewAction>.
Right before rendering the view? Use <f:event type="preRenderView">.
During bean's initialization? Use #PostConstruct.
See also:
Why JSF calls getters multiple times
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When to use f:viewAction / preRenderView versus PostConstruct?

Difference in navigation by action="xyz" and action="#{bean.returnXyz}"

How is navigation from a Facelet page
<p:commandLink action="xyz.xhtml">
or a backing bean
<p:commandLink action="#{bean.redirect}">
public class Bean{
public String redirect(){
.....
return "xyz.xhtml";
}
}
different from each other?
How is navigation from a xhtml page or a backing bean different from each other.
There's no difference. The both examples invoke a POST request and instructs JSF to render the view associated with the given outcome. The backing bean method has the only advantage that it allows you to perform some business logic beforehand or even control the outcome value programmatically.
However, if you don't have any business logic at all and solely want to have an idempotent link to another page, then using a command link is actually a bad practice. Using POST for page-to-page navigation is not user nor SEO friendly. The target page is not bookmarkable (the URL remains the one of the page where the POST form was been submitted to) nor searchbot-crawlable (it is using JavaScript to submit a hidden form).
You should instead use a normal link.
<h:link outcome="xyz.xhtml">
This generates a SEO-friendly <a> element with the full URL in its href and ends up in an user-friendly bookmarkable URL.
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Check out the documentation of p:commandLink here, which says the following for action attribute:
A method expression or a string outcome to process when command is
executed.
Now, as action="xyz.xhtml" returns String xyz.xhtml you're redirected accordingly and for action="#{bean.redirect}" which again returns xyz.xhtml you are again redirected according to the returned String.

vaadin embed in div, how to pass query string

I'm trying to embed my vaadin app into a jsp file, this for the reason I want to do some basic SEO stuff in there.
Unfortunately, my vaadin app uses a request/parameter handler which is not called with my parameters when I embed the div into the jsp page.
Is there a simple way to pass the query string to the vaadin servlet? I was thinking of something like {appUri:'de'<%=request.getQueryString()%>. But I'm not sure if this is the proper way.
Any proper solution is appreciated :)
Thank you so much.
p.s. I guess iframe would do it, but I would like the div version if possible.
It doesn't matter what you are doing to start your vaadin app.
Just modify your main application to have:
public class SomeVaadinApplication extends Application implements HttpServletRequestListener
Then in the onRequestStart method:
#Override
public void onRequestStart(HttpServletRequest request, HttpServletResponse response) {
String someParameter = request.getParameter("SomeParameter");
//Do something with parameter
}

JSF2 + IceFaces 2 - Retrieve UIComponent from ViewRoot

I've got hard time resolving the following. My problem is quite simple : I would like to highlight in red the forms fields that triggered validation errors. The error messages are placed correctly in the FacesContext using a context.addMessage(...) line.
I'd like my system to be generic. All form fields having a message attached are automatically highlighted.
I've found on this site a link to this excellent article :
http://www.jroller.com/mert/entry/how_to_find_a_uicomponent
With it, I did implement a PhaseListener for the RENDER_RESPONSE phase, which do the following :
#Override
public void beforePhase(PhaseEvent event) {
// get context
FacesContext context = event.getFacesContext();
// iterate on all the clientIds which have messages
Iterator<String> clientIdsWithMessages = context.getClientIdsWithMessages();
while (clientIdsWithMessages.hasNext()) {
// get the clientId for the field component
String clientIdWithMessage = clientIdsWithMessages.next();
// split on ":"
String[] splitted = clientIdWithMessage.split(":");
UIComponent component = findComponentInRoot(splitted[splitted.length - 1]);
if (component != null) {
Map<String, Object> attributes = component.getAttributes();
if (attributes.containsKey("style")) {
attributes.remove("style");
}
attributes.put("style", "background-color: #FFE1E1;");
}
}
}
This perform perfectly well for almost all my usage.
Now, where it becomes a bit tricky, is that some of my forms have such code :
<ice:dataTable id="revisionDocuments" value="#{agendaBean.agenda.revisionsDocuments}" var="revision">
<ice:column>
<ice:inputText value="#{revision.sequenceAdresse}" id="revisionSequenceAdresse" />
</ice:column>
....
The generated form has several lines (one for each object of the revisionsDocuments list), and each element has a unique identifier (clientId) which looks like :
contentForm:revisionDocuments:0:revisionSequenceAdresse
With 0 changed for 1, 2, ... for each iteration.
Consequently, the code provided to search the UIComponent from ViewRoot does not work properly. All forms fields have the same "id". What surprise me more is : they have the same "clientId" in FacesContext too :
contentForm:revisionDocuments:revisionSequenceAdresse
I cannot distinguish, while going through the tree, if I do see the right form field or any of the others.
Does anyone have a hint to solve this ? Or another suggestion to implement the highlight of my fields ? I have to admit, I dont really like my code, I consider dirty to manipulate the viewRoot like I'm doing, but I could not figure out a better solution to have a generic highlight of my fields.
I'm running IceFaces 2.0.2 with JSF-Impl 2.1.1-b04 on JBOss AS 7.0.2.Final.
Thank you in advance for the answers.
Best regards,
Patrick
You should apply this in the client side instead. You've got a collection of client IDs with messages. One of the ways is to pass this information to JavaScript and let it do the job. You can find an example of such a PhaseListener in this article: Set focus and highlight in JSF.
Since JSF 2.0 there is however another way without the need for a PhaseListener. There's a new implicit EL variable, #{component} which refers to the UIComponent instance of the current component. In case of UIInput components, there's an isValid() method. This allows you to do something like:
<h:inputText styleClass="#{component.valid ? '' : 'error'}" />
with this in a CSS file:
.error {
background: #ffe1e1;
}
(yes, you can also do this in a style attribute, but mingling style with markup is a poor practice)
To abstract this away (so that you don't need to repeat it in every input), you can just create a composite component for this, something like <my:input>.
For completeness, here is the solution I finally found to highlight the fields that do have error messages with IceFaces 2.0.2 :
The basic idea is strictly the same than proposed by BalusC on http://balusc.blogspot.com/2007/12/set-focus-in-jsf.html
The piece of code I had to change with IceFaces is the small Javascript call :
<script>
setHighlight('${highlight}');
</script>
I could not find any IceFaces component which is re-rendered at each JS call. I found that placing the script into a panelGroup works most of the time. However, there was a case that did not work :
submitting the form with errors do trigger the JS.
then, re-submitting the form with errors on the same field than previous validation do NOT trigger the JS.
then, re-submitting the form with any error field having no more errors do trigger JS.
then, re-submitting the form with any non-errored field having an error do trigger JS.
For some reason, IceFaces do not render the panelGroup that contains the JS when the set of fields having errors is the same between two calls.
I tried to use the Javascript API with code like Ice.onAsynchronousReceive(), using Prototype library to attach an event to the AJAX completion of the commandButton, but had not much success with it. Some of my tests could run (with errors but did the job) and I could observe similar behavior.
Here is the trick I finally used (ugly but working) :
<ice:panelGroup>
<script type="text/javascript">
var useless = '#{testBean.time}';
setHighlight('${highlight}');
</script>
</ice:panelGroup>
The getTime() function simply return the current timestamp. The value is then always different and trigger the JS execution at any AJAX request.
Sadly, IceFaces do not have the RichFaces useful "oncomplete" attribute, which I do regret highly for this case.
Ugly solution, but funny and working.

Wicket page links do not use mounted URL coding strategy?

In the Wicket Application class I have mounted a page at the location /about
mountBookmarkablePage("about", AboutPage.class);
I verify that the about page is available at /about. Then in the page which needs a link to the about page, I use the Wicket Link class:
add(new Link("link") {
#Override
public void onClick() {
setResponsePage(AboutPage.class);
}
};
)
The links work as expected but the target URL diplayed in the browser status bar when the mouse is over the link looks like
http://localhost:8080/?wicket:interface=:0:linkpage:repeating:1:link::ILinkListener::
A workaround which I have found is to use ExternalLink
new ExternalLink("link", "/about", "about");
This changes the target URL to
http://localhost:8080/about
which is displayed in the browser status bar when the mouse is over the link.
Is there a way to use the mounted URL as the target link with Wicket Link class, or is there a way to get the mount location for a class, so that I can use it to build the link url for AboutPage.class (instead of hard coding it in the ExternalLink constructor)?
For this purpose you should use BookmarkablePageLink (as you're saying you're doing), to set the link label (or any other content for that matter) just call .add(Component... c) since BookmarkablePageLink is actually a MarkupContainer.
So, to create a link to AboutPage.class you need to do this:
BookmarkablePageLink aboutLink = new BookmarkablePageLink("link", AboutPage.class);
aboutLink.add(new Label("linkText", "Go to About page"));
add(aboutLink);
and the matching markup
<a wicket:id="link"><span wicket:id="linkText">Link text goes here</span></a>
Yeppers, it's slightly more verbose but also very easily extensible. If you want to, you can create your own convenience subclass of BookmarkablePageLink called BookmarkableTextLink and have a
new BookmarkableTextLink(String id, Class<Page> pageClass, String linkText);
constructor for it.
Found a solution: the BookmarkablePageLink class
add(new BookmarkablePageLink("link", AboutPage.class));
This solution only has a small problem: the link label can not be set, maybe this can be done by assigning a model.

Resources