Showing posts with label LOV. Show all posts
Showing posts with label LOV. Show all posts

20 Apr 2015

Altering LOV View Criteria on-the-fly

In this post I am going to show how we can programmatically modify a view criteria which is applied to the view accessor view object at the LOV's popup window.

Let's consider a simple example. There is a page with Employee LOV on it:


Besides Employee LOV there is Min Salary field on the page. This field stores its value in a managed bean property. Users use this field in order to force the Employee LOV to show only employees whose salary is not less than required. So, basically, if Min Salary is not empty, the LOV dialog should look like this:



The LOV's view object (VEmployees) has a corresponding view criteria VEmployeesCriteria:


What we're going to do is to set up at run-time the minimum salary value in the LOV's launchPopupListener:

 <af:inputListOfValues id="ilov1"
   launchPopupListener="#{viewScope.TheBean.lovPopupListener}"

And a corresponding managed bean method is going to look like this:

public void lovPopupListener(LaunchPopupEvent launchPopupEvent) {
    UIXInputPopup lovComponent = (UIXInputPopup) launchPopupEvent.getSource();

    //Get LOV's View Criteria
    ListOfValuesModelImpl model = (ListOfValuesModelImpl) lovComponent.getModel();
    ViewCriteria vc = model.getCriteria();

    //Get first View Criteria Row
    ViewCriteriaRow vcr = (ViewCriteriaRow) vc.getRows().get(0);

    //Set up View Criteria Item
    vcr.setAttribute("Salary", getMinSalary())
}

The sample application for this post can be downloaded here. It requires JDeveloper 12.1.3.

That's it!



28 Feb 2015

LOVs in Oracle MAF

We all love one of the most powerful ADF features lists of values. Using them we can declaratively and easily build pretty complicated functionality in ADF applications. A good thing is that we have a similar approach in Oracle MAF as well. In ADF BC we define LOVs, attribute UI hints, validation  rules, etc. at the Business Service level, basically at the Entity or VO level. In MAF we are able to do the same but at the Data Controls level. This is pretty obvious since who knows what the business service is. It can be whatever in Oracle MAF.
So, in this post I am going to show how we can define and work with LOVs in Oracle MAF.
Let's consider a simple use-case. There is a payment form which looks like this:


An end user selects an account in the drop-down list and the total account balance is going to be used as a default payment amount, however the amount can be changed.
The business model is based on a couple POJO classes:

public class PaymentBO {

    private int accountid;
    private double amount;
    private String note;

and
public class AccountBO {

    private int id;
    private String accountName;
    private double balance;

There is also AccountService class providing a list of available accounts:
public class AccountService {

    private final static AccountService accountService = new AccountService();

    private AccountBO[] accounts = new AccountBO[] {
        new AccountBO(1, "Main Account", 1000.89),
        new AccountBO(2, "Secondary Account", 670.78),
        new AccountBO(3, "Pocket Account", 7876.84),
        new AccountBO(4, "Emergency Account", 7885.80)
    };


    public AccountBO[] getAccounts() {
        return accounts;
    }


    public static synchronized AccountService getInstance() {
        return accountService;
    }

And there is PaymentDC class which is exposed as a data control:
public class PaymentDC {

    private final PaymentBO payment = new PaymentBO();
    private final AccountService accountService = AccountService.getInstance();

    public PaymentBO getPayment() {
        return payment;
    }


    public AccountBO[] getAccounts() {
        return accountService.getAccounts();
    }
}

The DataControl structure looks like this:



In order to be able to define Payment attribute settings such as UI hints, validation rules, LOVs, etc. I am going to click the pencil button and I will have a form which looks pretty similar to what we have in ADF BC:




Those who are familiar with ADF BC will hardly get lost here. So, at the List of Values page we can define a LOV for the accountid attribute:





Having done that, we're able to setup LOV's UI hints, etc. Basically that's it. All we need to do is to drop accountid attribute from that DataControl palette onto a page as a selectOneChoice component.


<amx:selectOneChoice value="#{bindings.accountid.inputValue}"
                     label="#{bindings.accountid.label}" id="soc1">
    <amx:selectItems value="#{bindings.accountid.items}" id="si1"/>
</amx:selectOneChoice>


The framework will do the rest defining the list binding definition in the pageDef file:

 <list IterBinding="paymentIterator" StaticList="false"
        Uses="LOV_accountid" id="accountid" DTSupportsMRU="true"
        SelectItemValueMode="ListObject"/>


But we have to implement somehow setting of the payment amount with the account balance when the account is selected. In ADF we would be able to define multiple attribute mappings in the LOV's definition and that would be the solution. Like this:


But in MAF it doesn't work. Unfortunately.  Only the primary mapping works. So, we're going to do that manually in the PaymentBO.setAccountid  method:

public void setAccountid(int accountid) {
    this.accountid = accountid;

    AccountBO account = AccountService.getInstance().getAccountById(accountid);
    if (account != null) {
        setAmount(account.getBalance());
    }
}

And in the PaymentBO.setAmount method we have to fire a change event in order to get the amount field refreshed on the page:

public void setAmount(double amount) {
    double oldAmount = this.amount;
    this.amount = amount;
    propertyChangeSupport.firePropertyChange("amount", oldAmount, amount);
}


That's it!

The sample application for this post can be downloaded here. It requires JDeveloper 12.1.3 and MAF 2.1.0.


31 Oct 2014

Showing a Subset of Display Attributes in the Drop-down List with Combo box List of Values

Combo box List of Values (inputComboboxListOfValues) is supposed to be a very popular ADF Faces component for working with LOVs. Frankly speaking, this is my favorite approach when it comes to Lists of Values. In this short post I am going to focus on one feature which is often overlooked by ADF developers. If a LOV is defined by default, for example like this:


Then the framework will render the entire list of display attributes in the drop-down combo box and  in the search dialog. For the search form this is desired in our use-case. Basically, that's why all available attributes are selected. But, definitely, it would be better to show a bit shorter attribute list in the combo box. It is possible to define a subset of attributes to be shown in the drop-down list by using the Show in Combo Box option. We can specify the number of first attributes from the list to be rendered in the combo box:



Having done that, the LOV's behavior becomes more user-friendly.
Combo Box:

Search Dialog:
That's it!

25 Feb 2014

Dynamic LOV binding

In this post I am going to show how we can create list-of-values binding dynamically and add it to the binding container at run time. In order to create a LOV binding I've got a couple of methods in my managed bean:
public JUCtrlListBinding getJobsLOV() {
    
    //Find listOfValues binding in the current binding container
    //May be it is already there
    DCControlBinding jobsLov = getBindings().findCtrlBinding("JobId");
    
    //Let's create listOfValues binding as we didn't find it 
    if (jobsLov == null) {
        jobsLov = createJobsLOV(); 
    }
    
    return (JUCtrlListBinding) jobsLov;
 }

private JUCtrlListBinding createJobsLOV() {
  //Create an instance of listOfValues binding definition
  //Actually lovDef is going to be an instance of FacesCtrlLOVDef
  DefinitionFactory defFactory = 
      JUMetaObjectManager.getJUMom().getControlDefFactory();
  JUCtrlValueDef lovDef = 
      (JUCtrlValueDef) defFactory.createControlDef(JUTags.PNAME_listOfValues); 

  //Initialize listOfValues binding definition
  HashMap initValues = new HashMap();
  initValues.put(DCControlBindingDef.PNAME_IterBinding, "VEmployeesIterator");
  initValues.put(ListBindingDef.PNAME_ListServerBindingName, "LOV_JobId");  
  initValues.put(ListBindingDef.PNAME_AttrNames, new String[] {"JobId"});
  initValues.put(JUTags.ID, "JobId");
  lovDef.init(initValues);
    
  //Create an instance of listOfValues binding
  JUCtrlListBinding lov = (JUCtrlListBinding) 
         lovDef.createControlBinding(getBindings());
  
  //Add the instance to the current binding container
  getBindings().addControlBinding(lovDef.getName(), lov);
  return lov;
}


And a corresponding LOV component looks like this:
    <af:inputComboboxListOfValues id="jobIdId"
       popupTitle="Search and Select: #{LovBean.jobsLOV.hints.label}"
       value="#{LovBean.jobsLOV.inputValue}"
       label="#{LovBean.jobsLOV.hints.label}"
       model="#{LovBean.jobsLOV.listOfValuesModel}"
       required="#{LovBean.jobsLOV.hints.mandatory}"
       columns="#{LovBean.jobsLOV.hints.displayWidth}"
       shortDesc="#{LovBean.jobsLOV.hints.tooltip}"/>
 
The sample application for this post requires JDeveloper R2.

That's it!

30 Jun 2013

Resizing of Search and Select dialog of LOV Components

Playing with skin selectors of ADF Faces LOV components I found a new selector announced in release notes for 11.1.1.7.0 and 11.1.2.4.0 versions. The -tr-stretch-search-dialog selector enables the feature of resizing LOV's search and select dialog, allowing users to interact with this dialog in more convenient way.   

By default the feature is disabled and in order to enable it the source code in the css file for the inputListOfValues component should look like this:

af|inputListOfValues{
             -tr-stretch-search-dialog: true;
           } 


And for the inputComboboxListOfValues it should look like this:

af|inputComboboxListOfValues{
             -tr-stretch-search-dialog: true;
           } 



The cool thing is that when end user is resizing the dialog, it is going to stretch its content as well:




The sample application for this post can be downloaded here. It requires JDeveloper 11.1.2.4.0.

That's it!


22 Jun 2013

Building Custom LOV with searchContent Facet

List of Values UI components, such as inputListOfValues and inputComboboxListOfValues have a special facet searchContent. The facet is supposed to be used as an extension point which allows us to build our custom LOV's. The content of the facet is going to be rendered in the LOV's search dialog window. This feature looks pretty attractive, since there are lots of use cases when we would like to modify the search dialog content and functionality. And what is important, we basically don't want to throw away the existing LOV's search engine and build it ourselves from scratch. Our goal is to enhance a little bit the search dialog in terms of look and feel and to inherit the existing functionality.

In order to transform a LOV into the custom one, we've got to implement a couple of listeners and design the content of the searchContent facet. So, there is a LOV:

<af:inputComboboxListOfValues id="deptId"
    popupTitle="Search and Select: #{bindings.DepartmentId.hints.label}"
    value="#{bindings.DepartmentId.inputValue}"
    label="#{bindings.DepartmentId.hints.label}"
    model="#{bindings.DepartmentId.listOfValuesModel}"
    required="#{bindings.DepartmentId.hints.mandatory}"
    columns="#{bindings.DepartmentId.hints.displayWidth}"
    shortDesc="#{bindings.DepartmentId.hints.tooltip}"
    autoSubmit="true"
    
