Showing posts with label custom components. Show all posts
Showing posts with label custom components. Show all posts

Tuesday, 12 January 2016

Lambda expression as JSF actionListener

Introduction

Although there is no official version of JSF which supports Java 8, there are various application servers that run on it today. And thus can we use some Java 8 features today.

I'll show you in this blog post an example of using a lambda expression as an action listener. And more specific where we have a custom composite component with multiple actions sources.

And although I'm not a fan of the binding property, probably due to the issues I had with it during the early days of JSF 1.x, it is a nice use case for Lambda expressions.

Custom composite component

Short recap of what a custom composite component is.
If you have on multiple screens a set of components used in the same manner, you can create a custom component for it. The markup doesn't need to be exactly the same on all those pages or linked to the same managed bean, because you can specify parameters.

That way you can also 'build' your screens using different reusable blocks and you have a very modular approach comparable with using Java methods to increase readability.

And creating those custom composite components is very easy in JSF 2.x. Create JSF file with the definition of your component (interface  and implementation parts) in a special specific folder and you are ready to use it due to the convention principles in place.
Have a search on the internet on this topic and you find various examples how you can do it.

Assigning an action listener to a button within your custom composite components seems for some people a bit more difficult but using the actionSource attribute of the composite component namespace makes it very easy.

<ui:component xmlns="http://www.w3.org/1999/xhtml"
              xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
              xmlns:cc="http://xmlns.jcp.org/jsf/composite"
              xmlns:p="http://primefaces.org/ui">

    <cc:interface>
        <cc:actionSource name="submitListener" targets="submitBtn"/>
        <cc:actionSource name="cancelListener" targets="cancelBtn"/>
    </cc:interface>
    <cc:implementation>
        <div>
            Some multiple button component 
            <p:commandButton id="submitBtn" value="Submit"/>
            <p:commandButton id="cancelBtn" value="Cancel" immediate="true"/>
        </div>
    </cc:implementation>
</ui:component>


The above example defines a custom composite component where we have 2 buttons and each of them, we can assign a different actionListener.

ActionListener

ActionListener is a JSF interface defined for those implementations which want to respond on the click on a button (for example there are other components which also generate the same event) on the screen.

The interface has just one method, as you can see;
/**
 * Invoked when an action occurs.
 * @param e the event to be processed
 */
public void actionPerformed(ActionEvent e);

This makes it an ideal candidate to use it in combination with Lambda expressions since we have a functional interface.

So the following lambda expression
e -> System.out.println("Save clicked");

is valid implementation for the actionListener interface and thus we can assign such methods to the button(s).

Binding the actionListener implementation

As a said in the introduction, with the binding attribute, it is very easy to 'bind' an implementation of the ActionListener interface to the button. 

<adv:multiple>
    <f:actionListener for="submitListener" binding="#{cityBean.save}"/>
    <f:actionListener for="cancelListener" binding="#{cityBean.cancel}"/>
</adv:multiple>
In the above example we retrieve the instance to which the listener is bound to, with a method result. The java code can be as follows.

@Modelpublic class CityBean {

   private ActionListener save;
   private ActionListener cancel;

   @PostConstruct
   public void init() {
      save = e -> System.out.println("Save clicked");
      cancel = e -> System.out.println("Cancel clicked");
   }

   public void performSearch() {
      System.out.println("Searching ");
   }

   public ActionListener getSave() {
      return save;
   }

   public ActionListener getCancel() {
      return cancel;
   }

}
As you can see, this is a nice,clean usage of lambda expressions where we have multiple actionListener targets in the custom composite component.

Conclusion

Using a lambda expression for an ActionListener implementation make your code much more readable and reduces the boilerplate in those cases where you need multiple actionSources for a custom composite component.

Enjoy Java 8 and Java EE!



Monday, 19 January 2015

GridLayout component for JSF 2.X

Introduction

