how to bring common ui patterns to adf
DESCRIPTION
When working with enterprise applications, you want to have the same user experience that you know from for instance office applications and browsers. People know how to use the features that can be found in browsers such as bookmarking, favorites, and working with tabs. The search mechanism provided by Google, that uses suggestions based on the text typed by the user, is so common that people expect this in every application. And there are more of these UI patterns. In this session, you will learn how to implement some of the common UI patterns in your ADF application.TRANSCRIPT
![Page 1: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/1.jpg)
ADFHow to Bring Common UI Patterns to ADF
Luc Bors, AMIS, The NetherlandsWednesday, June 27, 2012 ODTUG KScope 12San Antonio, Texas, USA
![Page 2: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/2.jpg)
UI PATTERNS
Pattern Name
Problem statement
Use when ?Solution
Examples
Pattern Description
![Page 3: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/3.jpg)
FUSION APPS PATTERNS
![Page 4: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/4.jpg)
RECOGNIZE THESE ?
ADF Train Taskflow
![Page 5: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/5.jpg)
RECOGNIZE THESE ?
ADF Breadcrums
![Page 6: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/6.jpg)
TABBED NAVIGATION
![Page 7: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/7.jpg)
TABBED NAVIGATION
ADF UI Tabshell
![Page 8: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/8.jpg)
CLOSE ALL / CLOSE OTHERS
![Page 9: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/9.jpg)
CLOSE ALL / CLOSE OTHERS
![Page 10: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/10.jpg)
CLOSE ALL / CLOSE OTHERS
• e
![Page 11: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/11.jpg)
CAN YOU DO THIS IN ADF ?
Create the menu
Invoke the menu
Close the tab(s)
![Page 12: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/12.jpg)
CREATE THE CONTEXT MENU
<af:popup id="contextMenu" contentDelivery="lazyUncached" eventContext="launcher" launcherVar="source"><af:menu id="men1" text="#{source.attributes.menuInvokedOnTab}"> <af:commandMenuItem id="cmi1" text="close“ actionListener="#{viewScope.jhsDynTabContext.closeThis}"> <af:setPropertyListener from="#{source.attributes.menuInvokedOnTab}" to="#{viewScope.jhsDynTabContext.menuInvokedOnTab}" type="action"/> </af:commandMenuItem> <af:commandMenuItem id="cmi2" text="close others“ actionListener="#{viewScope.jhsDynTabContext.closeOthers}">……. </af:commandMenuItem> <af:commandMenuItem id="cmi3" text="close all“ actionListener="#{viewScope.jhsDynTabContext.closeAll}"> …………….. </af:commandMenuItem> </af:menu></af:popup>
![Page 13: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/13.jpg)
INVOKING THE CONTEXT MENU
<af:navigationPane ...........> <af:commandNavigationItem ...............> <f:attribute name="tabId" value="#{tab.id}"/> <af:clientListener method="showMenu" type="contextMenu"/> <af:clientAttribute name="menuInvokedOnTab" value="#{tab.id}"/> </af:commandNavigationItem></af:navigationPane >
function showMenu(evt) { var popup = AdfPage.PAGE.findComponent("pt:contextMenu"); …………….. popup.show(hints); evt.cancel();}
![Page 14: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/14.jpg)
USE EXISTING FUNCTIONALITY
![Page 15: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/15.jpg)
CLOSE THIS TAB
public void closeThis(ActionEvent action) {
String id = getMenuInvokedOnTab(); List<String> tabsToRemove = new ArrayList();
for (DynTab t : getActiveTabList()) { String x = t.getId(); if (id == x) { tabsToRemove.add(x); } } for (String t : tabsToRemove) { removeTab(t); }}
![Page 16: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/16.jpg)
CLOSE OTHER TABS
public void closeOthers(ActionEvent action) {
String id = getMenuInvokedOnTab(); List<String> tabsToRemove = new ArrayList();
for (DynTab t : getActiveTabList()) { String x = t.getId(); if (id != x) { tabsToRemove.add(x); } } for (String t : tabsToRemove) { removeTab(t); }}
![Page 17: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/17.jpg)
CLOSE ALL
public void closeAll(ActionEvent action) {
List<String> tabsToRemove = new ArrayList();
for (DynTab t : getActiveTabList()) { tabsToRemove.add(t.getId()); } for (String t : tabsToRemove) { removeTab(t); }}
![Page 18: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/18.jpg)
CLOSE ALL / CLOSE OTHERS
![Page 19: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/19.jpg)
MOST RECENTLY USED (..HISTORY)
![Page 20: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/20.jpg)
IMPLEMENTATION
• Record activities– Use setPropertyListeners
• Historybean (session scope) that manages the collection of navigation events– Display Label, Entity Type and Primary Key– bean calls …
• BusinessService to record event in database for this user– (Optional) Also remove events for deleted records!
![Page 21: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/21.jpg)
CREATE THE BEAN
• Create History bean
<managed-bean id=“1"> <managed-bean-name id=“2"> recentHistoryBean</managed-bean-name> <managed-bean-class id=“3"> nl.amis.jsf.history.beans.RecentHistoryBean </managed-bean-class> <managed-bean-scope id=“3">session</managed-bean-scope></managed-bean>
![Page 22: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/22.jpg)
INTERCEPT ACTIVITY
<af:commandLink id="ot3" text="#{row.LastName}" action="edit" actionListener="#{recentHistoryBean.add}"> <af:setPropertyListener from="#{row.EmployeeId}“ to="#{recentHistoryBean.entityInstanceIdentifier}" type="action"/> <af:setPropertyListener from="#{row.LastName}“ to="#{recentHistoryBean.entityInstanceDisplayLabel}" type="action"/> <af:setPropertyListener from="#{'EMP'}" to="#{recentHistoryBean.entityType}" type="action"/> </af:commandLink>
![Page 23: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/23.jpg)
RECORD ACTIVITY
public void add(ActionEvent actionEvent) { // Add event code here... recentHistory.add(new HistoryEvent(new oracle.jbo.domain.Date() , entityType , entityInstanceIdentifier , entityInstanceDisplayLabel)); HRServiceImpl hrAppMod = (HRServiceImpl) pageTemplateBc.getDataControl().getApplicationModule(); hrAppMod.recordAndPersistHistoryEntry(recentHistory.get(0));
![Page 24: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/24.jpg)
PERSIST ACTIVITY
public void recordAndPersistHistoryEntry(HistoryEvent event) { String statement = "RECENT_HISTORY_MANAGER.RECORD_AND_PERSIST_ENTRY(?,?,?,?)"; callStoredProcedure(statement, new Object[] {event.getEntityType() , event.getKey().toString() , event.getDisplayLabel(), null}); }
![Page 25: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/25.jpg)
THE RESULT
![Page 26: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/26.jpg)
DO YOU RECOGNIZE THIS ??
![Page 27: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/27.jpg)
GOOGLE SEARCH
![Page 28: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/28.jpg)
ADF QUERY COMPONENT ……
I want 1 search field !
Use Oracle Text
![Page 29: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/29.jpg)
PREPARE THE DATABASE
• Make sure that the HR user is allowed to use the ctxsys.ctx_ddl package
grant EXECUTE on CTXSYS.CTX_DDL to HR
![Page 30: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/30.jpg)
CREATE A SEARCH PACKAGE
function get_emp_search_item ( p_rowid in rowid ) return varchar2 as begin for b in (select e.first_name , e.last_name , e.email , e.phone_number , j.job_title from employees e left join jobs j using (job_id) where e.rowid = p_rowid) loop return b.first_name || ' ' || b.last_name || ' (' || b.email || ', ' || b.phone_number || ', ' || b.job_title || ')'; end loop; end get_emp_search_item;
![Page 31: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/31.jpg)
CREATE THE ORACLE TEXT INDICES
-- Configure preferences...ctx_ddl.create_preference('emp_datastore', 'user_datastore');ctx_ddl.set_attribute('emp_datastore', 'procedure' , 'ot_search.create_emp_search_item');
-- Create the indices... execute immediate 'create index emp_search_index on employees(last_name) indextype is ctxsys.context parameters (''datastore emp_datastore wordlist wordlist lexer lexer stoplist stoplist sync (on commit)'')';
![Page 32: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/32.jpg)
THE BASE CLASSES
• OracleTextSearchSupport: • Converts the given user input (the search command):
<code>searchValue</code> to an Oracle Text search-string.
• BaseViewObjectImpl • overrides getCriteriaItemClause(ViewCriteriaItem vci)
• BaseViewDefImpl • implementation to provide the following custom properties on
ViewObjects:• ORACLE_TEXT_SEARCH_ATTRIBUTE: To mark the column in which the seach
info is queried• ORACLE_TEXT_INDEX_ATTRIBUTE: To mark the database column on which
the index was defined in the database.
![Page 33: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/33.jpg)
CREATE THE MODEL PROJECT
![Page 34: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/34.jpg)
CREATE THE MODEL PROJECT
![Page 35: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/35.jpg)
VIEWCONTROLLER : A BEAN
<managed-bean-name id="1">departmentsQuickSearch</managed-bean-name> <managed-bean-class id="4"> adfplus.quicksearch.controller.bean.QuickSearchBean </managed-bean-class> <managed-bean-scope id="2">pageFlow</managed-bean-scope> <managed-property id=“8"> <property-name id=“10">iteratorBindingName</property-name> <property-class>java.lang.String</property-class> <value id="9">DepartmentsVO1Iterator</value> </managed-property> <managed-property id="11"> <property-name id="13">searchAttribute</property-name> <property-class>java.lang.String</property-class> <value id="12">DepartmentSearchString</value> </managed-property> <managed-property id="14"> <property-name id="15">searchIteratorBindingName</property-name> <property-class>java.lang.String</property-class> <value id="16">DepartmentsVO1IteratorQuickSearch</value> </managed-property>
![Page 36: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/36.jpg)
VIEWCONTROLLER : A SUBFORM
<af:subform id="s1" defaultCommand="cb7"> <af:panelGroupLayout id="pgl4" layout="horizontal" inlineStyle="margin:10px;"> <af:inputText label="Search" id="it2“ value="#{pageFlowScope.departmentsQuickSearch.searchValue}"> <af:autoSuggestBehavior suggestItems= "#{pageFlowScope.departmentsQuickSearch.suggestItems}" maxSuggestedItems="10"/> </af:inputText> <af:commandButton text="Search" id="cb7" action="#{pageFlowScope.departmentsQuickSearch.go}" partialSubmit="true"/> </af:panelGroupLayout></af:subform>
![Page 37: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/37.jpg)
VIEWCONTROLLER : SEARCH METHOD
private synchronized List<SelectItem> search(String searchValue) {
DCIteratorBinding iter = getSearchIteratorBinding(); applySearchCriteria(iter, searchAttribute, searchValue);
translations.clear(); lastSuggestList = new ArrayList<SelectItem>(); lastSearchValue = searchValue;
Row[] rows = iter.getAllRowsInRange(); for (Row row : rows) { String description = (String)row.getAttribute(searchAttribute); lastSuggestList.add(new SelectItem(description)); translations.put(description, row.getKey()); }return lastSuggestList; }
![Page 38: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/38.jpg)
THE RESULT
![Page 40: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/40.jpg)
THE CONCEPT
![Page 41: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/41.jpg)
THE IMPLEMENTATION; THE DATABASE
grant change notification to <user>;
![Page 42: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/42.jpg)
REGISTER FOR DBQRCN (STEP 1)
public void startChangeNotification(){ DatabaseChangeRegistration dcr = null; String query = "SELECT * from DEPARTMENTS"; Properties prop = new Properties(); prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS
,"true"); prop.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION ,"true"); try { dcr = conn.registerDatabaseChangeNotification(prop); RdbmsChangeEventListener listener = new RdbmsChangeEventListener(this); dcr.addListener(listener); ………..
![Page 43: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/43.jpg)
REGISTER FOR DBQRCN (STEP 2)
// second step: add objects in the registration: Statement stmt = conn.createStatement();
((OracleStatement)stmt).setDatabaseChangeRegistration(dcr); ResultSet rs = stmt.executeQuery(query); while (rs.next()){} rs.close(); stmt.close();
![Page 44: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/44.jpg)
WHATS NEXT ….
Database is prepared
Queries are registered
Now its time for the UI
![Page 45: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/45.jpg)
SETUP ACTIVE DATA COMPONENT
public void setupActiveData() { ActiveModelContext context = ActiveModelContext.getActiveModelContext(); Object[] keyPath = new String[0]; context.addActiveModelInfo( this , keyPath , "activemessage"); System.out.println("add active bean as listener"); databaseNotificationProcessor.registerAsListener(this);}
![Page 46: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/46.jpg)
SETUP THE ACTUAL UPDATE
public void triggerDataUpdate(String message) { this.message = message; counter.incrementAndGet(); ActiveDataUpdateEvent event = ActiveDataEventUtil.buildActiveDataUpdateEvent( ActiveDataEntry.ChangeType.UPDATE, counter.get(), new String[0], null, new String[] { "activemessage" }, new Object[] { message }); System.out.println("fireActiveDataUpdate"); fireActiveDataUpdate(event); }
![Page 47: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/47.jpg)
IMPLEMENTATION IN THE PAGE
<af:activeOutputText value="#{pageFlowScope.trackChangesBean.updates}" id="aot1" visible="false"> <af:clientListener method="activeDataCallback" type="propertyChange"/></af:activeOutputText>
<af:resource type="javascript"> activeDataCallback = function (event) { var button = AdfPage.PAGE.findComponentByAbsoluteId("pt1:r1:0:cb1"); button.setVisible(true); }</af:resource>
![Page 48: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/48.jpg)
THE RESULT
MAGIC
![Page 49: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/49.jpg)
PATTERNS UNDER INVESTIGATION
• Grouping Tabs• Drag and Drop Tabs in UI Shell
– dragSource and dropTarget
• Duplicating Tabs– Restarting a new instance of a taskflow
![Page 50: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/50.jpg)
PATTERNS UNDER INVESTIGATION
• Adding Sticky Notes– dragSource and dropTarget– Contextual events
– Concept : http://technology.amis.nl• Search for: adf-11g-dragn-drop-and-contextual-events/
![Page 51: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/51.jpg)
RESOURCES
![Page 52: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/52.jpg)
RESOURCES
![Page 53: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/53.jpg)
SUMMARY
If you really want it …..…ADF can do it
Think out of the box
![Page 54: How to Bring Common UI Patterns to ADF](https://reader036.vdocuments.site/reader036/viewer/2022081504/5550d75fb4c905e8318b50d4/html5/thumbnails/54.jpg)
ADFHow to Bring Common UI Patterns to ADF
Luc Bors, AMIS, The Netherlands
[email protected]@gmail.comFollow me on Twitter : @lucb_
Wednesday, June 27, 2012 ODTUG KScope 12San Antonio, Texas, USA