Please disable your adblock and script blockers to view this page

Search this blog

Showing posts with label validation. Show all posts
Showing posts with label validation. Show all posts

Tuesday 17 January 2017

ADF Basics: Duplicate Record Validation Using Custom Java Method


Hello All

Recently I have posted about duplicate record validation using model level business rules (Unique Key Validation) but sometimes we need to check some more conditions or we have some other logic that should be checked before validating the input then in that case we can write custom java method in model (Application Module Impl class) and call it in bean validator using binding layer

Tuesday 1 September 2015

Apply Validator to programmatically created ADF Faces components

Again a post in series of  Working with ADF Faces Components programmatically
Previously i have posted about Getting value , Applying Action Listener , Applying Client/Server Listener, Creating and applying client Attributes, Setting value expression  to programmatically created component
Now this post post is about applying Validator to a component that is created at run time
See how to do this (Jdev 12.1.3)-
  • First created a FusionWebApplication and a page in viewController project
  • Dropped a button on page , on this button action i will create an inputText programmatically and assign validator method reference to it
  • To create new inputText i have added following code (described in previous post)

Wednesday 10 September 2014

Dynamic (parameterize) model level validation using message token -Oracle ADF

Hello all
This post falls under ADF Basics category (about a little trick in model layer) but about a common development requirement
How can we create dynamic ADF BC validation ? means it takes a parameter at run time and append it to validation message

Read previous post on model level validation-
Conditional Execution of Model (EO) level Validation- Oracle ADF
ViewObject Validation rules for transient attributes (Model level validation in ADF)

In this post I am using Departments table of oracle HR Schema



  • First step is same , prepare model (EO,VO and AM) using Departments table



  • Creating a business rule that DepartmentName can not be duplicate, for this created a alternate key in EntityObject 



  • Nnow creating unique key business rule for this alternate key and message that appears on validation failure (this is how we apply EO level validations)




  • Run AM and check in BC4J tester, create a new row and on entering duplicate DepartmentName this validation message appears -"Duplicate Department Name"


  • now my requirement is this message should be like - Duplicate Department Name <Administration> , so for this i have to pass parameter in message that shows entered DepartmentName on run-time. ADF provides built in feature to pass tokens in message and on run time it is replace with groovy expression value

  •  On running see desired output



  • to pass more than one parameter just add another token and set groovy for it, see the screens
 Output-


Thanks - Happy Learning :)

Sunday 7 September 2014

Show message (Invoke FacesMessage) using JavaScript in ADF Faces

Hello all
This post is about use of JavaScript in ADF Faces to show a simple message notification , it may be error/warning/information/critical error message
so this is simple, as we have to just invoke default FacesMessage using JavaScript

So for this i have used an af:inputText on page and use case is that this field should only take characters


How to validate characters (alphabet) only  using javascript ?





So for this i have taken a simple regular expression that check that entered value is alphabetic or not
see this JavaScript function that is added to page, here it1 is the id of inputText for that FacesMessage is invoked, i am using Jspx page so i use actual id of component, if you try this in region,dynamic region or inside pageTemplate then check and change the id of component .
It will be something like r1:0:it1 or pt1:0:it1, because that is nested page structure.
you can get this id using componentBinding.getClientId();


 <af:resource type="javascript">
              function validateStringOnKeyPress(event) {
                  //Regular Expression to validate String
                  var letters = /^[A-Za-z]+$/;
                  //Get value of input text
                  var charCode = event.getSource().getSubmittedValue();

                  if (charCode != '') {
                      if (charCode.match(letters)) {
                          // IF matches then no problem
                      }
                      else {
                          //Invoke FacesMessage
                          AdfPage.PAGE.addMessage('it1', new AdfFacesMessage(AdfFacesMessage.TYPE_ERROR, "Invalid Value", "Enter Characters Only"));
                          AdfPage.PAGE.showMessages('it1');
                          event.cancel();
                      }
                  }
              }
            </af:resource>


Added a clientListener to inputText that executes this JavaScript function on keyPress event





Run page and see how it works-
Here you see that 2 is not a character so it showing error message as FacesMessage is defined for TYPE_ERROR




So it's done but now problem is - when user input a wrong value a error message is displayed and after this validation alert if user keeps entering wrong values then every time a new FacesMessage is created and added to page, It appears on page like this (duplicate messages - really weird)


To remove additional messages , i have added one more line in JavaScript to clear previous validation message

JavaScript to clear validation message-


 // Clear all validation message 
              AdfPage.PAGE.clearAllMessages();

now JavaScript function is like this


function validateStringOnKeyPress(event) {
                  //Regular Expression to validate String
                  var letters = /^[A-Za-z]+$/;
                  //Get value of input text
                  var charCode = event.getSource().getSubmittedValue();
                  // Clear all validation message 
                  AdfPage.PAGE.clearAllMessages();
                  if (charCode != '') {
                      if (charCode.match(letters)) {
                          // IF matches then no problme
                      }
                      else {
                          //Invoke FacesMessage
                          AdfPage.PAGE.addMessage('it1', new AdfFacesMessage(AdfFacesMessage.TYPE_ERROR, "Invalid Value", "Enter Characters Only"));
                          AdfPage.PAGE.showMessages('it1');
                          event.cancel();
                      }
                  }
              }

and yes you can change type of message, use TYPE_ERROR, TYPE_INFO, TYPE_WARNING, TYPE_FATAL to change message type

see different output-
Warning Message (TYPE_WARNING)-

Informational Message (TYPE_INFO)-

Fatal Error Message (TYPE_FATAL)-


Thanks Happy Learning :)

Tuesday 20 May 2014

Blocking row navigation in af:table , synchronize row selection with model in case of validation failure- Oracle ADF

In ADF we often work on editable af:table and when we use af:table to insert ,update or delete data, it is normal to use some validation
but problem is when some validation failure occurs on page (in af:table) ,still we can select another row and it shows as currently selected Row
this is a bit confusing for user as Row Selection of af:table is not synchronized with model or binding layer

See Problem- 
  • I have an editable table on page


  • Added a validation to check negative value in field of LocationId, now navigate to another row


  • See selected focus is on Academic, but problem is when there is validation failure, why it is showing other row as selected ? 



  • If you check in ViewObject , you will find that row with DepartmentName Human Resource is current row

ADF framework provides a property in af:table to control navigation in af:table when there is some error or validation failure- blockRowNavigationOnError
See in oracle docs about this proprty-

Valid Values: always, never, auto


Whether we want to block row navigation in case of validation failure.
This is when you select a row and do some editing inside the table or in a related form, and this editing causes some validation failures. At this time, if you click on a different row in table, we want to block you from moving to the new row.
possible values are: always, never and auto. default value is auto.

  • always means we block the row navigation
  • never means we don't block and let the row navigation happen
  • auto means the framework will make the decision



by default in af:tabel it's value is <auto>


Change it to <always> and now see behavior on page


 now if you try to select another row, it is not get selected and selected focus is on row with validation

Sample ADF Application-Download
Cheers - Happy Learning :-)

Thursday 17 April 2014

ViewObject Validation rules for transient attributes (Model level validation in ADF)

Hello All,
this post is about model level validation for transient attributes, often we need to apply some common types of validation on transient attributes (as for negative value, for email, for phone number)
in ADF ViewObject there is a editor for validation rules for transient attributes, so now see how to use that editor and rules


  • Create a fusion web application and prepare model layer using Departments table of HR schema


  • Then create a transient attribute in viewObject and you can see that Validation Rules tab appears only in case of transient attribute



  • Now click on add icon to add new validation rule for attribute, you can see there are multiple types for that validation rule 





  • In this post i have used Compare and Regular Expression rules, suppose i have to check that value of transient attribute must not be 100 , so for that rule will be like this, and write a proper message for failure handling 



  • Now run your BC4J tester and check , a window with error message appears there in case of failure


  • You can also check this validation on your page, some more- i have added one more transient field for Email Address and applied a regular expression to validate this field (ADF by default provides regular expression for Email and Phone Number pattern for others you can use your own pattern)


  • After model level configurations , i have dropped Departments ViewObject on page as ADF form, here you can see both validation are working 




Cheers :-) Happy Learning

