Showing posts with label JSF. Show all posts
Showing posts with label JSF. Show all posts

Friday, 18 July 2008

Oracle ADF/ JSF: Mind your flags!

I do not know why JSF UI elements have a Disabled property. I mean I would prefer it if they instead offered an Enabled one. ADF bindings on the other hand have enabled properties, so UI tags usually look this :

<af:commandButton actionListener="#{bindings.Create.execute}"
                     text="#{res['commands.create']}"
                     disabled="#{!bindings.Create.enabled}"
                     action="addEdit"/>

How imagine having to wire in the UserInfo bean, I was talking about the other day. Ideally you would like to have the above Create button enabled when your user is an administrator i.e. #{UserInfo.admin == true} and when the Create binding is enabled, meaning #{bindings.Create.enabled == true}.

Since we now have a Disabled property, this means that the value assigned should be the opposite of #{UserInfo.admin == true && bindings.Create.enabled == true}. The EL expression for this is #{!(UserInfo.admin == true && bindings.Create.enabled == true)}. Using De Morgan's low we end up with #{!UserInfo.admin || !bindings.Create.enabled}.

I understand that for most people this is more than trivial, but I have to admit that is took me a good while to figure it out. (Does age come at a price or what?) I want to learn by my own mistakes. Therefore I thought I 'd put it down in witting, so I won't run into this again.

Thursday, 20 March 2008

Oracle ADF Two action listeners in one action

Some time ago, I run into a situation when I wanted to add two action listeners inside a single command element but I realized that this was just not possible. When I asked about that in the JDeveloper forums somebody told me that this could only be accomplished in code, but at that time my knowledge was just not enough

A couple of days ago I run into the same problem. I had a view page that when accessed wanted to know two things:

  • First was the ${row.rowKeyStr} of the row to display and ...
  • Next a session scope boolean parameter called #{sessionScope.returnHome} that indicated whether to return the user to the application home page or to another (the search in that case) page.

To summarize, I ended up with the a button called View record in two different pages both having a navigation case (also called view) linking to the view record page. in the application JSF diagram.

On both cases the expression #{row.rowKeyStr} had to be recorded in the JSF session scope along with a value for the returnHome flag that had to be true on one occasion and false on the other..

Following is the code I used to perform this. First the base class :

package myapp.view.backing;

import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

class backing_SRListBase {

    public backing_SRListBase()
    {
    }
    
    public String viewButtonBase_action( boolean returnHome)
    {
        // access the faces context
        FacesContext fc = FacesContext.getCurrentInstance();
        Application app = fc.getApplication();
        
        // on both case row.rowKeyStr points to the current row key
        ValueBinding vbActRowKey = app.createValueBinding("#{row.rowKeyStr}");
        String rowKey = (String )vbActRowKey.getValue(fc);
                
        // in that case we must save that in sessionScope
        ValueBinding vbSessionScopeRowKey = app.createValueBinding("#{sessionScope.rowKey}");
        vbSessionScopeRowKey.setValue( fc, rowKey);
                
        // also save the return home boolean value
        ValueBinding vbReturnHome = app.createValueBinding("#{sessionScope.returnHome}");
        vbReturnHome.setValue( fc, new Boolean( returnHome));
        
        return "view";
    }
}

Finally, the backing bean for each of the two pages looks like this

package myapp.view.backing;

public class backing_OpenSRList 
    extends backing_SRListBase {

    public backing_OpenSRList()
    {
    }

    public String viewButton_action()
    {
        return viewButtonBase_action( false);
    }
}

Thursday, 29 November 2007

ADF-BC/JSF Performing case insensitive searches

I have been asked to implement a service request system that will allow a company to record service requests from customer via a telephone line. The difference with oracle's SRDemo application is that in my case SR's will be entered by telephone operators and be assigned to departments and not to technicians

Anyway the application still offers a SRSearch page that allows telephone operators and managers to filter the service request list and here is where my problem started since they asked me if the QBE system would match parts of the requester first or last name case insensitively.My first reaction was to tell them to enter everything in capital letters, but then I though I might give it a try and ended up like this

first I added two additional fields in my query named SearchFirstName and SearchLastName defined like this

  SELECT 
       .....
       ServiceRequest.REQUESTER_FIRST_NAME, 
       UPPER( REQUESTER_FIRST_NAME) AS SEARCH_FIRST_NAME, 
       ServiceRequest.REQUESTER_LAST_NAME, 
       UPPER( REQUESTER_LAST_NAME) AS SEARCH_LAST_NAME, 
       ......

then changed I used JavaScript in the SRSearch page to make sure that whatever the user enters in the SearchFierstName and SearchLastName fields is converted to upper case before posting.

