Wednesday, October 16, 2019

How to implement CSS in ADF


This is a small post regarding "Implementation of CSS in ADF". Implementation of CSS in ADF application is very common and is also very useful as well, as it enhance the User Interface (UI) of Application.


JDeveloper supports two options for applying style information to your ADF Faces components:
  • Build a skin and a cascading style sheet (CSS) using defined style selectors and configure your ADF application to use the skin and style sheet.
  • Use style properties to override the style information from the skin CSS to set specific instances of component display.
Here, we are going to use a CSS file to change the look and feel of ADF components.

STEPS ARE AS FOLLOWS:

 1) First, create a Fusion Web Application (ADF). I have created CssInAdf.


Then, create a *.jspx page as showing above.

2) Now, you can add ADF faces components on your *.jspx page, so that we could apply CSS on those components. I have used ADF's outputtext component for the same.

Type outputtext in component palette (appears right side of your screen by default) &
Drag & drop Output Text (ADF Faces.Common Components) from component palette to your *.jspx page.


To provide space between two outputtext or any other components, you may use Spacer (ADF Faces.Layout) and can set its width or height as shown in the following image.



Here I haven't applied any panel or from on this *.jspx page. However, you may use PanelGroupLayout or PanelFormLayout to customize your page as per your requirement.

3) Now, right click on ViewController and go to New option. Create CSS file and give a name to it.


Now, there will be a CSS file under your Web Content section on your Application Navigator (left side of your screen). This CSS file comes up with some default text which you can delete if you do not need that.

Here, I have created 3 new CSS classes mycss1, mycss2 & mycss3 respectively. See below:



4) Now, create trinidad-skins.xml fileRight click on WEB-INF & choose New option. Now, select  XML Document (XML) from the list.




Now, paste the following code in trinidad-skins.xml file:


**Note: Please note one thing that skin-family should be same in both XML file (trinidad-config.xml & trinidad-skins.xml). Like I have used skyros in both the files.



In above image style.css (text in red circle) is the name of the CSS file which we had created earlier and css is the name of the directory under which it exists.

5) Now, go to your *.jspx page and find resource component in your component palette. Drag & drop it on form of your *.jspx page and select type as CSS.



6) Now, select resource component from you *.jspx's Structure panel and go to its Property Inspector. Provide the source of your CSS file as shown below :-




After clicking on Edit button you can choose your style.css file and press OK. Now, you would be able to see something like below:


7) Now, select the the OutputText component from your *.jspx page and go to its Property Inspector and provide the CSS class name in StyleClass section. Changes will be shown on your JSPX page. Like below:


Repeat the same thing for next two OutputText component & run your JSPX page. JOB DONE...!!
Here is the final screen....


--> You can download the sample application from here

Important Points:

We can use following options for applying style information to the ADF Faces components
  • Style Selectors - Style sheet rules include a style selector, which identifies an element, and a set of style properties, which describe the appearance of the components. ADF applications can use the skin and stylesheet using the defined style selectors. ADF Faces components includes following two categories of skin style selectors: 
    • Global selectors determine the style properties for multiple ADF Faces components.
      AFDefaultFontFamily:alias
      {
          -tr-inhibit:font-family;
          font-family:Arial, Helvetica, sans-serif !important;
      }
    • Component selectors are selectors that can apply a skin to a particular ADF Faces component.
      af|inputText::content {
               background-color: red;
      }
  • Style Properties - You can adjust the look and feel of any component at design time by changing the style-related properties which always render on the root DOM element. Any style-related property you specify at design time overrides the comparable style specified in the application skin or CSS for that particular instance of the component. ADF supports following style related properties:
    • The inlineStyle attribute is a semicolon-delimited string of CSS styles that can set individual attributes. They are applied to the root DOM element of the component e.g., we can apply style to a wrapper span for input using following
      <af:outputText value="outputText1" inlineStyle="color:Red; text-decoration:overline;"/>
    • The contentStyle attribute is available for some of the ADF Faces component like inputText. We can style style attributes that do not register on the root DOM element, e.g., we can style input item on the HTML page – where the user enters the value using following
      <af:inputText value="outputText1" contentStyle="color:Red;"/>
    • The styleClass attribute is a CSS style class selector used to group a set of inline styles, e.g.,
      <af:button text="Submit" id="btnSubmit" action="#{pageBean.submit}" styleClass="my-btn"/>
We can also style the final generated HTML using the traditional CSS elements and selectors - type, ID and class. This CSS file can be stored internal or external to the application. ADF assigns auto-generated class to each of the HTML element. We should not rely on these, as the class name and generated HTML structure can change with every release. If we need to use external stylesheets, we should define and assign our own custom class selectors to avoid migration issues.

What is skin? 


An ADF skin is a special type of cascading style sheet (CSS) that allows you to customize the appearance of these components. Instead of providing a CSS file for each component, or inserting a style sheet on each page of the application, you create one ADF skin for the web application. Every component that renders in the user interface automatically uses the styles defined by the ADF skin. This means you do not have to make design-time changes to individual pages to change their appearance when you use an ADF skin. Skinning refers to the task of developing an ADF skin to apply to a web application that uses ADF Faces and ADF Data Visualization components in the user interface.

How to use custom styles? 


ADF provides a rich set of skin selectors. But skins are not used to style individual instances of components. We can still achieve it using custom class selectors.
We can set a custom style on af:inputText using following code: 
<af:inputText id="input1" label="Name" styleClass="my-input"/>
We can then define this custom style within the skin as following:
af|inputText.my-input {background-color:yellow} 
af|inputText.my-input af|inputText::content {background-color:red} 
af|inputText.my-input af|inputText::label {font-weight: bold}
Also, the custom selector are very useful when we are using external stylesheet, instead of the auto generated class selectors. 

Skinning vs External Stylesheet


Following table provides a comparison between usage of skinning and external stylsheet within ADF:



ADF SkinExternal Stylesheet
ApproachComponent basedHTML based
Page Designing
Web page developers have no direct control over the HTML that is rendered. Components generate the HTML for themselves.
To help in better understanding of styles we should set the web.xml contextual parameter org.apache.myfaces.trinidad.
DISABLE_CONTENT_COMPRESSION=true during CSS design.
Web page developer can design an HTML page in its entirety, taking care to proper alignments across containers, leveraging relative CSS positioning, components can only generate the HTML for themselves.
Maintenance
Skin files are less intuitive than external stylesheet for webdesigners and have a learning curve. But styling components provide productivity and help achieve consistency in source code and in look & feel.
Styling is based on HTML elements like <div>, <span>, <ul> etc.
DeclarationYou do not need to include skin on every page. They are applied to all the pages based on any EL expression defined.The external stylesheets have to be declared
Scope
Skins applies to the entire application. They are not used to style individual instances of components, although to some extent we can make skin features conditional.
RichClient components – allow multiple styleclasses to be set. For example the inputText component has inlineStyle and contentStyle. The latter applies to input item in the HTML page – where the user enters the value – while inlineStyle is a set of CSS styles that are applied to the root DOM element of the component. Many components are composed of several DOM elements which may have their own styles applied to them.
Alternatively, we can define our own custom class selectors within the skin which can style components individually.  
If you do not wish to change ADF Faces components throughout the entire application, we can create a custom class selector in an external stylesheet and assign it to a component on the page using styleClass property.
InheritanceSkin styles inherit properties from each other, making global changes across all or all similar components fairly simple.We can use CSS inherit keyword which will still be dependent on the generated output by ADF.
Browser/Locale SupportSkins provide built-in support for different browsers and locales. ADF generates CSS code based on OS, browser and locale at runtime.We have to write browser specific CSS code.
Dynamic LoadingSkins can be switched dynamically using EL expressions with templates or using EL expression within trinidad-config.xmlThe resources on the page are bound during the declaration time itself. 
CompressionADF optimizes the page and applies compression to the skin files.External CSS files would require an external solution for optimization.
Runtime updatesSince skin is bundled along with the ear file, it cannot be updated without restarting application.External CSS can be updated without requiring an application restart.
Media QueriesMedia queries cannot be used within skin files and need to be kept in a separate external stylesheet. With ADF 12.1.3 onwards, we can use media queries within ADF skin file with selectors.Any media query supported by ADF can be placed here. 

Summary

