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!

6 comments:

  1. how does applyCriteria method get invoked from the page? I want to dynamically apply a view criteria and query too. So I am trying to understand how to invoke these methods.

    ReplyDelete
  2. You can invoke it wherever you need. For example in some action listener:
    //Selecting criteria with specified name
    private void selectAndApplyCriteria(String criteria) {
    QueryModel model = queryPnl.getModel();

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

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

    //Apply criteria
    applyCriteria(qd);
    }

    //Action listener for some button
    public void someButtonAction(ActionEvent actionEvent) {
    selectAndApplyCriteria("SalaryCriteria");
    }

    ReplyDelete
  3. Hi.

    Nice post.

    I have written an article speaking about this, with another style.

    I also explain how to apply two or more view criterias programmatically.

    Check it if you want.

    Regards

    ReplyDelete
    Replies
    1. Hi Juan!

      Sure, I will check your article with pleasure.

      Delete
  4. Hi Eugene,

    Maybe I missed something crucial, but in the second example - how and where do you set the salary value? I want to do something very similar after closing a popup, but I don't know whether it's the QueryDescriptor I need to populate or the QueryModel.

    Or is it possible for me to call my equivalent of your simple applySalaryCriteria method on the popup closing? I'm already using popup and dialog listener methods but I wasn't aware you could call ViewImpl class methods directly from managed beans.

    Can you please advise me?

    Many thanks,
    Darren

    ReplyDelete
    Replies
    1. Hi Darren,
      In the second example I have a query panel (queryPnl) with an input for salary value. And when I am invoking the applyCriteria method, the query panel takes care of the inputted salary value and passes it to the qury model.
      For sure, you can use applySalaryCriteria method, but don't invoke it directly from your managed bean, use method action in the binding container.

      Delete

Post Comment