    returnPopupListener="#{LOVUtilBean.lovSearchListener}"
    launchPopupListener="#{LOVUtilBean.lovPopupListener}"
    >    


Attributes returnPopupListener and launchPopupListener refer to some managed bean methods. And the searchContent facet:
 <f:facet name="searchContent">
  <af:panelGroupLayout layout="vertical" id="pgl1">
    <af:query headerText="Search" disclosed="true"
      value="#{bindings.DepartmentId.listOfValuesModel.queryDescriptor}"
      model="#{bindings.DepartmentId.listOfValuesModel.queryModel}"
      queryListener="#{LOVUtilBean.queryListener.processQuery}"
      resultComponentId="::t1"
      saveQueryMode="hidden"
      modeChangeVisible="false" maxColumns="4"
      rows="1" id="q1"/>
             
    <af:table value="#{bindings.DepartmentId.listOfValuesModel.
                       tableModel.collectionModel}"
              var="row" rowBandingInterval="1"                        
              rowSelection="single" columnStretching="last"
              width="700px" id="t1">
      <af:column headerText="#{bindings.DepartmentId.listOfValuesModel.
                               itemDescriptors[0].name}"
                 id="c1" sortable="true"
                 sortProperty="#{bindings.DepartmentId.listOfValuesModel.
                                 itemDescriptors[0].name}"
                 align="left" width="80">
        <af:outputText value="#{row.DepartmentId}" id="ot1"></af:outputText>
      </af:column>
     
      <af:column headerText="#{bindings.DepartmentId.listOfValuesModel.
                               itemDescriptors[1].name}"
                 id="c2">
        <af:outputText value="#{row.DepartmentName}" id="ot2"/>
      </af:column>
    </af:table>
  </af:panelGroupLayout>