The javascript file itself is as simple as this

/* ---------------------------------------------------------------------------
 * file SRSearchSubmit.js
 * contains code that allows to submit the SRSearch form with the first name
 * and last name fields converted to upercase.
 *
 * Date 03-12-2007
 * ---------------------------------------------------------------------------
 */
 function convert()
 {
    var firstName = document.forms["myADFForm"].elements["myADFForm:searchFirstNameField"].value;
    var lastName =  document.forms["myADFForm"].elements["myADFForm:searchLastNameField"].value;

    document.forms["myADFForm"].elements["myADFForm:searchFirstNameField"].value
      = firstName.toUpperCase();
    document.forms["myADFForm"].elements["myADFForm:searchLastNameField"].value
      = lastName.toUpperCase();

    return true;
 }

No the two final points. First we need to include the javascript file at the top of the page inside a <f:verbatim> tag. Next in order to get the names of the elements right, we need to set the id attribute of both the <h:form> and the <af:inputText> elements.

The page header part of the resulting JSF page looks like this

    <afh:html>
      <f:loadBundle basename="SRKomo" var="res"/>
      <afh:head title="#{res['application.title']}">        
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <link href="../css/oracle.css" rel="stylesheet" media="screen"/>
        <f:verbatim>
          <script src="../javascript/SRSearchSumbit.js" type="text/javascript"></script>
        </f:verbatim>
      </afh:head>
      <afh:body>
        <af:messages/>
        <h:form id="myADFForm" onsubmit="convert();">
        ...

And the definitions for the each of th two search fields like this

              <af:panelLabelAndMessage label="#{bindings.AllRequestsListSearchFirstName.label}">
                <af:inputText value="#{bindings.AllRequestsListSearchFirstName.inputValue}"
                              simple="true"
                              required="#{bindings.AllRequestsListSearchFirstName.mandatory}"
                              columns="#{bindings.AllRequestsListSearchFirstName.displayWidth}"
                              styleClass="searchTextField"
                              id="searchFirstNameField">
                  <af:validator binding="#{bindings.AllRequestsListSearchFirstName.validator}"/>
                </af:inputText>
              </af:panelLabelAndMessage>

and that did it.

Notes

  • The original info about how to place javascript into a JSF document comes from the Frank Nimphius' Blogbuster article ADF Faces: Submit a form with the Enter key.
  • I have found it very easy to understand the HTML produced by the Oracle JSF engine using Firebug. Especially the "Inspect element" function will locate the HTML code of each eleent you click on and that can save you an awfull lot of decoding trouble.

Friday, 9 November 2007

ADF/JSF Getting the current row with code executed from a table bucking bean

The following code comes from the JDeveloper Forums courtesy of Frank Nimphus. If added to any event listener fired from "inside" an ADF Table, it prints the row's 1'st attribute and the rowKey.

        FacesContext fctx = FacesContext.getCurrentInstance();
        ValueBinding vb = (ValueBinding) fctx.getApplication().createValueBinding("#{row}");
        JUCtrlValueBindingRef rwbinding = (JUCtrlValueBindingRef) vb.getValue(fctx);
        System.out.println("--- Key as String --"+rwbinding.getRow().getKey().toStringFormat(true));
        System.out.println("--- First Attribute ---"+rwbinding.getRow().getAttribute(1));

Thanks again Frank

ADF/JSF Avoiding uncought exeptions after commit.

When using Oracle JDeveloper 10.1.3.x, you can find it very tempting to create "Create/Edit Record" pages by dropping an ADF Form on a blank JSF page and then adding commit and rollback buttons in the place of the ok and cancel buttons with an action property that returns your users to the browse page.

So let's assume that your faces-config file contains a navigation case labeled "return", that leads from you edit page back to your browse page. In cases like these, the code for the commit button will more or less look like this

                      <af:commandButton 
                                     actionListener="#{bindings.Commit.execute}"
                                     text="Ok" 
                                     action="return"
                                     id="commitButton"
                                     disabled="false"/>

This approach, presents a very serious hazard, which is a bug in Oracle's JSF implementation. If any exception is thrown after commit, the framework moves to the page designated by the navigation case and the error messages are not being displayed at all.

To make matters worse, you end up with on open transaction and nothing else entered in this manner ever gets stored in your database while you users have no way to realize that something has gone wrong. I had raised an SR for this that ended up in a one off patch (5630740) for JDeveloper 10.1.3.2.

I run into this problem again in am application that I developed recently using JDeveloper 10.1.3.3. And then it hit me. The solution was as simple as the Egg of Columbus. The only thing that needs to be done is to bind the commit button action in a backing bean. JDeveloper will then change the button tag into something like :

                      <af:commandButton 
                                    text="Accept"
                                    id="commitButton"
                                    disabled="false"
                                    action="#{backing_Edit.commitButton_action}"/>

