JDev 12c: Badge Button reloaded

In my article JDev: Badge Button I showed how to build a special button with a notification ‘badge’:

The declarative component of this sample was build using JDev 11g (11.1.1.9.0 to be exact).

I received a couple of question on how to work with this declarative component in JDev 12c projects. In general, you can use the same source and build the declarative component in JDev 12c. However, as JDev 12c is using a different document type, Facelets instead of JSP XML, you can use the badge button only on JSPX type pages.

So, in this blog, I show how to create a declarative component which is usable in Facelets type pages. I don’t change the behavior of the badge button but reuse the code. This blog is more about how to create a declarative component in 12c and show the differences to 11g.

JSPX vs. Facelets

With the introduction of JSF 2.0 (JavaServer Faces 2.0 Overview and Adoption Roadmap in Oracle ADF Faces and Oracle JDeveloper 11g) a new document type Facelets was introduced. The difference and the motivation behind this is outlined in the document.

We are only interested in the fact that you can’t mix components designed for JSPX XML pages or fragments with Facelets type pages or fragments. This means that you can’t add the badge button created for 11g to a jsf page of jsff fragment of type ‘Facelet’.

Building a Declarative Component for 12c

We start from the old application workspace I created for the 11g implementation. Opening this workspace will migrate it to the 12c. At the end of the blog, you’ll find a link to download the final workspace for 12c.

After the migration we add a new project ‘BBB12cDeclarativeComponent’ of type ‘ADF ViewController Project’ to the workspace:

After creating a new project for the 12c badge button, we create a new ‘Declarative Component’ in the ‘Web Content’ folder

In the wizard, we now select ‘Facelets’ as the document type. Selecting ‘Facelets’ will create the 12c kind of declarative component.

Once we finished the wizard, we get the skeleton declarative component in the ‘BadgeButton12c.jsf’ file. If you got a file name ‘BadgeButton.jspx’ you did not set the document type to ‘Facelets’.

Now we can copy the code from the original sample written for 11g and copy it after the componentDef tag. Once you copied the code from the original sample you have to change the EL used to address the action and the actionListener to match the componentVar property in the componentDef tag. To make this distinguishable from the 11g sample, I changed the componentVar to ‘compButton’. The other change is to use an af:button tag instead of the af:commandButton tag. While the af:commandButton tag can still be used, 12c application should use the af:button tag.

 

The final code looks like

Adding the declarative component to the faces palette

You already know, that to use the declarative component in a project, you first have to add it to the component palette. The difference to the 11g sample is that we have to choose a different node in the project definition to add the library.

First, we need to deploy the declarative component project to an ADF Library. For this, all we need to do is to execute the deployment profile created with the project

Next, we add a ‘File System’ resource which points to the folder the jar is created in

And the jar should show up

To make it usable in the view controller project, we have to add the jar to the project

Now, when we look into the view controller projects properties, we find the new declarative component in the ‘Facelets Tags Libraries’ node. In JDev 11g the tab libraries can be found in the node ‘JSP Tag Libraries’. Again, the difference is where the tags or declarative component are usable. You use JSP tags in JSP XML files and you use Facelets tags in JSF files.

Next step is to create a new JSF Page in the adfc-config.xml, the unbounded task flow.

Again, we make sure to select ‘Facelets’ as document type as we otherwise will not be able to use the declarative component created for ‘Facelets’.

The layout of the page is similar to the one for 11g. 12c uses a panelGridLayout instead of the panelStretchLayout, but that’s all.

As we are now using a JSF page and added the 12c component library and find the BadgeButton in the component palette

and use this on the page. The final layout looks like

Or when running the JSF page

Clicking the button we get the log messages

Sample Application

You can download the sample application from GitHub BlogBadgeButton12.2.1.2

Advertisements

JDev: Badge Button

In this article, I describe how to build what I call a ‘Badge Button’. This is a button we know from many mobile applications which shows, e.g., how many new messages have arrived since the last visit.

The image above shows what I have in mind. We see a standard button with a badge indicating the number of new items. The badge can be used to display text as well

The idea behind this came from a question on the ODC JDev & ADF space. When I first read the question I wanted to answer “No, there isn’t such a component in ADF”, but after thinking about it, I decided to build one myself.

The Problem has two parts:

  1. How to build the badge
  2. How to create the component looking like a button with a badge

Solution Part 1