</f:facet>


The facet contains the standard Query+Table form, which is based on the LOV's model. Actually, we can fill free designing the content of the facet. The only requirement is that we should have one query component and one table component within the facet. But, even this restriction is based on the listener's implementation provided in this post. If you want to avoid the requirement, you can rewrite the listeners as you wish.

So, let's have a look at the listeners.
We're going to use the internal framework listener as the query listener of the Query component:
public QueryListener getQueryListener() 
{
  return queryListener;
}
private QueryListener queryListener = new InternalLOVQueryListener();
Handling the returnPopupEvent after selecting the value in the search dialog:  
public void lovSearchListener(ReturnPopupEvent returnPopupEvent)
{
  UIXInputPopup lovComponent =
    (UIXInputPopup) returnPopupEvent.getSource();

  //Looking for the table component within 
  //seacrhContent facet
  RichTable table = findTable(lovComponent);

  RowKeySet keySet = table.getSelectedRowKeys();


  if (keySet != null && keySet.size() > 0)
  {

    ListOfValuesModel model = lovComponent.getModel();
    Object newVal = model.getValueFromSelection(keySet);
    Object oldVal = lovComponent.getValue();

    //Have we selected anything new?
    //If yes, set it as a value of the LOV and update the model
    if (!ObjectUtils.equal(oldVal, newVal))
    {
      lovComponent.setValue(newVal);
      lovComponent.processUpdates(FacesContext.getCurrentInstance());
    }

  }
}

Handling the launchPopupEvent just before the search dialog is going to be rendered:
public void lovPopupListener(LaunchPopupEvent launchPopupEvent)
{
  UIXInputPopup lovComponent =
    (UIXInputPopup) launchPopupEvent.getSource();
  ListOfValuesModel model = lovComponent.getModel();

  if (model != null)
  {
    //Resetting the query component. 
    //So each time whenever the dialog is rendered the query component 
                  //is in its initial state
    QueryModel queryModel = model.getQueryModel();
    QueryDescriptor queryDesc = model.getQueryDescriptor();
    if ((queryModel != null) && (queryDesc != null))
    {
      queryModel.reset(queryDesc);
      //Looking for the query component within 
      //seacrhContent facet
      RichQuery query = findQuery(lovComponent);
      if (query != null)
        query.refresh(FacesContext.getCurrentInstance());
    }


    //If the LOV component has the searchFacet, then the framework fires this
    //event even in case of leaving the LOV component by TAB pressing. 
    //So, we have to check whether the dialog is really need to be launched.
    //And in case of exact match, we don't need any search dialog.
    Object oldVal = lovComponent.getValue();
    if (!ObjectUtils.equal(String.valueOf(oldVal),
                           launchPopupEvent.getSubmittedValue()))
    {
      List<Object> autoComplete =
        model.autoCompleteValue(launchPopupEvent.getSubmittedValue());
      
      //Do we have an exact match?
      if (autoComplete != null && autoComplete.size() == 1)
      {
        Object autoCompletedValue = autoComplete.get(0);

        Object newVal = model.getValueFromSelection(autoCompletedValue);
        lovComponent.setValue(newVal);
        lovComponent.processUpdates(FacesContext.getCurrentInstance());
        
        //We don't need to launch the dialog anymore
        launchPopupEvent.setLaunchPopup(false);
      }

    }

  }
}