Friday 27 December 2013

Overriding default query listener ,field validation of af:query- Oracle ADF


Hello All,
this post talks about a common requirement - can we apply custom validation in af:query fields ? yes , we can do that by overriding default query listener of af:query component

What af:query is ?

see- Oracle Docs-af:query
"The query component provides the user the ability to perform a query based on a saved search or personalize saved searches. The component displays a search panel with various elements, each of which help the user to accomplish various tasks."


Follow steps to apply validation on af:query-
  • Here i am taking example of Departments table of HR Schema
  • First create business components for Departments table


  • then create  bind variables and a view-criteria in departments view object



  • See the view criteria is applied for LocationId, ManagerId and Department Name
  • Now create a page and drop criteria with table on page- it will look like this

  • Next is to select af:query on page and go to property inspector and copy text of default query listener



  • Now create a managed bean and create a custom query listener for af:query

     
  • In this custom query listener , in this example i am checking for negative Location Id and Manager Id, if there is any negative values ,custom method will show a message otherwise default queryListener will be executed
  • We can get af:query's components value using 2 methods
    First One  - Using Bind Variable (getNamedWhereClauseParam)
    Second One - Using QueryDescriptor and ConjunctionCriterion
  • I'm going to explain both methods - see code of custom query listener using first method, two generic methods will be used in this process to invoke expression language and to get BindingContainer of current context

  •     /**Method to invoke EL Expression
         * @param el
         * @param paramTypes
         * @param params
         * @return
         */
        public static Object invokeEL(String el, Class[] paramTypes, Object[] params) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            ELContext elContext = facesContext.getELContext();
            ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
            MethodExpression exp = expressionFactory.createMethodExpression(elContext, el, Object.class, paramTypes);
    
            return exp.invoke(elContext, params);
        }
    
        /**Method to get Binding Container of current page
         * @return
         */
        public BindingContainer getBindings() {
            return BindingContext.getCurrent().getCurrentBindingsEntry();
        }
    

  • See the first method to get af:query components value and validate that

  •     /**Custome Query Listener- Using getNamedWhereClauseParam
         * @param queryEvent
         */
        public void customQueryListener(QueryEvent queryEvent) {
            String deptName = null;
            Integer locId = null;
            Integer mgrId = null;
    
            /**Get Iterator of Table*/
            DCIteratorBinding iter = (DCIteratorBinding)getBindings().get("DepartmentsView1Iterator");
    
            /**Get ViewObject from Iterator*/
            ViewObjectImpl vo = (ViewObjectImpl)iter.getViewObject();
    
            /**Get Bind Variable's Value*/
            if (vo.getNamedWhereClauseParam("LocIdBind") != null) {
                locId = Integer.parseInt(vo.getNamedWhereClauseParam("LocIdBind").toString());
            }
            if (vo.getNamedWhereClauseParam("MgrIdBind") != null) {
                mgrId = Integer.parseInt(vo.getNamedWhereClauseParam("MgrIdBind").toString());
            }
            if (vo.getNamedWhereClauseParam("DeptNmBind") != null) {
                deptName = vo.getNamedWhereClauseParam("DeptNmBind").toString();
            }
    
            /**Check for Negative values*/
            if ((locId != null && locId < 0) || (mgrId != null && mgrId < 0)) {
                FacesMessage msg = new FacesMessage("Id Value can not be negative");
                msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                FacesContext.getCurrentInstance().addMessage(null, msg);
            } else {
                /**Execute default query listener with help of invokeEL method*/
    
                invokeEL("#{bindings.DepartmentsViewCriteriaQuery.processQuery}", new Class[] { QueryEvent.class },
                         new Object[] { queryEvent });
            }
        }
    

  • And Second Method using QueryDescriptor is-

  •     /**Custom Query Listener-Using QueryDescriptor
         * @param queryEvent
         */
        public void customqueryProcess(QueryEvent queryEvent) {
            String deptName = null;
            Integer locId = null;
            Integer mgrId = null;
    
            /**Reference-Frank Nimphius Example- ADF Code Corner
           * http://www.oracle.com/technetwork/developer-tools/adf/learnmore/85-querycomponent-fieldvalidation-427197.pdf
           * */
            QueryDescriptor qd = queryEvent.getDescriptor();
    
            ConjunctionCriterion conCrit = qd.getConjunctionCriterion();
            //access the list of search fields
            List<Criterion> criterionList = conCrit.getCriterionList();
            //iterate over the attributes to find FromDate and ToDate
            for (Criterion criterion : criterionList) {
                AttributeDescriptor attrDescriptor = ((AttributeCriterion)criterion).getAttribute();
    
                if (attrDescriptor.getName().equalsIgnoreCase("DepartmentName")) {
                    deptName = (String)((AttributeCriterion)criterion).getValues().get(0);
    
                } else {
                    if (attrDescriptor.getName().equalsIgnoreCase("LocationId")) {
                        locId = (Integer)((AttributeCriterion)criterion).getValues().get(0);
    
                    }
                }
                if (attrDescriptor.getName().equalsIgnoreCase("ManagerId")) {
                    mgrId = (Integer)((AttributeCriterion)criterion).getValues().get(0);
    
                }
            }
            if ((locId != null && locId < 0) || (mgrId != null && mgrId < 0)) {
                FacesMessage msg = new FacesMessage("Id Value can not be negative");
                msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                FacesContext.getCurrentInstance().addMessage(null, msg);
            } else {
                /**Process default query listener*/
                invokeEL("#{bindings.DepartmentsViewCriteriaQuery.processQuery}", new Class[] { QueryEvent.class },
                         new Object[] { queryEvent });
            }
    
        }
    

  • Now Run your application and check it for negative values