Though skinning is less intuitive in the beginning to web developers, it provides lot of benefits like property inheritance, global stlying, support for different platforms & browsers, dynamic switching etc. Also, since ADF is component based application, developers will not have the control over the HTML generated. So it is more efficient to use component based approach like skinning over external stylesheet. Styling should not have to depend on the HTML structure.

But there will be cases where applications will be forced to use external stylesheets - like media query support before ADF 12.1.3 or ability to update CSS without restarting application.  
So the decision to use one over another or using mixed approach will depend on the application requirements. But in most of the cases skinning provides lot more control and adavntages over the traditional external stylesheets within ADF.

Sunday, October 13, 2019

How can we populate af:table programmatically?


It means that data in af:table is not populated through the model layer (Using ViewObject) using the binding layerlet’s say I have some values in our managed bean and have to show records in tabular format on page

So what we have to do –
    • First, you should know the number and data type of columns in the table, suppose I have to populate a table for person details (name, mobile number and salary). to get and set the value of columns I have created a java bean class, it has 3 variable for 3 columns
// Java Class to set and get value for table column

public class PersonBean {

public PersonBean(String name, String moNo, Integer salary) {
this.Name = name;
this.mobNo = moNo;
this.salary = salary;
}
private String Name;
private String mobNo;
private Integer salary;

public void setName(String Name) {
this.Name = Name;
}

public String getName() {
return Name;
}

public void setMobNo(String mobNo) {
this.mobNo = mobNo;
}

public String getMobNo() {
return mobNo;
}

public void setSalary(Integer salary) {
this.salary = salary;
}

public Integer getSalary() {
return salary;
}
}

    • Next step is to create a managed bean for referencing af:table , this managed bean makes use of person java bean class to add data in the same format for all table rows. A List data structure is used to pass all values in af:table. See code of managed bean
//ArrayList to poplate data in af:table


List<PersonBean> personList = new ArrayList();


//To Populate default row in table (Code in Constructor)

public ProgTableBean() {
personList.add(new PersonBean("Ashish Awasthi", "xxxxxxxxxx", 50000));
}

public void setPersonList(List<PersonBean> personList) {
this.personList = personList;
}

public List<PersonBean> getPersonList() {
return personList;
}

    • Now just drop an af:table on the page and set its properties like value, column header and text values in columns

As I have to show only 3 columns so deleted extra ones
Set properties –
value- from where table collection is populated
columns values- take the var reference of the table and refer variable name in List (here ‘row’ is table var and second is the variable name in person bean class)
See the XML source of af:table-
<af:table var="row" rowBandingInterval="1" id="t1" value="#{viewScope.ProgTableBean.personList}"
                          partialTriggers="::b1">
                    <af:column sortable="false" headerText="Name" id="c1" width="150">
                        <af:outputText value="#{row.name}" id="ot1"/>
                    </af:column>
                    <af:column sortable="false" headerText="Mobile Number" id="c2">
                        <af:outputText value="#{row.mobNo}" id="ot2"/>
                    </af:column>
                    <af:column sortable="false" headerText="Salary" id="c3" align="right">
                        <af:outputText value="#{row.salary}" id="ot3"/>
                    </af:column>
                </af:table>

    • Now run this application and see there will be one row in the table as the code is added in the constructor of managed bean to populate one row


    • I have added a form and button in the page to add new records in table , see the form source code
<af:panelFormLayout id="pfl1">
                    <f:facet name="footer"/>
                    <af:inputText label="Name :" id="it1" binding="#{viewScope.ProgTableBean.nameBind}"/>
                    <af:inputText label="Mobile Number :" id="it2" binding="#{viewScope.ProgTableBean.mobNumBind}"/>
                    <af:inputText label="Salary :" id="it3" binding="#{viewScope.ProgTableBean.salaryBind}">
                        <af:convertNumber/>
                    </af:inputText>
                    <af:button text="Add Record" id="b1" actionListener="#{viewScope.ProgTableBean.addNewRcord}"/>
                </af:panelFormLayout>