It is common practice to use a CSS Grid to define the layout of your web application page.  We shouldn’t use tables for that purpose.
Also in JSF we can use this CSS Grid but it requires quit a lot of DIV elements and thus boilerplate in your page. The good thing is that we can create a custom component which reduce the amount of html we need to put in dramatically.  The component got the name gridLayout.

PrimeFaces recently introduced in his version 5.1, also CSS Grid classes.  The following example comes from the user guide.
<div class="ui-grid">
    <div class="ui-grid-row">
        <div class="ui-grid-col-4">Col1</div>
        <div class="ui-grid-col-4">Col2</div>
        <div class="ui-grid-col-4">Col2</div>
    </div>
</div>

But also other CSS Grid systems can be used with the gridLayout custom component.  The component was first used in an application that used the Bootstrap CSS grid.  And in fact, all CSS grids can be used as you specify which CSS class will be used on the row DIV and which will be used on the column DIVs.

gridLayout

The gridLayout component has 3 attributes, which are
columns: This determines the number of columns which should be created.
rowClass: Determines the CSS class which will be used on the row DIV, in above example it is ui-grid-row.
columnClasses: A comma separated list of CSS classes which will be used on the column DIVs.

The needed steps to integrate the component are described further on in this text, I already give you an example usage:

<c4j:gridLayout columns="2" rowClass="ui-grid-row" columnClasses="ui-grid-col-2, ui-grid-col-4">
    <p:outputLabel for="firstName" value="First name"/>
    <p:inputText id="firstName"/>
    <p:outputLabel for="lastName" value="Last name"/>
    <p:inputText id="lastName"/>
    <h:panelGroup/>
    <p:commandButton value="save"/>
</c4j:gridLayout>
The above example creates a layout with 2 columns. The first column, with the labels, spans 2 ‘columns’, the other column takes 4 ‘columns’ of the CSS grid.  As you can see, we don’t need to take up the complete with available.  In this example, we are just using half of the screen.
On the last row, the button is aligned with the fields due to the .

Configure the project and usage of the component.

  • Download the code from GitHub.  It is a maven project but I didn’t deploy it to Maven Central.
  • Build it locally and add it to the dependencies of your project
<dependency>
     <groupId>be.rubus.web</groupId>
     <artifactId>gridLayout</artifactId>
     <version>1.0</version>
</dependency>
  • Define the namespace on top of your xhtml page, like 
xmlns:c4j="http://www.rubus.be/component"
  • Start using it, according to the info you saw already here.

Things to know

  • It is released under the Apache V2 License.
  • It is compiled against Java 1.5
  • It is only dependent on JSF 2.0 (Java EE 6).
  • It is NOT dependent on any component library.
  • If you define less CSS classes in the columnClasses attribute, as you have defined in the columns attribute, columnClasses are reused from the beginning of the attribute value.
    So the example from the PrimeFaces user guide can be achieved by the following coding
    <c4j:gridLayout columns="3" rowClass="ui-grid-row" columnClasses="ui-grid-col-4">
  • The correct assignment of each JSF component to a certain column and row is only guaranteed if you use JSF components as children.  If you use html elements or plain text/EL expressions, the layout can be very surprising and not want you had in mind.
  • You can also put your custom CSS classes in the columnClasses attribute and even combine them.  So if you want to right align the label column, you can write something like this.
    <c4j:gridLayout columns="2" rowClass="ui-grid-row" columnClasses="ui-grid-col-2 alignRight, ui-grid-col-4">

Conclusion

The gridLayout component is a very small one but makes it easy to use the CSS Grid of your choice in your JSF Web pages.
Have fun coding.

Update

13/4/2015

With the new PrimeFaces 5.2 release, the panelGrid component is updated to have similar functionality as the GridLayout (but only for PrimeFaces CSS classes)

See http://jsfcorner.blogspot.co.at/2015/04/native-gridlayout-component-in.html.