Cheers- Download Sample App Happy Learning :-)


Friday 23 August 2013

Validation Problem with Cascading mandatory fields in ADF Faces

It is a functional requirement , suppose in application one fields is dependent on another field for its value or any property (required,disable,visible), it means when you select first field and put value in that then second field's value or other property is populated.
or second one is, you have multiple required attributes (cascading) in page and any of that's AutoSubmit  is set to true, in this case when user puts value in first field and goes to second to enter value but before this a large message window appears with required validation and all fields get red




This is very much annoying for user to face this kind of message each time, as i had a scenario where there was 15 required fields in af:form on popup and 10 of that are set to AutoSubmit true .
to avoid this see steps

  • Suppose i have page with create button for Departments table (default HR Schema) on pop up as a form and all fields are reuired
  •  When user clicks on create button and put value in field of DepartmentId, all required fields throw exception

  • To avoid this i have set immediate true for first required field that is DepartmentName, it means when any validation occurs on popup , DepartmentName field will skip all validation on page and will shows only of its own
  •  Now when user put value in DepartmentId field, only DepartmentName field shows exception (required)
 Happy coding......!!

Monday 1 July 2013

Update Model Values while Validation (Exception) occurs on page on Value Change event- Oracle ADF (processUpdates)

In ADF when we have some validation on page and we try to submit any value, but normally after validation (Exception) values are not updated in Model until exception is handled.
This tutorial is about how to update values in Model while exception on page.
For a scenario, i have used department (default HR Schema) table and form in a JSP XML fragment inside bounded taskflow.
In form Department Id and Department Name is mandatory field, ManagerId and Location Id has auto submit true.
  • I have dropped createInsert,Execute,Commit and Rollback as buttons on page




  • Click on create button and first enter manager id, as this field has autosubmit true so on submission of value page is validated and then Required Fields throw exception, and after exception you can see that manager id & location id is not updated in Model, and not reflected in af:table also.


  •  Normally what we do, set immediate true to skip validations, but in this case i have witten ValueChangeListener on manager Id and Location Id to process values in Model.- see code

  •     public void mangrIdVCE(ValueChangeEvent vce) {
            vce.getComponent().processUpdates(FacesContext.getCurrentInstance());
        }
    

  • processUpdates() method of UIComponent class perform the coponent tree processing for all facet of this component by Update Model Values phase of request processing, and pushes data to Model

  • Now after calling this method, run application- Now values are populated in af:table and validation is still there on page


  • this approach can be used while using validators on page and want to process some values after validation (as conditional validation of some fields etc)
  • Download sample application -Sample App