The important thing is that these listeners are generic, they don't depend on any particular use-case and they don't depend on any particular LOV component. These methods can be gathered in some utility bean and used across the entire application.
The result of our work looks like this:
 
The sample application for this post can be downloaded here. It requires JDeveloper R2.

That's it! 

21 May 2013

Switching Lists of Values

Some time ago I blogged about a feature when a VO's attribute can have multiple LOVs and showed how to switch to the desired LOV depending on the value of another VO's attribute. I this post I'm going to use this technique again, but I'm going to choose the LOV for the attribute depending on its value, on the value of the attribute for which the LOV is defined.
Let's consider a simple use-case: We have an input field for a currency code. When a user inputs a currency code, we have to show corresponding currency description near the input field. So, it should look like this:


The implementation of this use-case is pretty obvious - we have to define a LOV for the currency attribute and set autoSubmit=true for the inputText.




<af:inputText value="#{bindings.Ccy.inputValue}"
              label="#{bindings.Ccy.hints.label}"
              required="#{bindings.Ccy.hints.mandatory}"
              columns="#{bindings.Ccy.hints.displayWidth}"
              maximumLength="#{bindings.Ccy.hints.precision}"
              shortDesc="#{bindings.Ccy.hints.tooltip}" id="it1"
              autoSubmit="true">
    <f:validator binding="#{bindings.Ccy.validator}"/>
</af:inputText>

<af:outputText value="#{bindings.CurrencyName.inputValue}" id="ot1"/>


Actually besides a symbolic code like USD and EUR a currency has a numeric code like 840 and 978. Sometimes a user prefers to input a symbolic code and sometimes a numeric one. Let's allow users to input whatever they want - either symbolic or numeric code, and we will take care of both and show correct currency description. We are going to add to the VO a transient updatable attribute with two LOVs. A user inputs a value of this attribute and depending on the value's type (string or numeric)  we'll use a corresponding LOV. The first LOV looks for the currency description by symbolic code and the second one by numeric code.

The LOV for the symbolic code (Ccy):



And the LOV for the numeric code (Nbuid):



In order to switch between LOVs we use additional transient attribute CcyLovSwitcher:



And the value of the CcyLovSwitcher is going to be some Groovy expression:


The expression adf.object.ccyLovName refers to the method of our custom ViewRowImpl  class:

public String getCcyLovName() {

  //Return a corresponding LOV's name
  //depending on the value's type - string or numeric

  String looukupValue = getCcyLookup();    
  if (isNumeric(looukupValue))
      return "LOV_CcyLookupByID";
  else
      return "LOV_CcyLookupByCcy";

}



//Check whether the value is numeric
private boolean isNumeric(String value) {
  return value.matches("\\d+");
}


And now our users are free to input either symbolic or numeric currency code:


That's it!




23 Jun 2012

Dependent LOV in a Search Form

Let's say we have a ViewObject with a LOV enabled attribute.

 The ViewAccessor's ViewObject has a bind variable.


In our use case we have a method in the ViewObjectImpl calculating value for this bind variable.

    public Integer getDealTypeID() {

        return someCalculatedValue;

    }


So, we can put a groovy expression "viewObject.dealTypeID" to the ViewAccessor's definition:


And it works fine everywhere except Search Form. If our LOV enabled attribute is used in a View Criteria and triggered from a Search form we will get something like this: JBO-25077: Name dealTypeID not found in the given object: oracle.adf.model.bean.DCDataVO. The object for the groovy script in case of a SearchForm is DCDataRow that is built internally by the af:query mechanism.
If we change the groovy expression to this "dataProvider.viewCriteria.viewObject.dealTypeID",
the Search Form will start to work, but the normal form will be broken. So, we have to understand somehow where the groovy expression is triggered from. The "adf.isCriteriaRow" expression can help us and our groovy script will look like this:

