Tuesday, 9 February 2016

Programmatically disable af:selectItem in af:selectOneChoice based on some conditions in ADF

Explanation: For demonstarion we will use the Countries table present in the HR schema of the Oracle Database XE 11g.

Requirement: I have a demo.jspx page. On that page I have one af:selectOneChoice component displaying all the CountryNames from the Countries table by default.

Also I have an af:button named as “Disable Some Countries Name“. Create an actionListener for the af:button as actionListener = "#{pageFlowScope.MyBean.disableCountryNames}"

Now my requirement is:
  1. When the page load it should disable the CountryName “Italy“ and “Nepal“ in the first af:selectOneChoice component by default.
  2. Initially none of the CountryName will be disabled in the second af:selectOneChoice component. When I click on the “Disable Some Countries Name“ button then only it should disable some of the Countries Name like: Argentina, Brazil, Egypt, Italy,and Nepal. I will pass the Countries to be diabled form the Java class.
Solution: For solution to the above requirement follow the steps as shown below:

Step 1: Create an Oracle ADF Fusion Web Application and name the application as ChoiceListEnableDisable.

Step 2: Create an ADF Business Components from Table for the Countries table. We will be creating all the three Business Components: CountriesEO, CountriesVO, and AppModule as shown below:


Step 3: Create the List of Value for the CountryName attribute as shown below:


Step 4: Create the demo.jspx page. Select CountryName attribute from the CountriesVO1 inside AppModuleDataControl and drag and drop it on the demo.jspx page as an af:selectOneChoice components.

Again select CountryName attribute from the CountriesVO1 inside AppModuleDataControl and drag and drop it on the demo.jspx page as an af:selectOneChoice components.

Drag and drop af:button from the component palette in the demo.jspx page. Name the af:button as “ Disable Some Countries Name". Create an actionListener as actionListener= "#{pageFlowScope.MyBean.disableCountryNames}".

Set partialTriggers="b1" for the second af:selectOneChoice components.

Create CountriesVO1 Tree Bindings. To do so open demo.jspx page --> Go to Bindings Tab--> Click on green + icon beside Bindings --> Select Root Data Source as AppModuleDataControl.CountriesVO1 --> Click the green + icon beside Tree Level Rules to Add Rules --> Select model.CountriesVO  --> Shuttle CountryName as the Display Attrubute as shown below:

Thus CountriesVO1 Tree Binding gets created and we can use this in our demo.jspx page inside af:forEach.


Remove f:selectItem from both the af:selectOneChoice components.

Drag and drop af:selectItem from the component palette inside both the af:selectOneChoice components. Surround both the af:selectItem  with af:forEach components. Set the items names for both the af:forEach compoenents as items="#{bindings.CountriesVO1.rangeSet}".

Give the var name as var="list1", and var="list2" for the first and the second af:selectOneChoice components respectively.

For the first af:selectItem set label="#{list1.CountryName}", value="#{list1.CountryName}", and disabled condition as disabled="#{list1.CountryName=='Italy' ||list1.CountryName=='Nepal'}". Here we are passing some fixed values in the demo.jspx page itself.

For the second af:selectItem set label="#{list2.CountryName}", value="#{list2.CountryName}", and disabled condition as disabled="#{pageFlowScope.MyBean.cname.contains(list2.CountryName)}". 

Here pageFlowScope.MyBean.cname will get its value from the MyBean.java class. Here we can control the CountryName to be disabled more dynamically.

Thus, the complete demo.jspx code is shown below:

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
       <jsp:directive.page contentType="text/html;charset=UTF-8" />
       <f:view>
              <af:document title="demo.jspx" id="d1">
                     <af:messages id="m1" />
                     <af:form id="f1">
                           <af:selectOneChoice value="#{bindings.CountryName.inputValue}"
                                  label="#{bindings.CountryName.label}"
                                  required="#{bindings.CountryName.hints.mandatory}"
                                  shortDesc="#{bindings.CountryName.hints.tooltip}" id="soc2">
                                  <af:forEach items="#{bindings.CountriesVO1.rangeSet}" var="list1">
                                         <af:selectItem label="#{list1.CountryName}" id="si2"
                                                value="#{list1.CountryName}"
                                                disabled="#{list1.CountryName=='Italy' ||list1.CountryName=='Nepal'}" />
                                  </af:forEach>
                                  <!--<f:selectItems value="#{bindings.CountryName.items}" id="si2"/>-->
                                  <f:validator binding="#{bindings.CountryName.validator}" />
                           </af:selectOneChoice>
                           <af:selectOneChoice value="#{bindings.CountryName.inputValue}"
                                  label="#{bindings.CountryName.label}"
                                  required="#{bindings.CountryName.hints.mandatory}"
                                  shortDesc="#{bindings.CountryName.hints.tooltip}" id="soc1"
                                  partialTriggers="b1">
                                   <!--<f:selectItems value="#{bindings.CountryName.items}" id="si1"/>-->
                                  <af:forEach items="#{bindings.CountriesVO1.rangeSet}" var="list2">
                                         <af:selectItem label="#{list2.CountryName}" id="si1"
                                                value="#{list2.CountryName}"
                                                disabled="#{pageFlowScope.MyBean.cname.contains(list2.CountryName)}" />
                                  </af:forEach>
                                  <f:validator binding="#{bindings.CountryName.validator}" />
                           </af:selectOneChoice>
                           <af:button text="Disable Some Countries Name" id="b1"
                                  actionListener="#{pageFlowScope.MyBean.disableCountryNames}" />
                     </af:form>
              </af:document>
       </f:view>
</jsp:root>
Step 5: Open MyBean.java and write the codes. Thus, the complete MyBean.java code is shown below:

package com.susanto;

import java.util.ArrayList;
import java.util.List;

import javax.faces.event.ActionEvent;

public class MyBean {
       List<String> cname = new ArrayList<String>();

       public void setCname(List<String> cname) {
              this.cname = cname;
       }

       public List<String> getCname() {
              return cname;
       }

       public MyBean() {
       }

       public void disableCountryNames(ActionEvent actionEvent) {
              cname.clear();
              cname.add("Argentina");
              cname.add("Brazil");
              cname.add("Egypt");
              cname.add("Italy");
              cname.add("Nepal");
              System.out.println("Elements in cname are : " + cname);
       }
}

Step 6: Save all and run the application. Thus the ran application is shown below:


On click of the first CountryName selectOneChoice component we can see that the CountryName Italy and Nepal are disabled:


Click on the second selectOneChoice component of the CountryName and we can see that none of the CountryName are disabled as shown below:


On click of the "Disable Some Countries Name"  button the following CountryName: Argentina, Brazil, Egypt, Italy,and Nepal gets disabled as shown below:


Hence, the solution to our requirement.

If we like the post please comment, share and like me on Facebook.


Thanks & Regards,
Susanto Paul