... create the following code :

    public String commitButton_action()
    {
        BindingContainer bindings = getBindings();
        OperationBinding operationBinding =
            bindings.getOperationBinding("Commit");
        Object result = operationBinding.execute();
        if (!operationBinding.getErrors().isEmpty()) {
            return null;
        }
        return "return";
    }

... and that does it. Commit exception messages are displayed correctly and everyone is happy.

In case you have many edit pages with different navigation case labels then you might wish to create a solution that is a little more sophisticated and closer to the OO paradigm. In a case like this I suggest that you create a base class to be the parent of all your page backing beans and add the following method.

public class MyBackingBase
{
    protected String executeCommit( BindingContainer bindings, String successValue)
    {
        OperationBinding commitBinding =
            bindings.getOperationBinding("Commit");
        
        commitBinding.execute();
                
        return commitBinding.getErrors().isEmpty() ? successValue : null;
    }
 }

Having done that the actual backing bean code could be something as simple as

    public String commitButton_action()
    {
        return executeCommit( getBindings(), "return");
    }

... and one more thing. The Copy as HTML function is not available again. I guess I 'll have to start looking why .. :-(

Wednesday, 7 November 2007

JSF Passing parameters to included jsp pages

The question was brought up in the JDeveloper forum. When I started creating my first JSF pages I wanted to be able to create a menu that I could edit and make make the changes propagate to all pages immediately. So What I wanted back then was amethod to include a jsp to all my pages but also be able to pass parameters from the including page to the one being included.

The answer came from the book Mastering JavaServer Faces by Bill Dudney, Jonathan Lehr, Bill Willis and LeRoy Mattingly.

The approach is to create a subview and then include the page using a jsp:include tag. Inside the include you must use a jsp:param tag where you define the name and value of the expected JSP parameter. To cut the long story short, I tested the solution with JDeveloper 10.1.3.3 and here is the code fragment to use.

            <f:subview id="header">
                <jsp:include page="/header.jsp" flush="true">
                    <jsp:param name="pageTitle" value="Welcome to my first JSF Application"/>
                </jsp:include>
            </f:subview>
 

The included page should be surrounded by an f:subview tag. The external parameter can be accessed by an EL expression like "#{param.paramName}" and a simple example would be something like :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=ISO-8859-7"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces" prefix="af"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces/html" prefix="afh"%>
<f:subview id="header">
  <afh:html>
    <afh:head>
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-7"/>
    </afh:head>
    <afh:body>
      <af:panelHeader text="#{param.pageTitle}"/>      
    </afh:body>
  </afh:html>
</f:subview>

... and one last comment. I guess that this is the first time that the Copy as HTML command works correctly in JDeveloper on Linux. :-)

Wednesday, 17 October 2007

JSF How to create and use dependent list boxes

Back in 2006, Frank Nimphius has written two excellent articles about using AJAX style combo (or list) boxes in a web page that filter one another based on values of a master detail relationship. I have to admit that thanks to him, my users have one less reason to grumble :-)

The first one is entitled ADF Faces: How-to build dependent lists boxes with ADF and ADF Faces and the second one ADF Faces: How-to build dependent lists boxes with ADF and ADF Faces Part - II

Thank you Frank.

Thursday, 27 September 2007

ADF Tables. Changing the colour of negative valued columns

My users asked me if it would be possible to display negative values of an ADF table using a different colour than the rest.

The solution turned out to be something as simple as defining two CSS classes like this :

.redFont {
    color: Red;
}
.blueFont {
    color: Navy;
}

The last step was to bind the StyleClass property of the adf:outputText elements using the following EL expression :

#{row.myColumn.value > 0 ? 'blueFont' : 'redFont'}

Thursday, 30 August 2007

JSF Basics Access the HTTP Session from a backing bean

Here is something I always seem to forget and never realy got to use :-)
Code to gain access to the HTTP session from a inside backing bean :

FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)fc.getExternalContext().getRequest();
HttpSession session = request.getSession();

Wednesday, 27 June 2007

JSF Basics Getting the value of an EL expression in code

You can use the following code to get the value of any EL expression defined inside your JSF page For example the following checks the value of the expression #{requestScope.requestRowKey}

        // access the faces context
        FacesContext fc = FacesContext.getCurrentInstance();

        ValueBinding vb = fc.getApplication().createValueBinding("#{requestScope.requestRowKey}");
        String rowKey = (String )vb.getValue(fc);

Assigning a new value can be preformed by using vb.setValue( Object o)