if (adf.isCriteriaRow)  
  return dataProvider.viewCriteria.viewObject.dealTypeID; 
else   
  return viewObject.dealTypeID;


This script will work in both cases!
But... That's all fine for R1 only . In R2 the expression "adf.isCriteriaRow" is not working in this case and the groovy script for R2 will look a bit ugly:


if (object.getClass().getName().endsWith('DCCriteriaValueRowImpl'))     
   return viewCriteria.viewObject.dealTypeID;  
else   
   return viewObject.dealTypeID;


That's it!.



2 Apr 2011

ADF Declarative Component example

In my previous post I promised to show  how to create ADF Declarative Component for Smart List Of Values. So, I'm going to create a component consisting of three elements: a label, an input text and a combobox list of values. That's very easy. I created a separate ADF ViewController project in my work space:




In this project open the Create JSF Declarative Component wizard:



The new declarative component smartLovDef should have at least three attributes: some string for label, attribute binding for input text and LOV binding for combobox list of values:


The wizard creates metadata file declarativecomp-metadata.xml and smartLovDef.jspx file where we can put the content of our component:


The source code of smartLovDef.jspx looks like this:
<?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:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <af:componentDef var="attrs" componentVar="component">
        
 <af:panelLabelAndMessage label="#{attrs.label}" id="plam1">
  <af:panelGroupLayout id="pgl1" layout="horizontal">
    <af:inputText value="#{attrs.attrBinding.inputValue}"
                  required="#{attrs.attrBinding.hints.mandatory}"
                  columns="#{attrs.attrBinding.hints.displayWidth}"
                  id="deptid" partialTriggers="departmentNameId"
                 autoSubmit="true" simple="true"/>
    <af:inputComboboxListOfValues id="departmentNameId"
                popupTitle="Search and Select: #{attrs.lovBinding.hints.label}"
                value="#{attrs.lovBinding.inputValue}"
                model="#{attrs.lovBinding.listOfValuesModel}"
                columns="#{attrs.lovBinding.hints.displayWidth}"
                shortDesc="#{attrs.lovBinding.hints.tooltip}"
                partialTriggers="deptid"
               simple="true">
    </af:inputComboboxListOfValues>
  </af:panelGroupLayout>
 </af:panelLabelAndMessage>

    <af:xmlContent>
      <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
        <display-name>smartLovDef</display-name>
        <attribute>
          <attribute-name>label</attribute-name>
          <attribute-class>java.lang.String</attribute-class>
          <required>true</required>
        </attribute>
        <attribute>
          <attribute-name>attrBinding</attribute-name>
          <attribute-class>java.lang.Object</attribute-class>
          <required>true</required>
        </attribute>
        <attribute>
          <attribute-name>lovBinding</attribute-name>
          <attribute-class>java.lang.Object</attribute-class>
          <required>true</required>
        </attribute>
        <component-extension>
          <component-tag-namespace>cscomponent</component-tag-namespace>
          <component-taglib-uri>/componentLib</component-taglib-uri>
        </component-extension>
      </component>
    </af:xmlContent>
  </af:componentDef>
</jsp:root>

The next step is to deploy the component into ADF Library. We have to add new deployment profile for the CSComponents project:




And let's deploy the project into library:



The following step is to define File System connection in the resource palette to the deployment path of CSComponents project:



After that we have to choose the project where we're going to use the new component (in my case ViewConroller) and add CSComponents.jar library to it:



Now we can use smartLovDef  component in our page and drag it from the component palette:



In our jspx page the source code is going to look like this:

    <cscompLib:smartLovDef label="#{bindings.DepartmentId.label}"
                        attrBinding="#{bindings.DepartmentId}" 
                        lovBinding="#{bindings.DepartmentName}"
                        id="sld1"/>

