JDeveloper: Skin Radio Buttons

In this blog article, I like to share how to use a skin to alter the look of radio buttons in ADF. The use case was a question on the ODC space JDeveloper & ADF which asked about how to provide more space for the radio buttons.

Here is an image of the default and the resulting radio buttons:

As you see, in the first radio group the space between the selectItems is narrower than in the second group.

In my older post about JDeveloper: Advanced Skin Technique I showed how to find out which style to change, so I spare this here.

The image above shows the standard “radiogroup” in Chrome Developer Tools. As you can see the radiogroup consists of “div” elements, each specifying one of the selectItem.

To change the spacing, we add a style class to the skin file like

.mysor af|selectOneRadio::content div {
  padding: 0px 0px 10px 0px;
}

The “.mysor” is the name of the style class which we later use on the page. The magic is done by specifying the base style as af|selectOneRadio::content and from there style each “div” element having the base style as a parent. This way we style the blue marked div in the image above.

One question remains. Why do we use a skin and don’t add the code right into the page?

Well, using a skin is the preferred method. The skin is created once and can be used everywhere in the application. If you need to make changes, you don’t have to search for the pages where the style has been added, but you just change the skin file and you are done.

Download Sample

You can download the sample which is build using JDev 12.2.1.2.0 and uses the HR DB schema from GitHub BlogAdvancedSkin

 

 

Advertisements

JDeveloper: Showing a Popup when Selecting an af:selectOneRadio

A question on the new OTN JDeveloper and ADF forum (or space if you like the new name better) inspired this post.

Use Case
The use case is to show a popup each time the user clicks on one of the radiobuttons of a button group. This popup should show an inputText component to let the user enter some text for the selection. After the selection the text is shown on the page under the button group.
To make it more interesting, it was not ask for this in the question, the popup should show which radio button was clicked.
UPDATE
An additional question on the OTN forum asks how to display the label of the selected radiobutton and not it’s value. I updated the workspace to show how to implement this.

Implementation UPDATE
The use case sounds easy first: add a showPopupBehavior to the selectItem to show the popup and show the selected radioValue as the title of the dialog inside the popup. Problem with this solution is that a selectItem can’t handle client listeners, which a showPopupBehavior is under the hood. If you try this you get an error

Caused by: javax.servlet.jsp.JspException: ADF_FACES-60023:Component: RichSelectItem[UIXFacesBeanImpl, id=si10] does not support client listeners.

Putting the showPopupBehavior onto the af:selectOneRadio isn’t a solution either as this would would allow to show the popup, but would prevent the selection of the radio button. This is because the showPopupBehavior is a client behavior tag which prevents the event to
go further.

The solution to the problem is to use a valueChangeListener on the af:selectOneRadio and show the popup from the bean code. Before showing the popup we need to process the value change event to get the selected value in the dialog of the popup.

The UI part looks like

        <af:panelGroupLayout id="pgl2">
          <af:selectOneRadio label="Activation" id="sor1" value="#{bindings.SelectedActivation1.inputValue}"
                             inlineStyle="border-width:thin; border-color:Blue; border-style:solid;"
                             valueChangeListener="#{RadiobuttonPopupBean.activationChangedListener}" autoSubmit="true">
            <af:selectItem label="Active" value="active" id="si1"/>
            <af:selectItem label="Inactive" value="not active" id="si2"/>
          </af:selectOneRadio>
          <af:outputText value="Last reason: #{bindings.PopupText1.inputValue}" id="ot1" partialTriggers="d1"/>
        </af:panelGroupLayout>
        <af:popup id="p1" contentDelivery="lazyUncached" binding="#{RadiobuttonPopupBean.radioPopup}">
          <af:dialog id="d1" title="Selected: #{bindings.SelectedActivation1.inputValue}">
            <af:inputText label="Reason" id="it1" value="#{bindings.PopupText1.inputValue}"/>
          </af:dialog>
        </af:popup>

The listener code in the bean, which is created in request scope as it contains a reference to a ui component, look like

import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;

import oracle.adf.view.rich.component.rich.RichPopup;

import org.apache.myfaces.trinidad.util.ComponentReference;

public class RadiobuttonPopupBean {
    private ComponentReference radioPopup;

    public void setRadioPopup(RichPopup radioPopup) {
        this.radioPopup = ComponentReference.newUIComponentReference(radioPopup);
    }

    public RichPopup getRadioPopup() {
        if (radioPopup != null)
            return (RichPopup)radioPopup.getComponent();

        return null;
    }

    public void activationChangedListener(ValueChangeEvent valueChangeEvent) {
        // process updates to get the selected value inside the popup
        FacesContext contxt = FacesContext.getCurrentInstance();
        valueChangeEvent.getComponent().processUpdates(contxt);
        //show the popup
        RichPopup.PopupHints hint = new  RichPopup.PopupHints();
        getRadioPopup().show(hint);
    }
}

The application running look like


You see that the popup shows the value of the selected radio button as the title and the entered text in the popup is shown as ‘last reason’ below the radio button group. This ‘magic’ is done by simply adding a partial trigger to the outputText component which is listening to the dialog inside the popup.
As the sample don’t store the value of the selection of the radio group or the entered text in the db, I use the variable iterator to store these values. More about this technique can be found in my blog

UPDATED IMPLEMENTATION
As the use case changed a bit I changes the solution in a way to show how to implement this. First step is that I added another attribute to the variables iterator to store the selected label. The attribute is name ‘SelectedActivation1’ and is of type String. This attribute is needed as it’s not easyly possible to get the selected label of the radiobutton outside the selection listener. The changed valueChangeListener looks like the code below:

    public void activationChangedListener(ValueChangeEvent valueChangeEvent) {
        // process updates to get the selected value inside the popup
        FacesContext contxt = FacesContext.getCurrentInstance();
        valueChangeEvent.getComponent().processUpdates(contxt);
        //get the selected lable from the radio button
        // for this we need to iterate over the children of hte af:selectOneRadio
        // and find the child which has the same value as the new value
        RichSelectOneRadio rsoc =
            (RichSelectOneRadio)valueChangeEvent.getSource();
        List childList = rsoc.getChildren();
        String newVal = (String)valueChangeEvent.getNewValue();
        for (int i = 0; i < childList.size(); i++) {
            if (childList.get(i) instanceof RichSelectItem) {
                RichSelectItem csi = (RichSelectItem)childList.get(i);
                if (((String)csi.getValue()).equals(newVal)) {
                    // get the binding container
                    BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();

                    // get an ADF attributevalue from the ADF page definitions
                    AttributeBinding attr = (AttributeBinding)bindings.getControlBinding("SelectedLabel1");
                    // and store the label there
                    attr.setInputValue(csi.getLabel());
                }
            }
        }
        //show the popup
        RichPopup.PopupHints hint = new RichPopup.PopupHints();
        getRadioPopup().show(hint);
    }

The images below showing the changes application

You can download the workspace from the ADF EMG Sample Project BlogTestRadiobutton.zip. The sample uses the HR DB schema (even as this is not really needed for the sample).