Making the badge turned out to be very easy. Searching the web, you find plenty of solutions for such components using CSS. As you might know, it’s not very straightforward to add a CSS solution to ADF. However, there are ways to do this. In the end, I used the following CSS to generate the badge:

.badge {
 background: radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -moz-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -ms-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -o-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background: -webkit-radial-gradient( 5px -9px, circle, white 8%, red 26px );
 background-color: red;
 border: 2px solid white;
 border-radius: 12px; /* one half of ( (border * 2) + height + padding ) */
 box-shadow: 1px 1px 1px black;
 color: white;
 font: bold 15px/13px Helvetica, Verdana, Tahoma;
 height: 16px;
 padding: 4px 3px 0 3px;
 text-align: center;
 min-width: 14px;
 margin: 0px 0px 20px -10px;
 position: relative;
}

Solution Part 2

ADF uses CSS which is built from skin files. It’s not straightforward to add any other CSS to a component as you don’t see the generated HTML where you need to add the CSS. So adding the CSS class just as style to the button doesn’t work, as you can’t add new properties to ADF components. You will get an error like

To create a badge, you need to create a span or div with the CSS class and some data which is put into the badge like
Selection_474

This can’t be added to an existing component easily. However, ADF has a component which renders as a div tag, the af:outputText. If you add an af:outputText to a page and look at the resulting HTML you get
Selection_475
So, the value of the outputText is just surrounded by a div tag. The problem still is that you can’t add your own property to the ADF component, but we can add the div with the needed style and the data as the value you the af:outputText component. All we have to do, other than to add the div is to set the escape property of the outputText to false. This setting avoids that ADF encodes the value which would transform the ‘<’ into ‘<’, essentially making a string out of the value. The reason for that is to prevent security issues (injection), so be aware of this!

Putting this on a page would look like

And generates

The solution works somehow, if we put an af:button on the page instead of the af:spacer. However, it looks ugly or ‘uncool’ to see the ‘div’ in the af:outputText.

Final Solution

The final solution is to hide the ‘how to build it’ in a declarative component. The use case is a perfect fit for an ADF declarative component. We move the CSS, the button and the outputText in such a component and can use the component in the page to get

The new solution looks clean, as the CSS and odd looking outputText isn’t visible. Here are some images of the running test application.

The input field is used to set the data to be shown on the badge. It can be numbers, text or both. Clicking on the button calls the action listener and the action.

And this is the log output.

Building the Declarative Component

There are many other blogs about how to create a declarative component so I will not do this in detail. However, I like to point out some things you should keep in mind when you create such a declarative component.

To make the component work, it’s not enough to just add a button and the outputText holding the CSS. We have to make properties available for the action and the actionListener of the button. If we don’t do this, all we get is a button, which is looking good but which can’t be used to start a navigation or to call an actionListener. The same is true for other properties of the button inside the declarative component. We have to add a property for the button text at least. If you like to enable/disable the badge button, you have to expose an attribute in the declarative component interface to get the value from the outside, your page See later).

When we build the declarative component, we start by adding another ‘ADF View Controller Project’ to the workspace. Declarative components should be developed in a separate project. They are deployed as adfLibrary jar files. We add a new JSF Declarative Component to the project.

And fill out a dialog with necessary data. This data can be changed later if needed. Here is a sample

Once we click OK, a jspx page with the selected name will be created alongside a meta-data file holding the information about the tag library.

In the JSPX page, we create the layout of the component. We already know how to add the badge, all we need to do is to put an af:button onto the page and add the code to the badge to it. The resulting declarative component looks like

Select the af:componentDef tag and open the property editor. There you can define metadata like attributes and methods you want to pass to the component from the outside.

And the methods to activate the button.

The data you specified in the property editor is added to the af:componentDef tag.

A special case is the partialTrigger property. You can’t set a partialTrigger from the outside to a component used in the declarative component. However, you can surround the declarative component with another component which has a partialTrigger property and use this outer component to send a ppr. In the code above I surrounded the declarative component with an af:panelGroupLayout which listens for ppr send from the af:inputText with the id “it1”. This partial refresh is needed in the sample to refresh the button with a new value entered in the field.

If you need more attribute to control the behavior of the component, you can add them via the property editor. For this simple test case, the attributes and methods are enough.

The sample application and declarative component is build using JDev 11.1.1.9.0 and can be downloaded from GitHub BlogBadgeButton. The sample doesn’t need a DB.