21 Aug 2011

How to apply View Criteria programmatically

Sometimes it could be handy to apply view criteria dynamically at run time.  Let's say I have a simple VO EmployeesView representing data from Emloyees table in HR schema. The VO has view criteria SalaryCriteria:


The criteria filters records with some salary value using bind variable "salary".  On my jspx page I have a table , inputText for salary value and a button:



By default the VO doesn't have any view criteria applied, but when the button is pressed, SallaryCriteria is to be applied with submitted value for salary bind variable. The button's action listener actually calls very simple method in EmployeesViewImpl class:

    public void applySalaryCriteria(Number salary) {
      setsalary(salary);
      setApplyViewCriteriaName("SalaryCriteria");
      executeQuery();
    }


In this use-case I don't have any af:query component on my jspx page and all the job of applying view criteria is going to be done in the model layer.
But there is another use-case when I have af:query on a page and I need to change selected criteria in af:query's component programmatically at run time. In my managed bean I have the following piece of code:

    private RichQuery queryPnl; //Bounded af:query

    //Looking for query descriptor in a list with specified query name
    private QueryDescriptor getQueryDescriptor(List<QueryDescriptor> list, String queryname) {
        QueryDescriptor result = null;
        for (Object qd: list.toArray()) 
            if (((QueryDescriptor) qd).getName().equals(queryname)) result = (QueryDescriptor) qd;
        return result;           
    }
    
    //Selecting criteria with specified name
    private void  selectCriteria(String criteria) {
        QueryModel model = queryPnl.getModel();

        //Looking for needed query decriptor  
        QueryDescriptor qd = getQueryDescriptor(model.getSystemQueries(),criteria);

        //Setting needed query descriptor as current one
        queryPnl.setValue(qd);        
        model.setCurrentDescriptor(qd);
    }


So, when I need to change selected criteria I call selectCriteria method  with specified criteria name. And if I need to apply the criteria and execute the query I call applyCriteria method:

    private void applyCriteria(QueryDescriptor qd) {       
        //Creating new QueryEvent
        QueryEvent queryevent = new QueryEvent(queryPnl, qd);
        
        //And processing this event
        //EmpCriteriaQuery is ID attribute of the searchRegion tag in the pageDef
        invokeMethodExpression("#{bindings.EmpCriteriaQuery.processQuery}",
            Object.class, new Class[]{QueryEvent.class}, new Object[]{queryevent});
    }
    
    //Just utility method to invoke EL expressions 
    public Object invokeMethodExpression(String expr, Class returnType, Class[]  argClasses, Object[] arguments){   
      FacesContext fc = FacesContext.getCurrentInstance(); 
      ELContext elc = fc.getELContext();
      ExpressionFactory exprFactory = fc.getApplication().getExpressionFactory(); 
      MethodExpression methodExpr = exprFactory.createMethodExpression(elc,expr,returnType,argClasses);    
      return methodExpr.invoke(elc,arguments); 
     }

That's all!

7 Aug 2011

Panel Form Layout and Labels with Icons

We often use panelFormLayout component as a standard approach to align our input controls and their labels on our pages. According to the documentation the component usually contains ADF Faces input components whose names start with 'input' (like inputText and inputDate) and components that start with 'select' (like selectOneChoice, selectBooleanRadio, and selectManyChoice).  When more complex field content is needed, we should use a panelLabelAndMessage around the content. In such case panelFormLayout draws the label on the left side and all the content of the panelLabelAndMessage on the right side. Sometimes we need to have an icon rendered before the label. There are two predefined icons we can get rendered before the label using  panelLabelAndMessage  and its attributes showRequired and changed.
So, in case of showRequired=true  it looks like this:


And in case of changed="true" it looks like this:

 
But when we need our custom icon to be rendered, we use  panelLabelAndMessage's attribute labelStyle. The attribute is used to provide a custom CSS style for the "label" part of the panelLabelAndMessage component. So, in order to get our custom icon rendered we will use the following piece of code:

<af:panelLabelAndMessage label="Label With Icon" id="plam1"
   labelStyle="background: transparent url(UA.png) no-repeat center left;
               padding: 3px 0 1px 18px;">
   <af:inputText id="it2" simple="true"/>
 </af:panelLabelAndMessage>

And it looks like this: