+ All Categories
Home > Documents > Introducing Page Templates - AMIS Oracle and Java Blog · Introducing Page Templates Page templates...

Introducing Page Templates - AMIS Oracle and Java Blog · Introducing Page Templates Page templates...

Date post: 13-Apr-2020
Category:
Upload: others
View: 23 times
Download: 0 times
Share this document with a friend
20
Introducing Page Templates Page templates allow us to specify the structure of the pages in our application through a single entity: the page template. In this template we can specify the layout structure - top bar, footer, side bar, logo’s, copyright message etc. Pages can be created based on the page template. The page specifies the content that is pasted in the designated areas in the template. When we want to change the overall look & feel of our application, we only need to make those changes in the page template, and all pages automatically display with those changes. Objective We will create a new Page Template with two facetRefs and a parameter. The pages based on the template have to provide the content for the two facets and the parameter. We will create two pages based on the template. We run the application. Then we decide to make a change in the template. And re-run the pages to see the changes applied. Steps 1. Create a new JDeveloper Application IntroductionPageTemplate - Generic Application; Choose the ADF Faces library. 2. Go to the New Gallery. Click on the JSF Category and select the JSF Page Template item.
Transcript

Introducing Page Templates

Page templates allow us to specify the structure of the pages in our application through a single

entity: the page template. In this template we can specify the layout structure - top bar, footer, side

bar, logo’s, copyright message etc. Pages can be created based on the page template. The page

specifies the content that is pasted in the designated areas in the template.

When we want to change the overall look & feel of our application, we only need to make those

changes in the page template, and all pages automatically display with those changes.

Objective We will create a new Page Template with two facetRefs and a parameter. The pages based on the

template have to provide the content for the two facets and the parameter. We will create two

pages based on the template. We run the application. Then we decide to make a change in the

template. And re-run the pages to see the changes applied.

Steps

1. Create a new JDeveloper Application IntroductionPageTemplate - Generic Application;

Choose the ADF Faces library.

2. Go to the New Gallery. Click on the JSF Category and select the JSF Page Template item.

Create JSF Page Template. Call it mainDataTemplate.jspx

Specify two facets: body and aboutWindow.

Go to the attributes page. Define three attributes: pageTitle, showGlobalSearch and

selectedMenuItem.

Now we will create the look and feel of our application. Or at least of the main template used in the

application. However, it does not need to look good at this point. As long as the right number of

facets is defined as well as the required attributes, we can leave the pageTemplate as ugly as we like.

This is because we can change it any time, without having to modify any of the pages. So although

our developers would probably prefer to have a decent template early on, there is no real need for it.

3. Create the main layout in the pageTemplate. Here are some steps that may give you a

reasonable idea of what you could do in a template (it does not really matter what you do, as

long as you use the two facets and ideally the three attributes as well)

Drag a PanelSplitter to the template page; drop it inside the af:pageTemplateDef

element (in the Structure Window); set the orientation attribute to Vertical

Drag a panelGroupLayout to the first panelSplitter facet. Drag a panelBorderLayout inside

the panelGroupLayout.

The content of the panelBorderLayout could be like this:

<af:panelBorderLayout>

<f:facet name="bottom">

<af:outputLabel value="#{attrs.pageTitle}"

inlineStyle="font-family:Verdana, Arial,

Helvetica, sans-serif; font-size:xx-large; color:Blue; font-weight:bolder;"/>

</f:facet>

<f:facet name="innerLeft">

<af:image source="/img_amis_logo.gif"/>

</f:facet>

<f:facet name="right">

<af:image source="/helpIcon.jpg" inlineStyle="width:35px;">

<af:showPopupBehavior triggerType="click"

popupId="aboutWindowPopup"/>

</af:image>

</f:facet>

</af:panelBorderLayout>

Here we specify two images and an outputText with some styling. This outputText

renders the title of the page and uses the value of the pageTitle attribute configured for

the pageTemplate. The second image is a question mark icon. Associated with this image

is a showPopupBehavior that specifies that when the image is clicked upon, the

aboutWindowPopup Popup should be displayed. We will create the Popup in a moment.

Drag another panelSplitter inside the second facet of our vertical Panel Splitter. This

splitter has a horizontal orientation. Set a background color on this splitter, for example

the light blue of the screenshot.

Drag a vertical panelGroupLayout to the first facet of this new splitter. Drag a facetRef to

the second splitter facet and drop it. Choose the body Facet from dropdown list, as that

is where the contents passed into the template through the body facet is to go.

The contents of the first facet of the horizontal panelSplitter could be something like this:

<af:panelGroupLayout layout="vertical">

<af:panelBorderLayout inlineStyle="height:100%;">

<f:facet name="bottom">

<af:outputText value="This application supports the

improvement of every day life for operators."

inlineStyle="background-

color:rgb(214,231,255); vertical-align:bottom;"/>

</f:facet>

<f:facet name="top">

<af:panelList maxColumns="1">

<af:goLink text="Main Menu"

inlineStyle="#{attrs.selectedMenuItem=='main'?'font-weight:bolder; font-

size:large;':''};"/>

<af:goLink text="Adminstration Menu"

inlineStyle="#{attrs.selectedMenuItem=='admin'?'font-weight:bolder; font-

size:large;':''};"/>

<af:goLink text="Your Worklist"

inlineStyle="#{attrs.selectedMenuItem=='work'?'font-weight:bolder; font-

size:large;':''};"/>

</af:panelList>

</f:facet>

<f:facet name="innerBottom">

<af:spacer width="10" height="50"/>

</f:facet>

</af:panelBorderLayout>

</af:panelGroupLayout>

The most interesting bit is the panelList with three imaginary menu options. The styling of

these menu options depends on the value of the selectedMenuItem attribute that is

specified by the pageTemplate and whose value is to be passed to the template from each

based based on it. The idea is that the page indicates which menu option should be

highlighted.

Let’s now create the Popup that is to be shown when the Help (Question Mark) image is

clicked:

Drag a Popup and drop it just under the PanelSplitter node; set its id attribute to

aboutWindowPopup.

Drag a panelWindow inside the Popup. Specify a title like About this Page.

Drag a facetRef component inside the panelWindow; choose the aboutPage facet in the

drop down list.

Time to create a page that is based on this template.

4. Create a new JSF page; call it MyFirstPage.,jspx. Choose the mainDataTemplate as the

template to base the page on.

5. Add f:attribute children to the af:pageTemplate element to pass values for the template’s

parameters:

<af:pageTemplate viewId="/mainDataTemplate.jspx">

<f:attribute name="pageTitle"

value="The title of the first page in this application" />

<f:attribute name="selectedMenuItem"

value="admin" />

6. Create content for the two facets that the template has predefined for this - and every other

page based on it.

Drag a rich text editor to the body facet.

Drag an image to the aboutPage facet.

Add a little bit help for our friends:

<f:facet name="aboutPage">

<af:panelHeader text="Explaining The Rich Text Editor

Page"

inlineStyle="width:450px;">

<af:image source="/img_amis_logo.gif"/>

<af:outputText value="This page is used for editing

textual content. It allows you to not only specify the text itself but

some of its mark up too. You can use it for specifying simple mark up

like Bold, Underline and Italic. It also allows setting of fonts, font

size, coloring and both bullet and number lists. Indentation and left

vs. right aligning is among the functionality too."

/>

</af:panelHeader>

</f:facet>

7. Run the page:

Notice how the page for which we only defined a title, a selectedMenuItem, the content of

the about window and the content for the body displays with a lot of extras. There is a

structure to the page, with a header with a logo and a sidebar with a menu. Of course that is

all added by the template that is applied at runtime.

Click on the big question mark. Now the popup behavior kicks in and opens the aboutPage

popup, that displays the content that we injected through the about facet - the little help for

our friends.

8. Let’s quickly create a second page, now that we get the hang of it.

Create a new JSF Page, select the same mainDataTemplate template. Provide values for the

attributes:

To quickly throw something together, I have dragged a panelGrid (JSF HTML library) to the

body facet and included image links into it (just random images from a Google Image search).

I provided content for the about facet with a PanelHeader and some OutputFormat text.

9. Run this page too.

10. Although the overall look & feel is consistent between “all” pages, it is consistently lousy. So

we need some changes.

Go to the page template and make for example the following changes:

Choose another Font and Style for the Page Title.

Use a different logo in the header and/or show the logo in the footer of the side bar.

Add a footer with a copyright message

Change the background color

Add one or two menu options

Add a global search item in the side bar - that is only shown when the

showGlobalSearch attribute has the value true

11. Now run the pages again - see how by changing a single template we impacted our entire

application! (the value of that statement increases with the number of pages in your

application, obviously)

Bonus Practice: Dynamic, Context Sensitive Template Selection Extra: the template reference in the pages can be specified through an EL expression. That means the

application can decide at run-time which template to apply - as long as the number of facets defined

for the templates is equal. The template - and therefore the look & feel/layout structure - can thus

be made context sensitive. See for a more detailed description this blog article:

http://technology.amis.nl/blog/3702/keeping-up-appearances-with-adf-11g-richfaces-context-

sensitive-styling-in-a-world-of-imperfect-html-with-dynamic-pagetemplate-and-page-fragment-

includes

1. Now try this out:

create a class that has a property currentTemplate

configure a managed bean for that class

change the template reference in the page to an EL expression referencing that bean and

property

create a new page template; include the same facets (body and about) and the same

attributes; create the layout structure for this new template

create a radio group or dropdown item in both templates; the select items refer to the

two templates; the value attribute of the select control is associated with the same EL

expression as used in the template reference, namely the bean and currentTemplate

property.

Create a Page Template

Embed one or more facetRef elements for the holes to be filled by the pages based

on the template

Publish the template “API” – the input parameters it supports

Create pages based on the template

In these pages, provide content for the facets exposed by the template

Provide values for input parameters supported by template

At any point in time:

change the template (reusing same facetRefs and parameters)

change the facet contents in any page

change template ref in a page (to template with same facets)

• Can be done dynamically

The steps for creating this functionality

1. Create Fusion Web Application

2. In Model Project, create default Dept and Emp Entity and View Objects, with ViewLink

between Dept and Emp. Ensure to set Deptno and Empno to be Primary Key attributes.

3. Create a new JSF page - DeptEmp.jspx.

Drag EmpView from Data Control palette and drop as Master Form Detail Table. Only include

Empno and Ename in the Emp table.

4. Create a class EmpTableManager. Configure a managed bean EmpTableManager based on

this class.

<managed-bean>

<managed-bean-name>EmpTableManager</managed-bean-name>

<managed-bean-class>view.EmpTableManager</managed-bean-class>

<managed-bean-scope>session</managed-bean-scope>

</managed-bean>

Add private member employeeKeyString and method processSelectionEvent() in the class:

String employeeKeyString;

public void processSelectionEvent(SelectionEvent selectionEvent) {

RowKeySet rks = selectionEvent.getAddedSet();

List k = (List)rks.iterator().next();

Key empKey = (Key)k.get(0);

employeeKeyString = empKey.toStringFormat(false);

}

5. Set the selectionListener attribute on the Employee table. Make sure the

EmpTableManager’s processSelectionEvent is called whenever a row is selected in the table:

<af:table …

selectionListener="#{EmpTableManager.processSelectionEvent}"

6. You can run the page and see a perfectly ordinary Master-Detail page with Form-Table

layout, navigation buttons for the Form to browse through departments

Now things start getting more interesting: we are about to first create and then embed a bounded

task flow.

7. Create New Bounded Task Flow. Go to the New Gallery (main menu File, New)

Name the task flow employee-form. Ensure that the checkbox Create as Bounded Task Flow

is checked (that is the default so it should be).

8. Create Method Binding for AllEmloyeesView setCurrentRowWithKey action: drag the

SetCurrentRowWithKey action from the Data Controls Pallet and drop it on the task flow

diagram.

This creates the SetCurrentRowWithKey action binding.

Right click the SetCurrentRowWithKey method call and select the option Edit Binding. In the

Action Binding editor specify the EL expression for the rowKey parameter:

#{pageFlowScope.empKey}. We will define an inputParameter on the Task Flow that stores

its value in that location.

9. Also create View EmployeeForm, by dragging a View activity from the Component Palette to

the task flow diagram.

10. Create a navigation flow between the two, using the default outcome of the MethodCall -

setCurrentRowWithKey - as we will always go to the EmployeeForm View after setting the

current row.

The diagram should now look like this:

11. Configure an input parameter on the task flow: select the task-flow in the Application

Navigator. In the Structure Window, select the task-flow-definition root node. In the

property inspector, you can now edit the parameters.

Add a new inputParameter by clicking on the green Plus icon, after disclosing the Parameters

panel.

It is called employeeKey to the outside world. The value passed for that parameter is stored

in #{pageFlowScope.empKey} where it can be used in the SetCurrentRowWithKey call.

12. Time to create the View: the Employee Form.

Double click on the EmployeeForm view activity in the Task Flow. This will take you to the JSF

Visual Page Editor.

Drag the Employees collection to the page and drop it as an ADF Form. Include a Submit

Button.

This concludes the construction of the Bounded Task Flow - at least for now. We will return to the

DeptEmp page to embed the Task Flow in order to add additional functionality using this reusable

component.

13. Go to the DeptEmp.jspx page.

Drag the employee-form task flow from the Application Navigator and drop it on the page,

next to the Employees Table.

Set the value for the employeeKey input parameter of the task flow to

#{EmpTableManager.employeeKeyString}.

The Task Flow Binding - the usage by the page of the Task Flow - is added to the Page

Definition of the page, that also has all data binding definitions. You can edit the Task Flow

Binding, for example to change the values passed into input variables. Or to change the

Refresh settings for the Task Flow.

14. The Task Flow is refreshed at least once, when the page it is embedded in is first displayed.

We want it to also refresh when another employee row is selected in the table. We have

taken care that when a row is selected, the bean property that provides the value for the

Task Flow’s employeeKey input parameter is properly updated - through the

selectionListener in the EmpTableManager bean.

However, we need to do one other small thing to make the region refresh whenever the

value of its input parameter refreshed, and that is to set the Refresh property on the Task

Flow Binding to ifNeeded.

15. We can now run the page. Whenever we click on another employee row in the

EmployeesInDepartment table, the employee detail form on the right side is synchronized.

Bonus Practice: Synchronize when browsing Departments When we switch departments, the Employee Form is not automatically synchronized. It only

refreshes when the #{EmpTableManager.employeeKeyString} changes, which currently only happens

when a row is selected in the Employees table. So in order to have the Employee Form synchronized

with a new Department, we have to ensure that we set the employeeKeyString to correct employee

key when a new Department becomes the current one - that is when either of the four navigation

buttons is activated.

We can capture the First/Last/Previous/Next actions and invoke the EmpTableManager and have it

determine the current Employee in the EmployeesInDepartmentIterator then set the key for that

Employee in the employeeKeyString property.

1. Add this action attribute to each of the four navigation buttons:

action="#{EmpTableManager.synchronizeWithCurrentEmployee}"

2. Add the synchronizeWithCurrentEmployee() method to the EmpTableManager class:

public String synchronizeWithCurrentEmployee() {

Object bc = BindingContext.getCurrent().getCurrentBindingsEntry();

DCIteratorBinding ib =

((JUFormBinding)bc).findIteratorBinding("EmployeesInDepartmentIterator");

this.employeeKeyString = ib.getCurrentRowKeyString();

return null;

}

3. Now run the page and see that whenever you navigate to a different Department, the region

with the embedded employee-form task flow is synchronized.

Bonus Practice: Split the Employee Form into a two-page overview One of the interesting features of the Bounded Task Flow infrastructure is that it allows the creation

of a multi-step, multi-page task flow that can be embedded in its entirety in another page. That

means that we can navigate between the steps in the task flow within the context of the host page.

We will see that in action.

1. Open the employee-form task-flow.

Add a new View activity. Call it EmployeeFormPartTwo.

Create Control Flow Case from EmployeeForm to EmployeeFormPartTwo; set the from-

outcome to parttwo. Create Control Flow Case from EmployeeFormPartTwo to

EmployeeForm; set the from-outcome to partone.

The task flow diagram should now look like this:

2. Double click on the new View activity. Accept the dialog that appears and go to the editor for

the EmployeeFormPartTwo.jsff page fragment.

Copy the entire contents from EmployeeForm.jsff and paste it in EmployeeFormPartTwo.jsff.

3. Go to the file DataBindings.cpx and copy the line for EmployeeForm.jsff in the pageMap

element. Change EmployeeForm.jsff to EmployeeFormPartTwo.jsff in the new line:

<pageMap>

<page path="/DeptEmp.jspx" usageId="view_DeptEmpPageDef"/>

<page path="/WEB-INF/employee-form.xml#employee-

form@SetCurrentRowWithKey"

usageId="view_employee_form_employee_form_SetCurrentRowWithKeyPageDef"/>

<page path="/EmployeeForm.jsff" usageId="view_EmployeeFormPageDef"/>

<page path="/EmployeeFormPartTwo.jsff"

usageId="view_EmployeeFormPageDef"/>

</pageMap>

This associates the Page Definition created for EmployeeForm.jsff also with

EmployeeFormPartTwo.jsff.

4. Now remove the form fields for Hiredate, Sal, Comm and Deptno from EmployeeForm.jsff

and remove the fields Empno, Ename, Job and Mgr from EmployeeFormPartTwo.jsff.

5. Add a button to EmployeeForm.jsff; its label should be Next (or Part Two). Its action should

be parttwo.

<af:commandButton text="Part Two" action="parttwo"/>

Add a button to EmployeeFormPartTwo.jsff; its label should be Previuous (or Part One). Its

action should be partone.

<af:commandButton text="Part One" action="partone"/>

6. Now you can run the page again, and watch the two-step bounded task flow in action:

Press the Part Two button - and you get to see the rest of the Employee Details:


Recommended