Sunday, May 22, 2016

Responsive design in Oracle ADF


Nowadays the need to create a web application based on a responsive design is becoming very common. ADF in its latest version (as of today), i.e. 12.2.1 provides the capability to address this. There is a feature in ADF called Match Media Behavior which helps the developer to set the layout and placement of UI components in a page based on the screen size. This enables the appropriate rendering of the page regardless of whether it is being rendered in a desktop, tablet or a mobile device. In this way, customers can see the possibilities of getting away from building a mobile app, which requires additional infrastructure, separate code base etc.

In this blog, I am providing a simple example of using the matchMediaBehavior tag. My page has a bar chart and a table. When the page is rendered in a desktop device, these components should render horizontally, and when it is rendered in a tablet device, these components should be displayed vertically, so that the table will be rendered below the bar chart.

Here is the code of the page:

<?xml version='1.0' encoding='UTF-8'?>
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
                xmlns:dvt="http://xmlns.oracle.com/dss/adf/faces" xmlns:f="http://java.sun.com/jsf/core">
  <af:panelGroupLayout id="pgl1" layout="horizontal">
    <af:matchMediaBehavior matchedPropertyValue="vertical" propertyName="layout" 
  mediaQuery="screen and (max-width: 900px)"/>
    <dvt:barChart orientation="vertical" id="barChart1" var="row" value="#{bindings.EmpDetailsVO1.collectionModel}">
      <dvt:chartLegend id="cl1"/>
      <f:facet name="dataStamp">
        <dvt:chartDataItem id="di1" series="#{bindings.EmpDetailsVO1.hints.Salary.label}" value="#{row.Salary}"
                           group="#{row.DepartmentName}"/>
      </f:facet>
    </dvt:barChart>
    <af:table value="#{bindings.EmpDetailsVO11.collectionModel}" var="row" rows="#{bindings.EmpDetailsVO11.rangeSize}"
              emptyText="#{bindings.EmpDetailsVO11.viewable ? 'No data to display.' : 'Access Denied.'}"
              rowBandingInterval="0" selectedRowKeys="#{bindings.EmpDetailsVO11.collectionModel.selectedRow}"
              selectionListener="#{bindings.EmpDetailsVO11.collectionModel.makeCurrent}" rowSelection="single"
              fetchSize="#{bindings.EmpDetailsVO11.rangeSize}" id="t1">
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.FirstName.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.FirstName.label}" id="c1">
        <af:inputText value="#{row.bindings.FirstName.inputValue}"
                      label="#{bindings.EmpDetailsVO11.hints.FirstName.label}"
                      required="#{bindings.EmpDetailsVO11.hints.FirstName.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.FirstName.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.FirstName.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.FirstName.tooltip}" id="it1">
          <f:validator binding="#{row.bindings.FirstName.validator}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.LastName.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.LastName.label}" id="c2">
        <af:inputText value="#{row.bindings.LastName.inputValue}"
                      label="#{bindings.EmpDetailsVO11.hints.LastName.label}"
                      required="#{bindings.EmpDetailsVO11.hints.LastName.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.LastName.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.LastName.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.LastName.tooltip}" id="it2">
          <f:validator binding="#{row.bindings.LastName.validator}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.Salary.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.Salary.label}" id="c3">
        <af:inputText value="#{row.bindings.Salary.inputValue}" label="#{bindings.EmpDetailsVO11.hints.Salary.label}"
                      required="#{bindings.EmpDetailsVO11.hints.Salary.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.Salary.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.Salary.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.Salary.tooltip}" id="it3">
          <f:validator binding="#{row.bindings.Salary.validator}"/>
          <af:convertNumber groupingUsed="false" pattern="#{bindings.EmpDetailsVO11.hints.Salary.format}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.DepartmentName.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.DepartmentName.label}" id="c5">
        <af:inputText value="#{row.bindings.DepartmentName.inputValue}"
                      label="#{bindings.EmpDetailsVO11.hints.DepartmentName.label}"
                      required="#{bindings.EmpDetailsVO11.hints.DepartmentName.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.DepartmentName.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.DepartmentName.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.DepartmentName.tooltip}" id="it5">
          <f:validator binding="#{row.bindings.DepartmentName.validator}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.JobTitle.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.JobTitle.label}" id="c6">
        <af:inputText value="#{row.bindings.JobTitle.inputValue}"
                      label="#{bindings.EmpDetailsVO11.hints.JobTitle.label}"
                      required="#{bindings.EmpDetailsVO11.hints.JobTitle.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.JobTitle.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.JobTitle.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.JobTitle.tooltip}" id="it6">
          <f:validator binding="#{row.bindings.JobTitle.validator}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.City.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.City.label}" id="c7">
        <af:inputText value="#{row.bindings.City.inputValue}" label="#{bindings.EmpDetailsVO11.hints.City.label}"
                      required="#{bindings.EmpDetailsVO11.hints.City.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.City.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.City.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.City.tooltip}" id="it7">
          <f:validator binding="#{row.bindings.City.validator}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.StateProvince.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.StateProvince.label}" id="c8">
        <af:inputText value="#{row.bindings.StateProvince.inputValue}"
                      label="#{bindings.EmpDetailsVO11.hints.StateProvince.label}"
                      required="#{bindings.EmpDetailsVO11.hints.StateProvince.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.StateProvince.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.StateProvince.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.StateProvince.tooltip}" id="it8">
          <f:validator binding="#{row.bindings.StateProvince.validator}"/>
        </af:inputText>
      </af:column>
      <af:column sortProperty="#{bindings.EmpDetailsVO11.hints.RegionName.name}" sortable="true"
                 headerText="#{bindings.EmpDetailsVO11.hints.RegionName.label}" id="c10">
        <af:inputText value="#{row.bindings.RegionName.inputValue}"
                      label="#{bindings.EmpDetailsVO11.hints.RegionName.label}"
                      required="#{bindings.EmpDetailsVO11.hints.RegionName.mandatory}"
                      columns="#{bindings.EmpDetailsVO11.hints.RegionName.displayWidth}"
                      maximumLength="#{bindings.EmpDetailsVO11.hints.RegionName.precision}"
                      shortDesc="#{bindings.EmpDetailsVO11.hints.RegionName.tooltip}" id="it10">
          <f:validator binding="#{row.bindings.RegionName.validator}"/>
        </af:inputText>
      </af:column>
    </af:table>
  </af:panelGroupLayout>
</ui:composition>


Tip: To test the behavior of page’s rendition in a tablet device, you can decrease size of the browser window.

When the page is rendered in desktop device


When the page is rendered in tablet device