27 Mar 2011

Smart List of Values

We can use two wonderful components for working with the lists of values :  Input List Of Values and Input Combobox List of Values. But my users got used to too much comfort and they want to input department's ID manually in one field and see automatic reflection of the department's name in another field. And they want to choose the department's name from some list and to have reflection of its ID automatically.
In order to match this requirement I need to do some trick in my model. I've got EmployeesView VO with DepartmentID and DepartmentName fields. The trick is to create two LOV's on Departmentid and Departmentname as well. The LOV for Departmentid:

 Note, that DepartmentName field is also mapped. And the LOV for DepartmentID:


It uses the same viewaccessor and has mapping for DepartmentID as well.

On my page I'm going to put one InputText for DepartmentID and one ComboBox List of Values for DepartmentName. It's needed to link them with each other as partial targets and mark DepartmentID as an autosubmitted field. 
Both fields are put on a horizontal layout panel within Panel Label and Message:
<af:panelLabelAndMessage label="#{bindings.DepartmentId.label}" id="plam1">
  <af:panelGroupLayout id="pgl1" layout="horizontal">
    <af:inputText value="#{bindings.DepartmentId.inputValue}"
                  required="#{bindings.DepartmentId.hints.mandatory}"
                  columns="#{bindings.DepartmentId.hints.displayWidth}"
                  id="deptid" partialTriggers="departmentNameId"
                  autoSubmit="true" simple="true"/>
    <af:inputComboboxListOfValues id="departmentNameId"
          popupTitle="Search and Select: #{bindings.DepartmentName.hints.label}"
          value="#{bindings.DepartmentName.inputValue}"
          model="#{bindings.DepartmentName.listOfValuesModel}"
          required="#{bindings.DepartmentName.hints.mandatory}"
          columns="#{bindings.DepartmentName.hints.displayWidth}"
          shortDesc="#{bindings.DepartmentName.hints.tooltip}"
          partialTriggers="deptid"
          simple="true">
      <f:validator binding="#{bindings.DepartmentName.validator}"/>
    </af:inputComboboxListOfValues>
  </af:panelGroupLayout>
</af:panelLabelAndMessage>


The working page looks like this:


In my next post I'm going to show how to create ADF declarative component in order to use this approach in your application as a standard one.

20 Feb 2011

ADF BC. Multiple LOVs for VO's attribute.

Everybody knows how to define LOV for view object's attribute. But what if depending on application's logic it's needed to get values for LOV from different sources or with completely different conditions. For suer, it's possible to define complex SQL query for LOV's VO and play with it's parameters. But most likely we'll get performance issue using this approach. And what we should do if it's required to use different display values for different use cases?

ADF BC allows us to define more than one LOV per attribute.
Let's say I have VO representing some form to input address information. It has attribute for country and attribute for region or state. If country is USA, user should select one of the US states, if country is India, user should select Indian state, in other cases user doesn't need any LOV and should input region manually.

I defined two LOVs for Regionstate attribute. Each of them retrieves values from its own data source  (US states and Indian states). In order to switch LOVs I defined new transient attribute StateLovSwitcher. The value of this attribute should contain proper LOV's name.



StateLovSwitcher's value is Groovy expression derived and defined as:


I'm going to provide user by two input controls for Regionstate field. For US and India user needs SelectOneChoice in other cases he needs InputText. I'm using af:switcher showing SelectOneChoice if  StateLovSwitcher has value and InputText if it doesn't.

  
    
      ...
    
  
    
        ...
    



And finally in order to get it working fine we need to clean region's value if country changes.

public void countryListener(ValueChangeEvent valueChangeEvent) {
   if (valueChangeEvent.getOldValue()!=valueChangeEvent.getNewValue())
          regionLOV.setValue(null);  
 }

You can download Jdev11.1.1.2.0 sample application for this post.