The code in managed bean for button action-
        /**Method to add new record in table
         * @param actionEvent
         */
        public void addNewRcord(ActionEvent actionEvent) {
            //Get all values using compoenet binding as mobNumBind
            if (mobNumBind.getValue() != null && nameBind.getValue() != null &&
                salaryBind.getValue() !=
                null) {
                // Add new Record in List
                personList.add(new PersonBean(nameBind.getValue().toString(), mobNumBind.getValue().toString(),
                                              Integer.parseInt(salaryBind.getValue().toString())));
            }
        }

    • Now run and check application-
    Populate af:table programmatically

    More posts on POJO Based table –
    Thanks, Happy Learning ðŸ™‚
    Download-Sample ADF Application

    Saturday, October 12, 2019

    How to Delete Duplicate Records in Oracle



    Summary: in this tutorial, you will learn step by step how to delete duplicate records in Oracle Database using the DELETE statement with a subquery.


    Once you’ve found the duplicate records in a table, you often want to delete the unwanted copies to keep your data clean.
    If a table has a few duplicate rows, you could do this manually one by one by using a simple DELETE statement. However, it is time-consuming to do it manually if the table has a large number of duplicate records. It is better to construct a single statement that removes all unwanted copies in one go.
    Before removing the duplicate records, you must decide which instances you want to keep. For example, you may want to preserve the newest or oldest row. In this case, you need a column in the table like id column that is not the part of the group used to evaluate duplicate.
    Consider the following fruits table:
    how to delete duplicate records in oracle - sample table
    Suppose you want to keep the row with the highest fruit_id and delete all other copies. The following query returns the last entry for each combination of fruit_name and color:
    how to delete duplicate records in oracle - max id
    You use the following DELETE statement with a subquery to delete rows whose values in the fruit_id column are not the highest ones.
    Three rows were deleted which is what we expected:
    how to delete duplicate records in oracle - after removing duplicates
    Likewise, if you want to keep the row with the lowest id, you use the MIN() function instead of the MAX() function:
    This method above works if you have a column that is not part of the group for evaluating duplicate. If all values in all columns can have copies, then you cannot use the fruit_id column anymore.
    Let’s drop and create the fruits table with a new structure and data as follows:
    how to delete duplicate records in oracle - sample table with duplicates in all columns
    In the fruits table, the values in all columns fruit_idfruit_name, and color have copies.
    In this case, you can use the rowid which is a physical locator that specifies where on storage Oracle stores the row. Because the rowid is unique to each row, you can use it to remove the duplicates as shown below:
    The following query verifies the delete operation:
    how to delete duplicate records in oracle - after deleting copies


    Second Approach:


    5 ways to delete duplicate records Oracle


    In Oracle there are many ways to delete duplicate records. Note that below example are described to just explain the different possibilities.
    Consider the EMP table with below rows
    create table emp(
    EMPNNO  integer,
    EMPNAME varchar2(20),
    SALARY  number);
    10    Bill    2000
    11    Bill    2000
    12    Mark    3000
    12    Mark    3000
    12    Mark    3000
    13    Tom    4000
    14    Tom    5000
    15    Susan    5000
    1. Using rowid
    SQL > delete from emp
    where rowid not in
    (select max(rowid) from emp group by empno);
    This technique can be applied to almost scenarios. Group by operation should be on the columns which identify the duplicates.
    2. Using self-join
    SQL > delete from emp e1
    where rowid not in
    (select max(rowid) from emp e2
    where e1.empno = e2.empno );
    3. Using row_number()
    SQL > delete from emp where rowid in
    (
    select rid from
    (
    select rowid rid,
    row_number() over(partition by empno order by empno) rn
    from emp
    )
    where rn > 1
    );
    This is another efficient way to delete duplicates
    4. Using dense_rank()
    SQL > delete from emp where rowid in
    (
    select rid from
    (
    select rowid rid,
    dense_rank() over(partition by empno order by rowid) rn
    from emp
    )
    where rn > 1
    );
    Here you can use both rank() and dens_rank() since both will give unique records when order by rowid.
    5. Using group by
    Consider the EMP table with below rows
    10    Bill    2000
    11    Bill    2000
    12    Mark    3000
    13    Mark    3000
    SQL > delete from emp where
    (empno,empname,salary) in
    (
    select max(empno),empname,salary from emp
    group by empname,salary
    );
    This technique is only applicable in few scenarios.
    Always take extra caution while deleting records. 
    1. First identify the duplicates using select.
    2. Double verify those are actual  ‘duplicates’ or not
    3. Take backup if necessary
    4. Apply commit only if you are sure.
    Did you find above post useful ? Your comments are highly valuable.