PHP Classes

File: fwphp/glomodul/mkd/01/001_instalac/001_oracle_db_F_R/03_2oracle_apex_sales_apl_cloud.txt

Recommend this page to a friend!
  Classes of Slavko Srakocic   B12 PHP FW   fwphp/glomodul/mkd/01/001_instalac/001_oracle_db_F_R/03_2oracle_apex_sales_apl_cloud.txt   Download  
File: fwphp/glomodul/mkd/01/001_instalac/001_oracle_db_F_R/03_2oracle_apex_sales_apl_cloud.txt
Role: Documentation
Content type: text/plain
Description: Documentation
Class: B12 PHP FW
Manage database records with a PDO CRUD interface
Author: By
Last change: Update of fwphp/glomodul/mkd/01/001_instalac/001_oracle_db_F_R/03_2oracle_apex_sales_apl_cloud.txt
Date: 1 year ago
Size: 413,427 bytes
 

Contents

Class file image Download
<a name="top"></a>2020.08.17 Oracle Application Express 20.1.0.00.13 Copyright © 1999, 2020 ## 1. Intro, content I. BASICS **Top**.....2.1 [Apexws_cloud](#Apexws_cloud).....2.2 [App. builder](#app_builder).....2.3 [Page](#page) .....2.5 [Environm](#environm) .....2.7 [URL](#url) II. APP .....**2.9 [Sales web app - DDL, add data](#sales)** III. SHARED COMPOMENTS .....**3.2 [SHARED C. (lists) 3.2.1 Menu](#shared)**......3.2.2 [Rep.List](#rep_list).....3.2.3 [Ord.WizList](#ord_wiz_list) .....3.3 [Top. right Navig](#top_navig).....3.4 [LOVs](#lov)....3.5 [IMGs](#img) IV. APP PAGES .....4. [Home p.](#home).....4.4 [Buttons](#buttons).....4.5 [PgStyles](#pgstyles).....5. [Cust](#cust).....6. [Product](#prod).....7. [Order](#order) .....8. [Graph. & Mobile](#gra_mob).....9. [Adv. Rep](#advrep) .....10. [Authoriz](#authoriz).....11. [Search--Style--Calendar](#searchstylecal).....12. **[ Deploy](#deploy)** >This txt on my Github : https://github.com/slavkoss/fwphp/blob/master/fwphp/glomodul/mkd/01/001_db/oracle_apex.txt (in Markdown format) is based on https://drive.google.com/drive/my-drive **2020_Riaz_Oracle_APEX_20_For_Beginner.pdf : **, URL to Download Book Code (no DDL) https://tinyurl.com/oracleapex20 >[MD to HTML converters on inet](#md2html) <br /><br /><br /><a name="Apexws_cloud"></a> ## Own Workspace to execute exercises online on Ora. servers (free) [Top](#top).....**Apexws_cloud**.....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared) ......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img).....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) ### Sales APEX app in Oracle Cloud 1. **Cloud Dev APEX : https://apex.oracle.com/pls/apex/f?p=4500:1000** is opened (APEX add :722441254522763:::::) or dev URL https://apex.oracle.com/pls/apex/f?p=4550 To sign in Cloud Dev APEX : https://apex.oracle.com/en/ -> "Sign in" button which opens Login page After "p=" is app alias 4500 (appID) means eg sales-web-app4, possys is workspace. 1000 is pageID. 2. **To leave APEX dev. envir**, click your name (appearing at top-right) and select Sign Out. 3. ** Cloud run Cloud APEX Sales app : https://apex.oracle.com/pls/apex/possys/r/sales-web-app4/home** (APEX add ?session=710994255959550) 1. https://apex.oracle.com/en/ Oracle APEX site 2. click "Get Started for Free" button 3. click "Request a Free Workspace" button On the Identification wizard screen, enter : Request a Workspace First Name Slavko Last Name Srakocic Email **slavkoss22@gmail.com** Workspace **possys** Country Croatia Usage Personal Confirm. email : Workspace Request Approved Environment: https://apex.oracle.com/pls/apex/ Click "Create Workspace" button to complete the approval process and set your psw. Workspace Successfully Created Your request for an account has been approved. Button "Continue to Sign in screen" psw=**MYLONGPSW** opens page : **Cloud Dev APEX : https://apex.oracle.com/pls/apex/f?p=4500:1000** (+ :722441254522763:::::) is opened ## App builder 1. https://apex.oracle.com/pls/apex/ (+ f?p=4550:1:117485610537637:::::) 2. button "Sign in" opens same URL, **page "App Builder"** Click on APEX opens **page "APEX"** contans "Top menus" of page "App Builder" as icons, instead "Dashboard" is "Team development". <br /><a name="goAPEXConcepts"></a> # 2. Oracle APEX Concepts ### 2.1 Exercises online on Ora. servers (free) [Own APEX Workspace on Oracle cloud](#Apexws_cloud) ### [2.2-2.8](#app_builder) <br /><a name="sales"></a> # 2.9 Start Building Sales app. 80858 [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....**Sales**.....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) https://apex.oracle.com/pls/apex/possys/r/sales-web-app4/home (+ eg ?session=706440515653484) 1. https://apex.oracle.com/pls/apex/ + eg f?p=4550 2. Sign In form : Username (your e-mail address) and Password (you provided in Section 2.3.1) 3. Click App Builder icon ->click some app -> "App home page" appears. Use App home page to run, edit, import, export, copy, or delete apps 4. On App Builder page, click "Create" icon 5. Select first "New App" option - Create an App page is displayed 5. In Appearance section, click "Set Appearance" icon 6. Enter **Sales Web Application** in Name box (A) 7. On Appearance page, in Navigation section, select **Mega Menu** option (or Shared Components | Edit App Definition | User Interface | Navigation Menu). Click Choose New Icon button (E), and select an icon (F) and its color (G). By default, App Builder process creates Home page along with a couple of pages (Login and Global). Since you will create other pages for your app in subsequent chapters, **you do not need to add any page** at the moment. 8. In Features section, click Check All link (K). In **Settings section**, accept all default values. Here, **Application ID = 80858** (K) . In **default APEX Accounts authentication scheme** (M) users are managed and maintained in Oracle APEX repository. 9. Click Create App button (N), app will be created with default pages, including **Page 1 Home, Page 9999 Login Page and Page 0 Global Page** (A). Using buttons (View Icons and View Report - B), you can get **different views of this interface**. To **modify** properties of your app (for example, **app name or menu position**), click Edit Application Properties button (D). See **Delete this App** link (E). See **Copy this App** link (F) - makes an exact copy of app under different ID. 10. **Click Run App** (H) - type same username (your e-mail ID) and password you entered earlier to access development environment. Home page bottom is **Developer Toolbar** : 1. Application option (D) takes you to the App Builder page, where you can select a different page to work on. 2. Edit Page option (E) in this toolbar takes you to Page Designer to edit the current page 3. Session option brings up a page (see Figure 2-6) that displays current state of app so that you can verify its behavior 4. Sign Out option (F top page right) exits app. 5. Administration menu option (G) - Administration page that lists all the features you selected in step 9. Features section. <br /><br /><br /><a name="goDBobjects"></a> ## 2.10 Create DB Objects interactively (no SQL) for Sales app Five tables : DEMO_STATES, DEMO_CUSTOMERS, DEMO_PRODUCT_INFO, DEMO_ORDER, and DEMO_ORDER_ITEMS. in folder J:\awww\www\fwphp\glomodul\mkd\01\001_db app 4500, pg 3002 is SQL workshop : https://apex.oracle.com/pls/apex/f?p=4500:3002 app 4500, pg 1001 is SQL workshop Object browser : https://apex.oracle.com/pls/apex/f?p=4500:1001 **See at end this txt [DB Objects](#DBobjects)** <br /><br /><br /><a name="goDBobjectsData"></a> ## 2.11 Add Data to tbl, see oracle_apex_....csv files 1. From main APEX menu, select SQL Workshop | Utilities | Data Workshop 2. On Get Started page, click Load Data button 3. On next screen, click Choose File button. In Open dialog box, select DEMO_CUSTOMERS csv 4. Load Data page will appear on your screen. Select options on this screen. By selecting Existing Table option you are informing that you want to upload the csv file data to eg existing DEMO_CUSTOMERS table. Once you select the database table, **APEX will automatically map columns**. Click Load Data button on this page. A message " Data in table DEMO_CUSTOMERS appended with 7 new rows! " should appear on your screen. Click the View Table button to browse data. **See at end this txt [DB Objects data](#DBobjectsData)** <br /><br /><br /> ### Next In chapter 3, we create building blocks (**shared components**) of app. Shared Components wizards allow us to define components we can re-use in pages (better name "modules" like Ora. Forms) throughout our app. (common, global on app level). Work in detail on Home page in Chapter 4 to convert it into dashboard. Chapter 5 - Customers. Chapter 6 - Products. Chapter 7 -Orders. <br /><br /><br /><br /><a name="shared"></a> # 3. Create (shared, common, appglobal) App Components You can see a list of all Shared Components utilized on some app page by accessing its "**Shared Components" tab in the Page Designer**. **See [3.1 About Shared Components](#shared_about)** # 3.2 Create Lists - collections of links rendered using template [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....[Sales](#sales).....**SHARED C.**......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) ### Shared Components you will use (create) for Sales Web app 1. Lists 2. List of Values (LOV) 3. app Logo **To access Shared Components page** : 1. Select Database apps from the App Builder menu. 2. Click Edit icon (A) under Sales Web app. 3. On the next screen, use either of the two Shared Components icons (pyramid of 3). For each list entry, you specify **display text, a target URL**, and other properties to control **when and how the list entry displays**. You control the display of the list and the appearance of all list entries by **linking the list to a template**. <br /> ## List 1 Main top menu (Desktop Navigation Menu List) APEX App Builder wizard created default Home and Administration mnuitems. Main top menu is hierarchical list of navigation, which appears either as a **responsive side bar or at top of window**. Based on available space, navigation bar either displays a **full menu or collapses to a narrow icon bar**. Modify Desktop Navigation Menu List list to add app submenu level1 entries **Setup, Orders, Reports** : 1. In Shared Components -> Navigation section -> click "Navigation Menu" option 2. On Lists page, click "Desktop Navigation Menu" option, which carries two entries Home and Administration 3. On List Details page, click **Create Entry button** (A) to create **new menu item named Setup**. This menu entry **will have sub-entries** that will allow you to **access Products and Customers modules**. Fill in **values for Setup menu submenu level1 entry** : 1. Do not select anything in the first attribute (Parent List Entry), because initially you will create level one entries 2. Click pop-up LOV icon representing **Image/Class** attribute. 1. From Show list, select Font APEX, and from Category, select Web app 2. Click Go button to refresh the view 3. Scroll down to the middle of the icons list and select **fa-database** icon. This image will be displayed for Setup submenu at run time. Note that you can select any **image from list or input its name** directly in the Image/Class attribute. 3. Type Setup in **List Entry Label field**. This label will appear in app menu. 4. In **Target Type attribute** you specify a **page in current app** or any valid **URL**. Target Type and Page properties inform Oracle APEX where to land when a menu item is clicked, eg Orders entry will take you to page 4. 4. Using button labeled Create and Create Another, create **two more level-1 entries** to form the **main menu of our app** because we set No Parent List Item for all three entries. | Parent List Entry | Image/Class | List Entry Label | Target Type | PgID | Help | | :----------------------- | :-------------------------: | :---------------- | :----------------------- | --------------: | :----------------------- | | No Parent List Item | eg fa-database | **Setup** | No Target | |not associated to any app page | | No Parent List Item | eg fa-send-o | **Orders** | Page in this app | [4](#order) | | | No Parent List Item | eg fa-table-arrow-up | **Reports** | Page in this app | 1 | | After adding last entry (Reports), **click Create List Entry** button. 5. Using same process create **submenus level-2 menu entries**. First two entries will come under the main Setup menu item, while Reports menu will contain two child entries (Graphical Reports and Advance Reports). | Parent List Entry | Image/Class | List Entry Label | Target Type | PageID | Help | | :----------------------- | :-------------: | :------------------------------ | :------------------- | -------------: | :----------------------- | | **Setup** | eg ... | **Manage Customers** | Page in this app | [2](#cust) | | | Setup | eg ... | **Manage Products** | Page in this app | [3](#prod) | | | **Reports** | eg .. | **Graphical Reports** | Page in this app | 1 | | | Reports | eg ... | **Advance Reports** | Page in this app | 1 | | TIP: If you make a mistake while creating these menu entries, you can rectify it. After creating the last entry, click Create List Entry button on Create/Edit page to move back to the List Details page. On this page, click menu entry you want to modify (under Name column) to call its definition in Create/Edit page. Rectify the error and click Apply Changes button. 6. Create l**level 3 entries**. First 5 entries will appear as submenu choices under Graphical Reports menu. Similarly, Monthly Review Report and Customer Invoice will be placed under Advance Reports. All the settings will set up a hierarchical navigation for your app. | Parent List Entry | Image/Class | List Entry Label | Target Type | PageID | Help | | :----------------------- | :----------------: | :-------------- | :---------------------------- | -------: | :----------------------- | | **Graphical Reports** | eg ...| **Customer Orders** | Page in this app | 1 | | | Graphical Reports | eg ...| **Sales By Category/Products** | Page in this app | 1 | | | Graphical Reports | eg ...| **Sales By Category/Month** | Page in this app | 1 | | | Graphical Reports | eg ...| **Order Calendar** | Page in this app | 1 | | | Graphical Reports | eg ...| **Product Order Tree** | Page in this app | 1 | | | **Advance Reports** | eg ...| **Monthly Review Report** | Page in this app | 0 |**set to zero**, because it will be invoked through a print request that will be configured in Chapter 9.| | Advance Reports | eg ...| **Customer Invoice** | Page in this app | 1 | | TIP: After making any modification in your app you can test it immediately. For example, after creating the navigation menu, hit Run Page button (at top-right) to see the app menu. <br /><br /><br /><a name="rep_list"></a> ## List 2 Reports List [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared).....**Rep.List**.....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home) List "Reports List" will have several links that will lead to different reports in your app. Note that you created the same links in the navigation menu in the previous section **to call some of these reports from app menu**. Reports List being created here will be used on a **dedicated report page** to call respective reports - see Chapter 8 section 8.2. 1. Go to **App 80858 -> Sales Web App -> Shared Components -> Navigation -> Lists**. There are 7 default (APEX created) lists. Click Create button to create a new list. 2. Select **From Scratch** on the Source wizard screen and click Next. On the next screen, enter **Reports List** for Name, select **Static** as the list Type, and click Next. When you create a static list you define a list entry label and a target (either a page or URL). 3. Enter the following values in Query or Static Values screen. Initially, the wizard allows you to create five entries. The remaining entries and Image/Class properties are created and set after saving the first five. | List Entry Label | Target PageID | Image/Class | | :--------------------------------------- | ----------------: | :--------------| | Customer Orders | 17 | | | Sales by Category and Product | 16 | | | Sales by Category / Month | 5 | | | Order Calendar | 10 | | | Product Order Tree | 19 | | | **Gantt Chart** | 20 | | | Box Plot | 21 | | | Pyramid Chart | 22 | | | List View (Mobile) | 23 | | | Column Toggle Report (Mobile) | 24 | | | **Reflow Report (Mobile)** | 25 | | | Monthly Review Report | 0 | | | Customer Invoice | 50 | | 4. **After entering the first five list entries** 1. click Next, accept default values in next screen, and click Create List button. 2. You will be taken back to the Lists page, where you will see new list "Reports List" 3. Modify list by clicking Reports List link in the Name column 4. Click Create Entry button to add the sixth entry. Enter Product Order Tree in List Entry Label. Set Target Type to Page in this app and enter 19 in the Page attribute. 5. Click Create and Create Another button to add the remaining entries, as shown in the table above 7. Modify each entry by clicking its name in the List Details interface and add image references. Click the Apply Changes button after adding the image reference <br /><br /><br /><a name="ord_wiz_list"></a> ## List 3 "Order Wizard" List (wizard steps to create an order) [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared).....[Rep.List](#rep_list).....**Ord.WizList**.....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home) List 3 is another utilization of lists. Rather than associating list items to pages in the app, you will use it for visual representation. It will be used while creating orders in Chapter 7. In our app, we will create an order using a set of wizard steps in the following sequence: 1. Identify Customer 2. Select Items 3. Order Summary <br /> So : 1. Go to Shared Components | Navigation | Lists and click Create button 2. Select the first From Scratch option and click Next 3. Type **Order Wizard** in the Name box, set Type to Static, and click Next 4. On the Query or Static Values screen, enter the following values and click Next | List Entry Label | Target Page ID or custom URL | Help | | :----------------------- | :------------------------------------: | :------------------------ | | Identify Customer | 11 | | | Select Items | 12 | | | Order Summary | 14 | | 5. Click Create List button on the Confirm screen. 6. Modify the newly created Order Wizard list. 7. Edit each list item, set **Target Type attribute to No Target** for all 3 list items. 1. The No Target value is set because this list is intended to **display the current order wizard step** where the user is **within the order processing module**, and **not to call a page** in the app. 2. In Current List Entry section, set "List Entry Current for Pages Type" to **Comma Delimited Page List** for all 3 list items, and set "List Entry Current for Condition" attribute to **11, 12, 14**. 3. Click Apply Changes button to save the modifications. **List Entry Current for Pages Type** attribute specifies **when this list entry should be current**. Based on the value of this attribute, you define a **condition to evaluate**. When this condition is true then the list item becomes current. The template associated with list item gives users a visual indication about the active list item. The following figure illustrates the use of Order Wizard list. Being the first step in the order wizard, the Identify Customer list item is marked as current (when Page 11 is called to enter a new order), while the remaining two are displayed as non-current. After selecting a customer, when you move on to the next step to select ordered items, the Select Items entry becomes current and the first and last entries become inactive. ``` ------------------------------- | | | | Non current ------------------------------- ------------------------------- | | | | Current ------------------------------- ``` <br /><br /><br /><br /><br /><a name="top_navig"></a> # 3.3 Desktop Navigation Bar eg top right [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared).....[Rep.List](#rep_list).....[Ord.WizList](ord_wiz_list).....**Top. Navig**.....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home) Also used to link various pages within app eg Help pages, Sign Out. **Location eg top right** of navigation bar depends upon associated page template. When you create a navigation bar, you specify an image name, label, display sequence, and target location (a URL or a page). Navigation bar used in our app will show : **feedback page icon, Page Help entry, About Page entry, id of logged in user and a Sign Out link**. All these entries are created automatically when you create new app. <br /><br /><br /><br /><br /><a name="lov"></a> # 3.4 List of Values (LOV) [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared).....[Rep.List](#rep_list).....[Ord.WizList](ord_wiz_list).....[Top. Navig](top_navig).....**LOVs**.....[Home p.](#home) Used to control input values and **limit users selection**. You can define two types of lists: 1. static list of values is based on **predefined display and return values** 2. dynamic LOV is based on a **SQL query** and it is executed at runtime. ## 3.4.1 LOV CATEGORIES (U, T) - STATIC See 6.4.2 Attach Categories LOV. ## 3.4.2 LOV PRODUCTS WITH PRICE - DYNAMIC You will use this LOV in Chapter 7 section 7.4.2. 1. Shared Components -> Other Components section -> Lists of Values APEX page -> Click Create button 2. Select From Scratch and click Next. 3. Enter **Products with Price** in the Name box. Select Dynamic Type and click Next. 4. On the List of Values Source screen, select SQL Query for the Source Type, and enter the following query in the Enter a SQL SELECT statement box. ``` select apex_escape.html(product_name) || ' [$' || list_price || ']' d , product_id r from demo_product_info where product_avail = 'Y' order by 1 ``` 5. On the final Column Mappings screen, select R for Return Column, D for Display Column and click the Create button to finish the wizard. **APEX_ESCAPE.HTML function** is used to protect against XSS (Cross Site Scripting) attacks. It replaces characters that have special meaning in HTML with their escape sequence. It converts occurrence of : ``` & to & ? to " < to < > to > ``` ## 3.4.3 LOV STATES (dr?ave) - DYNAMIC (used in crUD form Customers) See 5.4.2 Change cust. column "P7_CUST_STATE" to hold predefined LOV! States list. ## 3.4.4 LOV NEW OR EXISTING CUSTOMER - STATIC Will be incorporated in initial Order Wizard step (Chapter 7 Section 7.5.4) to select an existing customer for a new order or to create new one. 1. Shared Components -> Other Components section -> Lists of Values APEX page -> Click Create button 2. Select From Scratch and click Next. 3. Enter **NEW OR EXISTING CUSTOMER** in Name box, select Static as its Type and click Next 4. Fill in display and return values as shown in following tbl and click Create LOV button. | Sequence | Display value | Rerturn value | | :------- | :------------ | :------------ | | 1 | Existing customer | EXISTING | | 2 | New customer | NEW | <br /><br /><br /><br /><br /><a name="img"></a> # 3.5 Images [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page) [Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....**IMGs**....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) You can reference images within your app by uploading them to Images Repository. When you upload an image, you can specify whether it is available to all apps or a specific app. Images **uploaded as shared components** can be referenced throughout an app. They may 1. include images for application menus or buttons 2. or may represent icons that, when clicked, allow users to modify or delete data. **Images uploaded to the images repository should not be directly related to the app data** such as images of products and employees. Such images must be stored in the apps schema alongside the data to which the image is related. You will follow this approach **in Chapter 6 to save each products image along with other information in a DB table**. APEX images are divided into two categories: 1. Workspace images are available to all applications for a given workspace 2. App images are available for only one app ### Add your app logo to images repository. Logo appears at every page top in app. 1. Shared Components -> Files section -> click Static Application Files 2. Click the Upload File button. 3. Click the Choose Files button and select logo.ico file, available in the book code 4. Click the upload button. After uploading the image, you need to **tell Oracle APEX to use this file as your app logo** : 5. Shared Components -> User Interface section -> **User Interface Attributes** 6. Logo section -> Image and Text for Logo 7. Enter **#APP_IMAGES#oracle_apex.ico** in Image URL box, and enter **Sales Web App** in the Text box. An application logo can be an image, text, image and text, or based on custom markup. When you select a type for your app logo, additional attributes appear depending upon your selection. With this selection, your app logo and app name both will be displayed on each app page. The built-in substitution string (APP_IMAGES) is used to reference uploaded images, JavaScript, and cascading style sheets that are specific to a given app and are not shared over many apps. You must use this substitution string if you upload a file and make it specific to an app. Note that you must use the correct case for the image file name and extension, else the logo will not be displayed at runtime. Click the Apply Changes button. Run the app. <br /><br /><br /><br /><br /><br /><a name="home"></a> # 4. Page Home (App Dashboard, default page) with 6 stacked canvases (blocks) [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page)   [Environm](#environm).....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img)....**Home page**.....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) **4.1 About Home Page** Represents objective of app (module). Is created as a blank slate and needs to be populated with **content relevant to your app (module) **- stuff related to sales is : 6 regions to present different views of sales data (see 2.6 and 2.9 Page Designer interface and how to access your workspace). **4.2 Modify Home Page - 2 properties that are usually enough to set for the main page** 1. Sign in to your workspace -> in main menu click App Builder option -> click Edit icon under Sales Web App - see Figure 3-3 in chapter 3. 2. Click Home page icon (if you?re browsing the page in Icon view). This action will **open definitions of Home page in Page Designer interface**. Modify Page Attributes **Home page Name and Title properties** with meaningful labels. Rendering tab to your left -> click root node to refresh Property Editor (on the right side) with the main page properties. Set the properties mentioned in the following table and click the Save button (at the top-right corner). | Property | Value | Note | | :------- | :------------ | ----------------------------------- | | Name | Sales Web App | | | Title | Sales Web App | APEX engine uses title in place of **#TITLE# substitution string** used in page template inserted between the HTML tags <TITLE> and </TITLE> | **Use help** : Click a property in the Property Editor and then click the Help tab (in the Central pane). ## 4.3 Create Regions (stacked canvases - blocks) in Home Page You put page items (Text Field, Select List, Radio Group, report, chart, static HTML content, buttons...) on a page under a specific region (page area, section that serves as a container for content ee to group page elements). Each region can have its **own template**, which controls its appearance. Some of our regions will use **Oracle JET Charts**. Oracle JET Charts (charting library) is a component of JET. These charts work on any modern browser regardless of platform, screen size, or features. JET is integrated Oracle JavaScript and CSS3 and HTML5 Extension, open source Toolkit **To remove a component** (such as a region or an item) from a page, right-click the desired component in the Rendering section, and select Delete from the context menu. If you just created the component, click Undo (A) on the Toolbar to remove it from the page. <br /><br /><br /><a name="homereg1"></a> ## Home Page region 1 : "Top Orders by Date" [Top](#top).....[Home reg.1](#homereg1).....[Home reg.2](#homereg2).....[Home reg.3](#homereg3).....[Home reg.4](#homereg4).....[Home reg.5](#homereg5).....[Home reg.6](#homereg6).....[Home buttons](#hbuttons).....[Home styles](#hstyles) Displays top five orders by date from DB using a **bar chart - horizontal bars=months and sumsales on x axe** - SQL (or PL/SQL function) populated - summarized sales figures (bars) for each date from Orders table. !!!!! ***Rendering tab -> right-click Regions -> select Create Region*** to place new region = </> New under Content Body. **Click "</> New node" ** (future "Top Orders by Date" stacked canvas) and set common region properties in **Property Editor**. Property Editor is **declarative (ee functional programming)** above some prog.language procedural code. <br /><br /> ### Set common region properties (attributes)** | | Property | Value | Help | |-:| :------- | :------------ | :-------------------------------- | | 1 | Title | <span style="color:blue"><i><b>Top Orders by Date</b></i></span> | Title should be unique to every region - **region purpose** . Region has **child node - component - named Attributes** - contains **region-specific properties** (region properties are common to all regions). Eg properties of a Static Content type region are different from a Chart region. | | 2 | Type | Chart | = **page or page component purpose**. Default type is "**Static Content = HTML max 33.8 kB**" region with an empty source text eg **About section** on the right side of the App Builder interface region whose source is displayed text. After setting the second attribute (Type), you will be informed through the Messages tab that there **are some errors** on the page. These messages relate to some mandatory properties you will set accordingly in subsequent sections. | | | Location |**Local Database** | or sourced from : 2. **Remote DB**, connection is defined using REST Enabled SQL or from 3. **Web Source eg RESTful web service** defined using Web Source Modules | | | Type | SQL Query | or PL/SQL fn - how the data is queried | | 3 | SQL Query | select order_day, sales from (select to_char(o.order_timestamp,'Mon DD, YYYY') order_day, SUM(o.order_total) sales from demo_orders o group by to_char(o.order_timestamp,'Mon DD, YYYY'), order_timestamp order by 2 desc nulls last) where rownum < 6 | order by 2 desc nulls last is in 11g DB, but order by 2 desc nulls last **fetch first 5 rows only** - not in 11g DB | | 4 | Start New Row | On (default) | DB apps created in Oracle APEX use **layout comprising rows with 12 columns** to position page elements. "On" **puts region on a new row**. Next region "Sales for This Month" - Start New Row attribute it is set to Off to place that **region adjacent to this one**. | | 5 | Column | Automatic (default) | **Automatically finds a column position (col_ordnum 1 to 12) for the region**. There are **three regions on a single row, each region spans 4 columns**. Region1 will span from column number 1 to 4, R2 from 5 to 8, R3 from 9 to 12 | | 6 | Column Span | 4 | narrows "Top Orders by Date" region | | 7 | Show Region Icon | check mark to select this option | Under Template Options | | | Body Height | 240px | Under Template Options (Click OK to close dialog screen) | | | Icon | fa-lg fa-apex | If **Template property** is set to default "Standard" value for a region, you can place an icon in region header. First, select Show Region Icon option (under Template Options) to display region icon in region header beside region title. Then, click the LOV for the Icon property (under Appearance), select a Style (for example, Large), and choose and icon from provided list. | <br /><br /> ### Set region-specific properties Click Attributes node under new region and set the following region-specific properties : Set Type of this chart region to horizontal bar : | | Property | Value | |-:| :------- | :------------ | | 8 | Type | Bar | | 9 | Orientation | Horizontal | **Click the New sub-node under Series and set the following properties:** | | Property | Value | Help | |-:| :------- | :------------ |:-------------- | | 10| Location (under Source) | Region Source | When you set the region type to Chart (2), a Series node is placed underAttributes with a New sub-node under it. In this node you specify Location (10) for the Series. Since an SQL Query has already been defined, we set it to Region Source, which points to the region?s SQL Query defined in the third attribute. By default, a chart is created with **one series (named New)**, but you can add more (see Chapter 8 section 8.3 steps 5 and 6). | | 11| Label | ORDER_DAY | Label attribute (11) is set to ORDER_DAY column to display values from this column as labels | | 12| Value | SALES | to show sales figures (bars) | | 13| Type (under Link) | Redirect to Page in this application | | **Click No Link Defined under Target and set props in Link Builder dialog box:** Define links on charts is done in properties 13-15. Links let you **call another app page for browsing details**. | | Property | Value | Help | |-:| :------- | :-------------- |:---------------- | | 14| Type | Page in this application | When you click "No Link Defined" under Target prop., a small window titled Link Builder comes up, where you specify **target page details**. Once you set the link type to "Redirect to Page in this Application", a property named Target appears, where you provide the ID of the target application page you want to link with the chart (properties 14 and 15). The Template property (not indicated in the previous table) is set to Standard by default, which forms a **border around the region and displays the regions title across the top**. | | 15| Page | 4 (Click OK to close the dialog screen) | | To test your work from time to time eg after completing this region you can **save and run page** (by clicking the Save and Run Page button at the top-right corner) to check how the region appears on it. At this stage, your Home page will show just **one region (Top Orders by Date)**. If you **click any bar in the chart, app tries to open Page 4 (Orders)** and throws an error, because Orders page does not exist. After completing Page 4 (Orders) in Chapter 7, when you run the Home page and click any of these links, Page 4 will be rendered carrying a list of orders. <br /><br /><br /><a name="homereg2"></a> ## Home Page region 2 : "Sales For This Month" [Top](#top).....[Home reg.1](#homereg1).....[Home reg.2](#homereg2).....[Home reg.3](#homereg3).....[Home reg.4](#homereg4).....[Home reg.5](#homereg5).....[Home reg.6](#homereg6)....[Home buttons](#hbuttons).....[Home styles](#hstyles) Page region 2 uses a **Badge List - 2 circles "Tot.sales and Tot.orders"**. List is dynamically rendered based on a SQL Statement (or PL/SQL function) each time the page is viewed. Later on, we will transform it to present fetched data in graphical format. Create another region as previous region. <br /><br /> ### Set common region properties (attributes)** **Rendering tab to your left App builder -> Home icon (App 80858) -> Page Designer** -> right-click Regions -> select **Create Region** from context menu. New region will be created under previous one. Set following properties for this region in Property Editor. TIP: If a region is not created in the desired location, **drag and drop it to the appropriate location** in the rendering tree. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Title | **Sales for This Month** | | | 2 | Type | Classic Report | | | | Location | Local Database (default) | | | | Type | SQL Query | or **PL/SQL function** to fetch the desired data set. All columns you define in the query appear in a separate node (Columns) under region | | 3 | SQL Query | select sum(o.order_total) total_sales, count(distinct o.order_id) total_orders, count(distinct o.customer_id) total_customers from demo_orders o where order_timestamp >= to_date(to_char(sysdate,'YYYYMM') \|\| '01','YYYYMMDD') | | | 4 | Start New Row | Off | | | 5 | Column | 5 | | | 7 | Body Height (under Appearance -> Template Options) | 240px | | ### Create hidden page item to store first day of currmonth for behind processing **right-click Sales for this Month region and select Create Page Item** from the context menu. A **new node named Items** will be created with a new item named **P1_NEW**. Hidden items can be seen in the **Page Designer**, but they do not appear on the page at run time. Click the new item and set the following properties: | Property | Value | Help | | :--------------- | :------------ | :---------------------------------- | | Name | P1_THIS_MONTH | was P1_NEW | | Type | Hidden | | | Value Protected | On (default) | prevents item value from being manipulated when page is posted | | Type (under Source) | PL/SQL Expression | | | PL/SQL Expression | to_char(sysdate ,'MM') \|\| '01'\|\| to_char(sysdate ,'YYYY') | or if Order Date column on Page 4 is rendered as 09-JAN-2017 : '01-'\|\|to_char(sysdate ,'MON')\|\|'-'\|\|to_char(sysdate ,'YYYY') | Select **TOTAL_CUSTOMERS** column and set the Type attribute of this column to **Hidden Column** (invisible at run-time). ### TOTAL_SALES to transform it into a link **How to refer to a page item in links - present it as a substitution string : &P1_THIS_MONTH. - terminated with a period !!** - see Value property in serial 6 in the following table. Rendering section -> expand Columns node under the Sales for This Month region -> click TOTAL_SALES column - Figure 4-4. Set following props : | | Property | Value | Help | |-:| :------- | :------------ | :----------------------------------- | | 1 | Type | Link | column is to be displayed as a link | | 2 | Format Mask | in LOV select 5,234.10 | produces the mask 999G999G999G999G990D00 from list of values that shows some common currency and date/time formats, 9 is optional digit, 0 is required digit, G is thousand separator, and D is for decimal point | Define link : Click **No Link Defined** under Target -> Link Builder dialog is opened -> set following properties. To call another app page, it is suffice to transform a column into a link by setting three values : Link, Page in this application, and Page Number. Recall that **in previous region you formed a similar kind of link**. | | Property | Value | Help | |-:| :------- | :------------ | :-------------------- | | 3 | Type | Page in this app | link should call a page in current app | | 4 | Page | 4 | Target page number. Next prop. Name (5) and Value (6) are values to be passed from currpg to targetpg. They form a filter argument to display current month's order on the target page (Page 4 - Orders, to be created in Chapter 7). Values for properties (5) and (6) are **usually picked from LOVs** using Page attribute, but due to **absence of Page 4 of our app**, we entered them manually. | | 5 | **Name** (under Set Items) | IRGTE_ORDER_DATE | to specify session state for an item | | 6 | **Value** (under Set Items) | &P1_THIS_MONTH. (do not forget to add the trailing period) | to specify session state for an item | | 7 | Clear Cache | RIR,4 | resets the interactive report on Page 4 | | 8 | Action | Reset Pagination | resets pagination of the target page | **Click OK to close the Link Builder - Target dialog box** | | Property | Value | | |-:| :------- | :------------ | | | 9 | Link Text | Text #TOTAL_SALES# (select this value using the **Quick Pick button**) | column to be displayed as a link | In the current scenario, we used one name/value pair to **filter interactive report on the target page**. However, this section **allows you to set as many filters as you want**. **Each time you provide a value, another row is appended**, thus allowing you to enter another pair of name/value. You can use this section to also specify **target pages items in the Name column** and can set their values using the Value box. For example, to set a customers credit limit items value on the target page, enter the name of that item : (P7_CREDIT_LIMIT) in the Name box and type the corresponding value (5000) in the Value box. This way, **when you call the target page, the value (5000) appears in the credit limit item**. Note that **column names are enclosed in # symbol when you specify them in Link Text attribute**. This is a **mandatory attribute** whose value can be selected using the Quick Pick button appearing next to it. At run-time the link is formed like this (if the application's Friendly URL attribute is turned off): **f?p=145615:4:8824748217892::NO:RP,RIR,4:IRGTE_ORDER_DATE:01012018** using the following syntax: **f?p=&APP_ID.:Page:Sessionid::NO:RP,RIR,4:IRGTE\_(itemname):itemvalue** (stored in &P1_THIS_MONTH item). Table URL parameters : | Argument | Explanation | | :--------------- | :-------------------- | | &APP_ID. | eg 80858. The expression used here is called a **substitution string that holds the application ID** used to make app more portable. | : | colon special character is argument separator. Since the URL contains no REQUEST argument, the position of this argument is left empty - see additional colon before the debug argument (NO). | | 4 | target page 4 = Orders we are calling in URL | | Sessionid | number (8824748217892) appearing in the URL is session ID of our app and is used **to create links between app pages** by maintaining the same session state among them. Note that session ids are managed automatically by Oracle APEX. | | NO | = do not enter the debug mode. References debug flag, which is used to display app processing details. | | RP,RIR,4 | Placed in URL's ClearCache position, this argument **RP (Resets Pagination) for interactive report on Page 4**. RIR=Reset Interactive Report. Pagination =**info about numrows and currrownum within result set**. You control how pagination displays by making selections from **Pagination Type attribute** in Property Editor (prop palete u F6i) - style of links or buttons used to navigate to the next or previous page. Clear cache section can have RIR or CIR or RP to reset, **clear, or reset** pagination of primary default reports of all interactive report regions on the target page. | | IRGTE_ORDER_DATE | is used in itemNames position. IR (Interactive Report) string is used along with greater than and equal to operator (GTE), followed by an item name (ORDER_DATE - an item on Page 4). This argument acts as a filter and is used in conjunction with itemValue (&P1_THIS_MONTH. mentioned underneath) to only display current month's orders. In simple words it says: **Order date of interactive report is greater than or equal to item value**. | | &P1_THIS_MONTH. | Used in the itemValue position, the value stored in this hidden item is forwarded to the target page. **To create a filter** on an interactive report in a link, use the string IR\<operator>\_\<target column alias> in the ItemNames section of the URL and pass the filter value in corresponding location in the IORDER_DATEtemValues section of the URL. See section 2.7 in Chapter 2 for further details on Oracle APEX f?p syntax. Other operators you can use to filter an interactive report include: EQ = Equals (the default operator) LT = Less than GT = Greater than LTE = Less than or equal to GTE = Greater than or equal to LIKE = SQL LIKE operator N = Null To apply the filter, you must use correct date format mask in the SQL query for order_timestamp column. For example, if the Order Date column on Page 4 appears as 01-JAN-2017, then you must use 'DD/MON/YYYY' format mask. | <br /><br /> ### Set region-specific properties "Sales for This Month" region -> Click Attributes node -> Switch its **Template from "Standard" to "Badge List"** -> click **Template Options** -> set **Badge Size to 128px**, **Layout to Span Horizontally** -> click OK. By setting these region properties, the derived one row summarized report will be presented as a badge list, spanned horizontally. Also set Pagination Type to **No Pagination (Show All Rows)**. Click Save and **Run Page button** to see this **region with two badges (circles) on it displaying 1. current month's sales and 2. number of orders placed**. First badge - Current month's sales - acts as a link and leads you to Page 4 to display details of the summarized data. Since Page 4 will be created in Chapter 7, you will get Page Not Found message if you click this badge. <br /><br /><br /><a name="homereg3"></a> ## Home Page region 3 : "Sales by Product region" - pie chart [Top](#top).....[Home reg.1](#homereg1).....[Home reg.2](#homereg2).....[Home reg.3](#homereg3).....[Home reg.4](#homereg4).....[Home reg.5](#homereg5).....[Home reg.6](#homereg6)....[Home buttons](#hbuttons).....[Home styles](#hstyles) Page region 3 shows **sale figures (sums as pie slices) visible when you move the mouse pointer over pie slices of pie chart** for individual products. Create another region as previous region. <br /><br /> ### Set common region properties (attributes)** | | Property | Value | |-:| :------- | :------------ | | 1 | Title | **Sales by Product **| | 2 | Type | Chart | | | Location | Local Database | | | Type | SQL Query | | 3 | SQL Query | SELECT p.product_name \|\| ' [$' \| \| p.list_price \|\| ']' product, SUM(oi.quantity * oi.unit_price) sales FROM demo_order_items oi, demo_product_info p WHERE oi.product_id = p.product_id GROUP BY p.product_id, p.product_name, p.list_price ORDER BY p.product_name desc | | 4 | Start New Row | Off | | 5 | Column | 9 | | 5 | Column span | 4 | | 7 | Body Height (under Template Options) | 240px | <br /><br /> ### Set region-specific properties Click the Attributes sub-node under new region and set following properties. | | Property | Value | Help | |-:| :------- | :------------ | :------------ | | 8 | Type | Pie | | | 9 | Show (under Legend) | Off (default) | If you are creating a multi-series chart, then you can use legend (9) to identify each series on the chart. Using legend properties you can specify whether to display it, and if so, where it should be placed on the chart. You will use these properties in Chapter 8. | **Click the New sub-node under Series and set the following properties:** | | Property | Value | |-:| :------- | :------------ | | 10 | Location (under Source) | Region Source | | 11 | Label | PRODUCT | | 12 | Value | SALES | | 13 | Show (under Label) | On (Specifies **whether the label(s) should be rendered on the chart**) | <br /><br /><br /><a name="homereg4"></a> ## Home Page region 4 : "Sales by Category" region [Top](#top).....[Home reg.1](#homereg1).....[Home reg.2](#homereg2).....[Home reg.3](#homereg3).....[Home reg.4](#homereg4).....[Home reg.5](#homereg5).....[Home reg.6](#homereg6)....[Home buttons](#hbuttons).....[Home styles](#hstyles) Page region 4 will present sale figures - **bars for each product category : Men, Women, and Accessories**. This time, we will add a region using the drag and drop APEX feature. ***Drag Chart icon from Regions gallery and drop it under "Top Orders by Date region***. **Chart region will appear**. Place chart region at its proper location, if needed. <br /><br /> ### Set common region properties (attributes)** | | Property | Value | |-:| :------- | :------------ | | 1 | Title | **Sales by Category**| | 2 | Type | Chart | | | Location | Local Database | | | Type | SQL Query | | 3 | SQL Query | SELECT p.category Category, sum(o.order_total) Sales FROM demo_orders o, demo_order_items oi, demo_product_info p WHERE o.order_id = oi.order_id AND oi.product_id = p.product_id GROUP BY category ORDER BY 2 desc | | 4 | Start New Row | On | | 5 | Column | 1 | | 5 | Column span | 4 | | 7 | Body Height (under Template Options) | 480px | <br /><br /> ### Set region-specific properties Click Attributes sub-node under new region and set following properties. | | Property | Value | |-:| :------- | :------------ | | 8 | Type | Bar | | 9 | Show (under Legend) | Off (default) | **Click the New sub-node under Series and set the following properties:** | | Property | Value | Help | |-:| :------- | :------------ | :------------ | | 10 | Location (under Source) | **Region Source** | | | 11 | Label | CATEGORY | | | 12 | Value | SALES | | | 13 | Color (under Appearance) | #18A0C2 | or **Color Picker tool** - to change default chart color. | <br /><br /><br /><a name="homereg5"></a> ## Home Page region 5 : "Top Customers" region [Top](#top).....[Home reg.1](#homereg1).....[Home reg.2](#homereg2).....[Home reg.3](#homereg3).....[Home reg.4](#homereg4).....[Home reg.5](#homereg5).....[Home reg.6](#homereg6)....[Home buttons](#hbuttons).....[Home styles](#hstyles) **Top six customers** with highest orders and will present info **in text format**. Create a new region by **dragging Classic Report icon** from gallery and dropping it under "Sales by Category" region. Source of a Classic Report is **SQL query**. Each time page is rendered, APEX evaluates query and displays result within the region. Once you specify row and column properties using following table, region will appear next to the Sales by Category region. <br /><br /> ### Set common region properties (attributes)** | | Property | Value | |-:| :------- | :------------ | | 1 | Title | **Top Customers**| | 2 | Type | Classic Report (should be already set) | | | Location | Local Database | | | Type | SQL Query | | 3 | SQL Query | SELECT b.cust_last_name \|\| ', ' \|\| b.cust_first_name \|\| ' - '\|\| count(a.order_id) \|\|' Order(s)' customer_name, SUM(a.ORDER_TOTAL) order_total, b.customer_id id FROM demo_orders a, DEMO_CUSTOMERS b WHERE a.customer_id = b.customer_id GROUP BY b.customer_id, b.cust_last_name \|\| ', ' \|\| b.cust_first_name ORDER BY NVL(SUM(a.ORDER_TOTAL),0) DESC | | 4 | Start New Row | Off | | 5 | Column | 5 | | 5 | Column span | 4 | | 7 | Body Height (under Template Options) | 240px | Rendering tab -> expand Columns node under "Top Customers" region, and **click CUSTOMER_NAME column**. Set following properties to **transform this column into a link to provide drill-down** capability. **APEX specifies CUSTOMER_NAME column in Link Text attribute**. | | Property | Value | |-:| :------- | :------------ | | 8 | Type | Link | **Click No Link Defined under Target and set the following properties:** | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 9 | Type | Page in this app | | | 10 | Page | 7 | | | 11 | Name | P7_CUSTOMER_ID | This value refers to an item on Page 7 that will be populated with the value held in #ID# . It is forwarded to Page 7 from the Home page to display **selected customer profile**. | | 12 | Value | #ID# | references third column in above SELECT query. Standard procedure in APEX to **refer to a column value** is to enclose it between # symbols. To **refer page item we use substitution strings**. | | 13 | Clear Cache | 7 | | When we run this page, each customer's name appears as a hyperlink, clicking which calls customer's profile page (Page 7). We set Page attribute to 7, which is the page we want to navigate to. We also forwarded the customer?s ID (#ID#) to Page 7. Click **ORDER_TOTAL** column and set Format Mask to $5,234.10 = FML999G999G999G999G990D00. Select ID column and set **Type property (under Identification) to Hidden Column** to hide this column at run-time. <br /><br /> ### Set region-specific properties Click the Attributes sub-node under new region and set following properties. | | Property | Value | |-:| :------- | :------------ | | 1 | Pagination Type | No Pagination (Show All Rows) | | 2 | Maximum Row to Process (under Performance) | 6 | | 3 | Type (under Heading) | None | **Pagination is suppressed** since we want to see only six records in the region. We also set Heading Type to None to **suppress column headings**. Click Save and Run Page button to test the progress. <br /><br /><br /><a name="homereg6"></a> ## Home Page region 6 : "Top Products" region [Top](#top).....[Home reg.1](#homereg1).....[Home reg.2](#homereg2).....[Home reg.3](#homereg3).....[Home reg.4](#homereg4).....[Home reg.5](#homereg5).....[Home reg.6](#homereg6)....[Home buttons](#hbuttons).....[Home styles](#hstyles) Similar to Top Customers region - **create this region by copying the Top Customers region**. Displays **six top selling products**. **Right-click Top Customers region** -> **Duplicate** from context menu. Copy of source region will be appended just under it. <br /><br /> ### Set common region properties (attributes)** | | Property | Value | |-:| :------- | :------------ | | 1 | Title | **Top Products**| | 2 | Type | Classic Report (should be already set) | | | Location | Local Database | | | Type | SQL Query | | 3 | SQL Query | SELECT p.product_name\|\|' - '\|\|SUM(oi.quantity)\|\|' x' \|\|to_char(p.list_price,'L999G99')\|\|'' product, SUM(oi.quantity * oi.unit_price) sales, p.product_id FROM demo_order_items oi, demo_product_info p WHERE oi.product_id = p.product_id GROUP BY p.Product_id, p.product_name, p.list_price ORDER BY 2 desc | | 4 | Start New Row | Off | | 5 | Column | 9 | | 5 | Column span | 4 | | 7 | Body Height (under Template Options) | 240px | Expand the Columns node and **click PRODUCT column** to set the following properties: | | Property | Value | |-:| :------- | :------------ | | 8 | Type | Link | **Click No Link Defined under Target and set the following properties:** | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 9 | Type | Page in this app | | | 10 | Page | 6 | | | 11 | Name | P6_PRODUCT_ID | This value refers to an item on Page 7 that will be populated with the value held in #ID# . It is forwarded to Page 7 from the Home page to display **selected customer profile**. | | 12 | Value | #PRODUCT_ID# | references third column in above SELECT query. Standard procedure in APEX to **refer to a column value** is to enclose it between # symbols. To **refer page item we use substitution strings**. | | 13 | Clear Cache | 6 | | Click **SALES column** and set its Format Mask to $5,234.10. Select **PRODUCT_ID column** and set its Type property to **Hidden Column**. <br /><br /> ### Set region-specific properties Click the Attributes sub-node under new region and set following properties. | | Property | Value | |-:| :------- | :------------ | | 1 | Pagination Type | No Pagination (Show All Rows) | | 2 | Maximum Row to Process (under Performance) | 6 | | 3 | Type (under Heading) | None | Click Save and Run Page button to see how all six regions appear on Home page. **END creating all regions.** <br /><br /><br /> <a name="buttons"></a> ## 4.4 Create Buttons on top of each region [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....**Buttons**.....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) These buttons provide **drill-down** functionality and take user to relevant pages to dig further **details for summarized information**. Eg buttons **add, view...** - click "Add Order" btn in "Top Order by Date" region -> redirect to page 11 to add new order. ### 4.4.1 Button View Orders To view a list of all customer orders. **Right-click Top Orders by Date region** -> select Create Button from context menu. This way, **button will be created in selected region**. A **new node "Region Buttons"** will be added with a button. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | VIEW_ORDERS | | | 2 | Label | View Orders | appears as tooltip when you move over button at run-tim | | 3 | Region | Top Orders by Date | region where button will appear | | 4 | Button Position | **Edit** | over dozen values, try other options as well to observe different positions | | 5 | Button Template | Icon | button will be displayed as an icon | | 6 | Icon | **fa-chevron-right** | name of icon **">"** from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this app Page = 4 | | | | | | | If we click new button ">" : Sorry, this page isn't available Application "80858" Page "4" not found. ### 4.4.2 Button Add Order Calls Order Wizard (to be created in Chapter 7) to place a new order. **Right-click Region Buttons under the Top Orders by Date region** -> select Create Button. A new button will be added under previous one. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | ADD_ORDER | | | 2 | Label | Enter New Order | appears as tooltip when you move over button at run-tim | | 3 | Region | Top Orders by Date | region where button will appear | | 4 | Button Position | Edit | over dozen values, try other options as well to observe different positions | | 5 | Button Template | Icon | button will be displayed as an icon | | 6 | Icon | **fa-plus** | name of icon **"+"** from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this app Page = 11 Clear Cache=11 | | | | | | | ### 4.4.3 Button View Orders For This Month Drill-down into current month's order details. 1. drag "Icon" button from Buttons gallery 2. drop it under Sales for this Month region in EDIT position A new button will be added to this region. Link properties set here are similar to those set earlier in section 4.3.2.Figure 4-7 | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | VIEW_MONTH_ORDERS | | | 2 | Label | View Orders for This Month | appears as tooltip when you move over button at run-tim | | 3 | Region | Sales for This Month | region where button will appear | | 4 | Button Position | Edit | (already set) over dozen values, try other options as well to observe different positions | | 5 | Button Template | Icon | (already set) button will be displayed as an icon | | 6 | Icon | **fa-chevron-right** | name of icon **">"** from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this Application Page = 4 Name = IRGTE_ORDER_DATE Value = &P1_THIS_MONTH. Clear Cache = RIR,4 | | | | | | | ### 4.4.4 Button View Customers on Page 2 of app. You?ll place two buttons in the Top Customers region. **Create these buttons using either of the two methods applied above**. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | VIEW_CUSTOMERS | | | 2 | Label | View Customers | appears as tooltip when you move over button at run-tim | | 3 | Region | Top Customers | region where button will appear | | 4 | Button Position | **Edit** | over dozen values, try other options as well to observe different positions | | 5 | Button Template | Icon | button will be displayed as an icon | | 6 | Icon | **fa-chevron-right** | name of icon **">"** from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this app Page = 2 | | | | | | | ### 4.4.5 Button Add Customer call Page 7 "Customers" blank form Target page will appear **on top of the Home page (as a modal dialog)**. **Right-click VIEW_CUSTOMERS button** -> select **Create Button**. Set following properties for new button. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | ADD_CUSTOMER | | | 2 | Label | Add Customer | appears as tooltip when you move over button at run-tim | | 3 | Region | Top Customers | region where button will appear | | 4 | Button Position | **Edit** | over dozen values, try other options as well to observe different positions | | 5 | Button Template | **Icon** | button will be displayed as an icon | | 6 | Icon | **fa-plus** | name of icon **"+"** from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this app Page = 11 Clear Cache=11 | | | | | | | ### 4.4.6 Button View Products leads to main products page 3 - list of all products Two buttons in the Top Products region (same as in Top Customers region). | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | VIEW_PRODUCTS | | | 2 | Label | View Products | appears as tooltip when you move over button at run-tim | | 3 | Region | Top Products | region where button will appear | | 4 | Button Position | **Edit** | over dozen values, try other options as well to observe different positions | | 5 | Button Template | **Icon** | button will be displayed as an icon | | 6 | Icon | **fa-chevron-right** | name of icon ">" from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this app Page = 3 | | | | | | | ### 4.4.7 Add Product Button calls Page 6 to add a new product | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | ADD_PRODUCT | | | 2 | Label | Add Product | appears as tooltip when you move over button at run-time | | 3 | Region | Top Products | region where button will appear | | 4 | Button Position | **Edit** | over dozen values, try other options as well to observe different positions | | 5 | Button Template | **Icon** | button will be displayed as an icon | | 6 | Icon | **fa-plus** | name of icon "+" from the APEX's repository | | 7 | Action | Redirect to Page in this App | | | 8 | Target | Type = Page in this app Page = 6 Clear Cache=6 | | | | | | | At this stage, all the seven buttons are placed at their proper locations with expected functionalities and are ready for partial test. These buttons **will be productive after creating pages indicated in their Target properties**. <br /><br /><br /> <a name="pgstyles"></a> ## 4.5 Styling Page Elements - 6 regions light gray [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....**PgStyles**.....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) CSS provides way to control style of a web page without changing its structure. When used properly, a CSS separates visual properties such as color, margins, and fonts from the structure of the HTML document. APEX includes themes containing templates to reference their own CSS. The style rules defined in each CSS for a particular theme also determine the way reports and regions display. CSS can be added to APEX apps inline, as CSS file(s) or through ThemeRoller. Depending on your requirements, you can add CSS to your app at the: 1. Page Level 2. Page Template Level 3. Theme Style Level 4. Theme Level 5. **User Interface Level** - In this exercise Here you?ll upload a custom CSS file carrying just one rule to style all six regions of the home page. The file named **AppCss.css** available in the source code contains **following rule, which creates a rounded border and places inset shadow around regions**. For more details on CSS, see Chapter 7 section 7.6.1. .region {background:white;border-radius:10px 10px 10px 10px;box-shadow: inset 0px 0px 30px #dfdbdf} To apply CSS at user interface level: 1. **Shared Components page** -> Files section -> Static App Files 2. Click Upload File button 3. click **Choose Files**, select **AppCss.css** file from the source code and click Upload. The css file will be added to the static app files listing. **Copy Reference URL entry #APP_IMAGES#AppCss.css** appearing on this page to your clipboard. **APP_IMAGES substitution string** is used to **reference uploaded images, JS, and CSS specific to given app** and are not shared over many apps. Recall that you used this substitution string earlier in chapter 3 to reference app logo. 4. Add the CSS file to User Interface : **Shared Components User Interface section** -> **User Interface Attributes**. 5. On User Interface tab, click **Cascading Style Sheets sub-tab** and press Ctrl+V to append the reference text in File URLs box **under existing URL** : ``` #APP_IMAGES#app-icon.css?version=#APP_VERSION# #APP_IMAGES#AppCss.css ``` 6. Click Apply Changes. 7. Finally, you have to **apply the CSS rule to your region**. Open home page (Page1) of your app and select first region - **Top Orders by Date**. In the properties pane, scroll down to the **Appearance section** and enter **region** (a class defined in the AppCss.css file) in **CSS Classes attribute**. CSS allows you to specify your own selectors called "id" and "class". 1. **id selector** is used to specify **style for single, unique element**. It uses id attribute of HTML element, and is defined with **"#" identifier**. 2. **class selector** is used to specify a **style for a group of elements**. This means you can set a particular style for many HTML elements with the same class. It uses HTML class attribute, and is defined with **"." identifier.** Add the region class to the CSS Classes property of the remaining five regions. Test Your Work Click the Save and Run Page button to see the Home page, which should now look similar to the one illustrated in Figure 4-1 at the beginning of this chapter. <br /><br /><br /> ### Summary of chapter 4 "Home page" declarative (functional) development We added contents to a blank page, modified properties to customize look and feel of this page. This is uniqueness and beauty of Oracle APEX that allows you to **create pages rapidly without writing tons of code**. Oracle APEX features you learned : 1. Region - We added **six regions (stacked canvases)** to display different types of contents : different types of charts, badge list, and classic reports to populate these regions via simple SQL statements. 2. **12 columns grid Layout** - to arrange multiple regions on a page. 3. **URL & Links** - link **app pages** together by setting some properties. How APEX formulates URL and passes values to target page using some link properties. 4. Buttons can also be used to link application pages. You created a few buttons to access different application pages. 5. Apply Styles - You learned how to **add custom styles to page elements through user interface level**. In the next chapter, you will learn about **Interactive Grid** and how to create **web forms** to receive user input. <br /><br /><br /><br /><br /><br /><a name="cust"></a> # 05. Module Customers 2 pages tbl ID=2 CRud & form ID=7 crUD - profile page 133/419 [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....**Cust**.....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) ## 5.1 CRUD DEMO_CUSTOMERS tbl 1. R Browse and search customer records 2. U Modify customers profiles 3. C Add record of a new customer to DB 4. D Remove a customer from the database Customers info is used in other app segments (**app modules**) eg customer orders and invoices. You can evaluate how much business you have done with your customers either by **location or by product**, as you did in previous chapter where you created Customers region on **page ID=1 **Sales web app. ## 5.2 Page Customers tbl ID=2 - CRud - main page of Cus. module - IG (interactive grid) Page ID=1 Sales web app - was created by App Builder wizard at the time when app was created. Other pages in this app will be created manually with help of **wizards and copy utility**. Customers who have some existing orders cannot be Deleted - see chapter 2 section 2.10 step 11. Each **customers name appears as link in interactive grid** -> form page profile of selected customer. Create two module pages via built-in wizard: 1. Main App Builder interface -> click "**Sales Web Application's Edit icon**" (A) -> click "**Create Page**" button (B). ### Create tbl IG page ID=2, Editing Enabled=Off (for "On" see [Sample Interactive Grids](#sampleIG)) >TIP: To **delete page**, open page in Page Designer by clicking its name -> select **Delete from top-right Utils menu**. 2. On first wizard screen, select **"Report"** option -> **report of customers in an interactive grid**. 3. On next wizard screen, **click Interactive Grid**. This screen presents sub-categories of reports and requires a single selection the report will base on. The option you selected here means an **interactive grid will act as a report** to display all customers from DB. >Up to version 5.0 APEX used **IR (Interactive Report)** feature to present data tbl. Since version 5.1 - new feature **IG (Interactive Grid)** similar to IR + **clicking on a cell** and editing its value (Clipper Dbedit !). IG introduces fixed headers, frozen columns, scroll pagination, multiple filters, **sorting**, aggregates, computations... Supports all **item types and item type plug-ins**. You can **create master-detail relationships to any number of levels deep and across**. See section 5.6. 4. On the next wizard screen, set following ### Properties of IG page | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Page Number | 2 | Main page of this module (form page to be created next will have number 7) | | 2 | Page Name | Customers | | | 3 | Page Mode | Normal | How you want to see page. It has two options: 1. **Normal** Dialog. New pages default to Normal. When you call a normal page, it replaces an existing page appearing in your browser. 2. **Modal** Dialog is stand-alone page, which appears on top of its calling page and doesn't allow users to do anything else unless it is closed. A modal page can be displayed only on top of another page. | | 4 | Breadcrumb | Breadcrumb | Breadcrumb shared component was created by the App Builder when you created this app earlier (see Shared Components -> Navigation > Breadcrumbs). In this step, you selected the same breadcrumb component and added an entry name (Customers) to it. Take a look at Figure 5-1 and see where the provided entry name appears in the breadcrumb region. We use breadcrumbs as a **second level of navigation** at the top of each page - hierarchical list of links indicates where the user is within the app from a hierarchical perspective to **switch to any level**. | | 5 | Parent Entry | Home (Page 1) | To create hierarchy in this app, you selected Home menu entry as Parent Entry for this page. | | 6 | Entry Name | Customers | | 5. On **Navigation Menu wizard screen** ### Set menu item to call this page 1. set Navigation Preference = Identify an existing navigation menu entry for this page 2. set Existing Navigation Menu Entry = Setup 3. click Next. This step will make **Setup entry active in the main navigation menu** (created in Chapter 3, section 3.2.1) **when this page is accessed**. 6. On **Report Source screen**, set following properties. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Editing Enabled | **Off** | form pg ID=7 edits cust records. Examples of editing rec. in interactive grid see later in this ch. | | 2 | Source Type | Table | Tbl data to populate this interactive grid | | 2 | Table/View Owner | | accept displayed value of Oracle **schema** (POSSYS) to which you are connected. | | 2 | Table/View Name | DEMO_CUSTOMERS (table) | Once you select a schema, all tables within that schema are populated in Table/View Name drop-down list from where you select a table - DEMO_CUSTOMERS in the current scenario whose data will be displayed in the interactive grid. Note that in the current scenario **you can select only one table** from the provided list. | If not visible, click the arrow icon next to the Column section to see the table columns. When you choose a table, **all the columns from that table are selected (moved to the right pane in the Columns section)**. For this exercise, leave the following columns in the right pane and **exclude others by moving them to the left pane using Ctrl+click and the left arrow icon**. Here are the columns we want to show in the interactive grid. Cust_First_Name, Cust_Last_Name, Cust_Street_Address1, Cust_Street_Address2, Cust_City, Cust_State, and Cust_Postal_Code. 7. Click **Create button** to finish report page creation process. Page Customers tbl ID=2 is created and its structure is presented in Page Designer. Only significant aspect of this page is **"Customers"** Interactive Grid region under : **Rendering -> Regions -> Content Body node** to your left. Wizard created this region with all columns you specified in step 6 - see **SQL Query box** in Page Designer. All these columns appear under Columns node. Properties in the **Interactive grid's Attributes** node control how an interactive grid works. For example, developers use these properties to determine if end-users can edit the underlying data, configure report pagination, create error messages, configure toolbar, use download options, control if and how users can save an interactive grid, and add Icon and Detail Views to the toolbar. You will go through these properties later in this chapter. For now, walk around the Page Designer to observe page components and relevant properties. Click Application eg 145615(=appID) breadcrumb at top-left to **leave Page Designer interface**. ## Create Page ID=7 to carry form "CrUD Customers" 1. Click **Create Page button** -> select **"Form"** option -> click another Form option on next wizard screen -> creates form page based on DB table. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Page Number | 7 | **Page to carry form to CrUD Customers** | | 2 | Page Name | Customer Details | | | 3 | Page Mode | **Modal** Dialog | stand-alone page, which appears on top of the calling page. Oracle APEX page can be created as dialog, which supports for all the functionality of a normal page, including computations, validations, processes, and branches. | | 4 | Breadcrumb | | | 5 | Parent Entry | Customers (Page 2) | called from Page 2 | | 6 | Entry Name | Customers Details | | 2. On the Navigation Menu screen, set "Navigation Preference" = **Identify an existing navigation menu entry** for this page, set "Existing Navigation Menu Entry" = Setup, and click Next. 3. On the Source screen, set the following properties and click Next. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Data Source | Local DB | | | 2 | Source Type | Table | | | 2 | Table/View Owner | | accept displayed value of Oracle **schema** (POSSYS) to which you are connected. | | 2 | Table/View Name | DEMO_CUSTOMERS (table) | | 4. This time, select all columns from DEMO_CUSTOMERS tbl to display **all of them in the input form (Page 7)** to populate backend DB tbl. For "Primary Key Type", select second option **Select Primary Key Column(s)**. Then, set first "Primary Key Column" attribute to **CUSTOMER_ID**. **Click "Create" button** to complete form page creation process. >In this step, you specified PK (primary key) column col or set of cols that uniquely identify record in tbl. Note that in current scenario PK col for cust tbl will be populated using DEMO_CUSTOMERS_SEQ Sequence object through BI_DEMO_CUSTOMERS **trigger**. Trigger fires when you insert a new customer. To browse this trigger, select SQL Workshop -> Object Browser -> Tables -> click on DEMO_CUSTOMERS table and then click the SQL tab. **Sequence** is a database object that automatically generates PK values for every new cust row. Rows are identified using either PK defined on tbl, or **ROWID pseudo column**, which uniquely identifies row in a tbl. **Forms support up to 2 columns in PK**. For tables using primary keys with more than two columns, ROWID option should be used. For further details, see Chapter 2. 5. Access main App Builder interface by **clicking application ID breadcrumb** to see **two new pages** (Customers and Customer Details) with their respective page numbers. **Click Customer Details (Page 7)** to open its definitions in Page Designer. **Expand Pre-Rendering node** and rename process **Initialize form Customer Details as "Initialize Customer Details"**. Click Processing tab and rename process **Process form Customer Details to "Process Customer Data"**. NOTE: If you see a different process name, then there is nothing to worry about as it sometimes happens due to change in APEX version. APEX is a low-code application development platform. Two pages you just created have everything you need to view and manipulate data. Customers Page 2 contains Interactive Grid in which you can view all customers data. Click Customer Details Page 7 to open it in Page Designer. On Rendering tab, expand Pre-Rendering node. Here, you will see an auto-generated process named **Initialize Customer Details of Form Initialization type**. This Process is responsible to initialize form region items. Initialization can either be **fetching data from region source**, using PK value(s) or **simple initialization** of form region items. Process fetches and displays data in page items when you select customer by clicking corresponding **edit icon on the reports page** and it initializes page items **when you create a new customer record**. Customer Details region is a **Form type region**, which connects to local DB and fetches data from DEMO_CUSTOMERS table into relevant page items listed under Items node. Same page items are used to receive user input when new customer record is created. In Buttons section, you will see a **bunch of auto-generated buttons** (Cancel, Delete, Save, and Create). **DB Action** property of these buttons specify function each button performs. When you click button (eg CREATE), corresponding DB action is submitted to process named **Process Customer Data**, which resides under the Processing tab. This process is of Automatic Row Processing (DML) type and performs CrUD action on form region - Customer Details region in current scenario. ## 5.3 Modify Tbl Customers Page ID=2 Main page of this module (Page 2) holds interactive grid generated by wizard with some default data source values. In next steps we **change default data source values** and **produce custom output using SQL query**. ### 5.3.1 Modify Customers Region Prop. Cols hdr, order, filter and cust name as link 1. In App Builder, click Customers page (Page 2) to open it in the Page Designer for modification. ## Cols hdr, cols order, cols filter in tbl Customers 2. **Click Customers region under Content Body node**. Standard method to modify properties of page component is to click corresponding node. This action refreshes Properties section (located to your right) with properties of selected page component for alteration. 3. Change **Type (under Source section)** = SQL Query to see **default query generated for interactive grid**. ``` select ROWID, CUSTOMER_ID, CUST_FIRST_NAME, CUST_LAST_NAME, CUST_STREET_ADDRESS1, CUST_STREET_ADDRESS2, CUST_CITY, CUST_STATE, CUST_POSTAL_CODE, CUST_EMAIL, PHONE_NUMBER1, PHONE_NUMBER2, URL, CREDIT_LIMIT, TAGS from DEMO_CUSTOMERS ``` Enter following SQL statement in SQL Query text area, replacing existing one: ``` SELECT customer_id, cust_last_name || ', ' || cust_first_name customer_name , CUST_STREET_ADDRESS1||decode(CUST_STREET_ADDRESS2, null, null, ', '||CUST_STREET_ADDRESS2) customer_address , cust_city, cust_state, cust_postal_code FROM demo_customers ``` Decode Syntax: decode( expression , search , result [, search , result]... [, default] ) If default is omitted, Oracle returns null. 4. Expand Customers region -> expand Columns node. Click column eg CUSTOMER_NAME and **change its heading (under Heading section in Properties pane) to Name**. Change headings of other cols : Address, City, State, and Postal Code 5. In Columns node, click the **CUSTOMER_ID** column, and change it Type property from **Number Field to Hidden** to hide col at runtime. PK cols are added to DB tbls to enforce data integrity and are not displayed in apps. This is why such column's Type property is set to hidden to make them invisible at runtime. 6. **Run page**. **Click Actions menu** (A) - select Columns. When you click column in left pane, right pane (D) shows its name and width. You can input a numeric value to **change width of col**. Using arrow icons (E), arrange selected columns in following **order**: Name, Address, City, State, and Postal Code 7. Click Save button in the Columns window to apply the changes. 8. **After you modify interactive grid in runtime save it :** Click Actions menu -> Save from Report option, otherwise you?ll lose the applied settings when you access it later. 9. **Click Edit Page2 (F) in the Developer Toolbar at the bottom of page** to access Page Designer. ## Cust name as link in tbl Customers 10. Click CUSTOMER_NAME column to set properties: **transforming cust name col into link that will lead to Page 7 cust. form**. >When you click customer's name in interactive grid report at runtime: 1. ID of that cust is stored in substitution string (&CUSTOMER_ID.) (G) 2. and is forwarded to corresponding page item (P7_CUSTOMER_ID) (H) on Page 7, which displays cust profile using this ID. >You created similar kind of link in Chapter 4 for region "Sales for this Month". Scroll down to Link section and **click "No Link Defined"** under Target to bring up **Link Builder dialog box** -> set link properties : | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Type | Page in this app | | | 2 | Page | 7 | | | 3 | Name | P7_CUSTOMER_ID | This value refers to an item on Page 7 that will be populated with the value held in #ID# . It is forwarded to Page 7 from the Home page to display **selected customer profile**. | | 4 | Value | &CUSTOMER_ID. | references third column in above SELECT query. Standard procedure in APEX to **refer to a column value** is to enclose it between # symbols. To **refer page item we use substitution strings**. | | 5 | Clear Cache | 7 | | Use LOVs (I) in Set Items section to select item name (3) and value (4). 11. **Close Link Builder dialog box using OK button**. 12. **Save and run page**. **Cust Name col will now appear as link**. Click any customer name to see details on Page 7, which pops up on top of Page 2. ### 5.3.2 Button "Create" in tbl Customers To call Page 7 with a blank form from Page 2 - Customers : 1. Rendering tab to your left click Customers interactive grid region -> set its **Template property to Standard** (was Interactiv). Selected template **will place title and border for interactive grid region**. Right-click Customers region and from context menu select **Create Button**. Button named New will be added. Set properties for new button : | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | CREATE | | | 2 | Label | Create Customer | appears as tooltip when you move over button at run-time | | 3 | Button Position | **Copy** | over dozen values, try other options as well to observe different positions | | 4 | Hot | On | renders the button in dark color | | 5 | Action | Redirect to Page in this App | (under Behavior) - **Creates link** to call Page 7. | | 6 | Target | Type = Page in this app Page = 7 Clear Cache =7 | **Creates link** to call Page 7. Clear Cache prop. makes all items on target pg 7 blank | 2. **Save and run Page 2**, which should look similar to Figure 5-1. 3. Click Create Customer button to call Customer Details Page 7 on top of calling page as a modal dialog. ### 5.3.3 Button "Call PHP page" to Call PHP script - report from APEX https://www.youtube.com/watch?v=WLE9_1I_nA0 Like 5.3.2, properties are : | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | CallPHPpge | | | 2 | Label | **Call PHP page** | appears as tooltip when you move over button at run-time | | 3 | Button Position | **Copy** | over dozen values, try other options as well to observe different positions | | 4 | Hot | Off | if On : renders the button in dark color | | 5 | Action | Redirect to URL | (under Behavior) - **Creates link** to call PHP Page | | 6 | URL | "http://192.168.../" or "http://dev1:8083/fwphp/www" ?param1=&P26_PARAM | **Creates link** to call PHP Page | Open in new tab : ? ## 5.4 Modify properties of crUD form Customer Details - Page 7 With Page 7 cust. form being displayed in browser, **click Edit Page 7 in Developer Toolbar** at pge bottom to call this pge in PageDesigner. ### 5.4.1 Modify Page Items Properties >**Like region placement** in 12 cols grid layout, done for six Home pge regions, pge items can also be placed using APEX's grid layout, as follows. >**Width** property sets items width on page. >If **Value Required** is set to Yes and **page item is visible**, APEX **automatically performs NOT NULL validation when page is submitted** and **you are asked to input a value** for field. If you set Value Required to No, no validation is performed and a NULL value is accepted. Value Required attribute works in conjunction with **Template = Required** to signify (ozna?i) mandatory items visually. ### Page Id=7 Customer Details (profile) items properties and values Page flds are in 2 columns, only "Tags" fld spans both cols. Save your changes and call this Page 7 by **clicking any customer's name** on Page 2. It should come up with selected customer profile (Figure 5-6 Customer Details Page). Click each item under Items node and apply following properties. 1. P7_CUST_FIRST_NAME Label=**First Name**.....Sequence=20.....Start New Row=On.....Column=Automatic.....Column Span=Automatic .....Template=Required.....**Label Column Span=2 (becomes visible in Layout section only after setting Template property) ** .....Width=50.....Value Required=On 2. P7_CUST_LAST_NAME Label=**Last Name**.....Sequence=30.....Start New Row=**Off**.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Required.....**Label Column Span=2** .....Width=**50**.....Value Required=On 3. P7_CUST_STREET_ADDRESS1 Label=**Street Address**.....Sequence=40.....Start New Row=On.....Column=Automatic .....Column Span=Automatic.....Template=**Optional**.....Label Column Span=2 .....Width=50.....Value Required=Off 4. P7_CUST_STREET_ADDRESS2 Label=**Line 2**.....Sequence=50.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=50.....Value Required=Off 5. P7_CUST_CITY Label=City.....Sequence=60.....Start New Row=On.....Column=Automatic .....**Column Span=6**.....Template=Optional.....Label Column Span=2 .....Width=50.....Value Required=Off 6. See 5.4.2 Change cust. column "P7_CUST_STATE" to hold predefined LOV! States list 7. P7_CUST_POSTAL_CODE Label=Zip Code.....Sequence=80.....Start New Row=On.....Column=Automatic .....Column Span=6.....Template=Required.....Label Column Span=2 .....Width=8.....Value Required=On 8. P7_CREDIT_LIMIT Label=Credit Limit.....Sequence=90.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Required.....Label Column Span=2 .....Width=8.....Value Required=On 9. P7_PHONE_NUMBER1 Label=Phone Number.....Sequence=100.....Start New Row=On.....Column=Automatic.....Column Span=Automatic .....Template=Optional.....Label Column Span=2.....Width=12.....Value Required=Off 10. P7_PHONE_NUMBER2 Label=Alternate No.....Sequence=110.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=12.....Value Required=Off 11. P7_CUST_EMAIL Label=Email.....Sequence=120.....Start New Row=On.....Column=Automatic .....Column Span=Automatic.....Template=Required.....Label Column Span=2 .....Width=50.....Value Required=On 12. P7_URL Type=Text Field.....Label=URL.....Sequence=130.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=50.....Value Required=Off 13. P7_TAGS Type=Textarea.....Label=Tags.....Sequence=140.....Start New Row=On.....Column=Automatic .....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=100.....Value Required=Off ## 5.4.2 Customer's page column "P7_CUST_STATE" to hold app-shared dynamic LOV! States list. app-shared means defined in app shared componebts in one place and reusable in all app modules pages. ### 1. In Shared Components to fetch State names from DEMO_STATES table 1. **Shared Components** -> Other Components section -> **"Lists of Values" APEX page** -> Click Create button 2. Select **From Scratch** option and click Next 3. Enter **States** in Name box, select **Dynamic for its type**, and click Next 4. On List of Values Source screen, select **SQL Query for Source Type**, and enter following query in **Enter SQL SELECT statement** box. Click Next ``` both VARCHAR2 30 : select state_name display_value, st return_value from demo_states order by 1 --select state_name display_value, state_id return_value from demo_states order by 1 ``` 5. On final Column Mappings screen, select RETURN_VALUE for Return Column, DISPLAY_VALUE for Display Column and **click Create button** to create the LOV. <br /><br /> ### 2. P7_CUST_STATE prop. Label=**State**.....Sequence=70.....Start New Row=**Off**.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=**Required**.....**Label Column Span=2** .....Width=make it **null** (this item will be transformed into a select list).....Value Required=On <br /><br /> ### 3. Type Text Field change to -> Select List and Attach STATES LOV! to it (was created in 3.4.3) 1. In Page Designer interface, **click P7_CUST_STATE item**. 2. Change its Type property from **Text Field to Select List**. 3. Set Type (under List of Values) to **Shared Components** and **select STATES for LOV**. This step ***attaches States LOV to page item***. 4. **Turn off "Display Extra Values" property**. An item may have a **session state value**, which does not occur in its LOV definition. Select whether this LOV should display this extra session state value. If you choose not to display this extra session state value and there is no matching value in list of values definition, first value will be selected value. Eg while creating new customer record you will see - Choose a State - as the first value in the list. This value is added to the list in following steps. 5. **Turn on Display Null Value property**, which is default. Display Null Value property makes it possible for a user to choose a null value instead of one of the list items. If you set this property to Yes, additional properties appear on the screen for you to specify display value for this new entry. Eg "Choose State". 6. **Enter - Choose State - in Null Display Value**. This step, along with the previous one, **generates a placeholder** that appears on top of the LOV asking for a selection whenever you call this page to create a new customer record. 7. Save your work. <br /><br /> ### 5.4.3 Apply Input Mask to Items Modify the **two phone number items in cust. form pgID=7** and set their **Value Placeholder property** (under Appearance) to 999-999-9999. When a new customer record is added, this placeholder is shown in the two phone number items to receive input in the specified format. As you type in values, the placeholders will be replaced by the numbers entered. ### 5.4.4 Create Validation 1 (logic control of user input) - Check Customer field "P7_CREDIT_LIMIT" Field "Credit Limit" is used to assign a credit cap to each customer with a figure of $5,000. **If you enter a value more than the assigned cap**, you'll be prevented by presenting an appropriate message. NOTE: Validation error messages display when : 1. validation fails the equality test 2. or evaluates to FALSE 3. or non-empty text string is returned. In left pane of Page 7 cust.form : click **Processing icon (was tab)** -> **right-click Validating node** -> **Create Validation** from context menu (Figure 5-7) -> Set following properties for this new validation : | | Property | Value | Help |-:| :------------------------ | :----------------------- | :------------ | | 1 | Name | **Check Credit Limit** | should be meaningful ! | | 2 | Type | PL/SQL Expression | expression in valid PL/SQL syntax **that evaluates to true or false** | | 3 | PL/SQL Expression | **:P7_CREDIT_LIMIT <= 5000** | If true customer record is saved to DB. Note that **you use bind variables** (item name preceded with a colon) when you reference value of a session state variable from within PL/SQL code. | | 4 | Error Message | Customer's Credit Limit must be less than or equal to $5,000 | | ### 5.4.5 Create Validation 2 - "Can't Delete Customer with Orders" This check is performed to **retain DB integrity from front-end**. Validation is performed using custom PL/SQL function, which returns either a true or false (deletion process is aborted) value. Validation is **associated to DELETE button in last attribute in following table**, which means that validation will be performed only **when Delete button is pressed**. In left pane of Page 7 cust.form : click **Processing icon (was tab)** -> **right-click Validating node** -> **Create Validation** from context menu (Figure 5-7) -> Set following properties for this new validation : Setting a condition type involves selecting a condition from list that **must be met in order for a validation to be processed**. | | Property | Value | Help |-:| :------------------------ | :----------------------- | :------------ | | 1 | Name | **Can't Delete Customer with Orders** | should be meaningful ! | | 2 | Type | PL/SQL Function Body (Returning Boolean) | fn PL/SQL **that returns true or false** | | 3 | PL/SQL Fn Body (Ret. Boolean) | SEE BELOW | If true customer record is deleted in DB. Note that **you use bind variables** (item name preceded with a colon) when you reference value of a session state variable from within PL/SQL code. | | 4 | Error Message | Can't Delete Customer with Orders | | | 5 | When Button Pressed | DELETE | You can control **when and if validation (or process) is performed by configuring When Button Pressed and Condition Type attributes of validation**. If you want a validation to execute **only when specified button is clicked**, select a button from the list. | **| 3 | PL/SQL Fn Body :** ``` begin for c1 in ( select 'x' from demo_orders where customer_id = :P7_CUSTOMER_ID ) loop RETURN FALSE; end loop; RETURN TRUE; end; ``` ### wbp cre_row >"Customer Details" - Page 7 - observe **auto-generated buttons (Cancel, Delete, Save, and Create)** with default functionalities. Eg when you fill in form with new customer's record and click Create button, record is **added to DB table using a built-in process** - discussed in a while. ### In Pre-Rendering (pre_form crUD costomer) we read_by_id Expand **Pre-Rendering** node (under root node - Page 7: Customer Details). Here, you will see **process of Form Initialization type created by wizard** - purpose of which is to fetch row from DB by key, and put row values into pge items Px\_.... Eg when you click customer name in Interactive Grid on Page ID=2, ID of that customer is used by this process to fetch and display details of the selected customer on page ID=7. ### Px\_... flds are F[orm] flds Wizard also created individual **input items** (under Customer Details region) for each tbl column. 1. Source **Type ** property of these cols is set to **DB Column** 2. **DB Column property is set to column name in table**. Eg two properties set for P7_CUST_FIRST_NAME page item tells the ARF process to set item with value retrieved from CUST_FIRST_NAME table column. ### Shared Component confirmation dialog box before deleting Click root node (Page 7: Customer Details) and scroll down to Function and Global Variable Declaration section in Property Editor, you'll see a **global variable defined as var htmldb_delete_message**. This variable was generated automatically along with a corresponding **shortcut named DELETE CONFIRM MSG** (in **Shared Components** > Other Components > Shortcuts) to control record deletion process by presenting a **confirmation dialog box before deleting** a customer?s record (other app pages will also use it). ### crUD process of form items with source of type DB Column Note that Delete button was created by wizard with **SQL DELETE DB action**. Similarly, INSERT and UPDATE DB actions were set automatically for Create and Save buttons, respectively - see **DB Action attribute under Behavior**. When clicked, these buttons perform selected SQL operations to trigger specified DB action within **built-in Automatic Row Processing (DML) type process**, also created automatically by wizard on Processing tab. This process is located under **Processing > Processes node** and it is responsible to CrUD rows into backend database table. This process is used to process form items with source of type DB Column. This process has three advantages : 1. you are not required to provide any SQL coding 2. APEX performs DML processing for you 3. this process automatically performs **lost update detection** which ensures data integrity in apps where **data can be accessed concurrently** In addition, wizard created **Dynamic Action (Cancel Dialog)** to close this form when Cancel button is clicked. These are some of the beauties of declarative development that not only generates **basic functionalities of an app**, but on the same time **doesn't limit our abilities to manually enter specific and tailored code (demonstrated in subsequent chapters), both on the client and server sides** to answer our specific needs. ### Test Your Work Save and run app. Access this module by clicking **"Manage Customers" menu item (under "Setup")**. You?ll see Page 2 - Customers (Figure 5-1), carrying an interactive grid. Grid has : 1. **search bar** (search string in report ) comprising : 2. magnifying glass - drop down list to limit your search to a specific column 3. text area 4. Go button - Type eg albert in text area and click Go button - shows rows. **Click remove filter icon** to reinstate the grid to its previous state. Alternatively, you can **click Reset button** appearing on top-right of the grid. #### Actions menu in runtime See Chapter 7. Couple of save options under Actions -> Report in runtime : 1. First one **Save** is used when you customize report by **applying filters or moving columns**. Otherwise you'll lose applied settings when you subsequently view same report. 2. Clicking second option **Save As** presents a window with **Type drop-down list** and **Name text box**. Developers can save **four types of reports** Primary, Alternative, Private, and Public : 1. **Primary report** is initial interactive grid report rendered in your browser. Default Primary report (you are looking at) is created by app developer. It **cannot be renamed or deleted**. Primary report is displayed on toolbar under heading Default. 2. **Alternative report** enables developers to create **multiple report layouts**. **Only developers** can save, rename, or delete an Alternative Report. An alternative report is based on default primary report and is rendered in a different layout (see Section 7.3.3 in Chapter 7). 3. **Private report** can be viewed, saved, renamed, or deleted **by user who created it**. 4. In contrast, when you save a report as **public**, **all users can view it**. By default, end-users cannot save Public reports. To enable support for Public reports, developers edit the report attribute and enables users to save it as public report - see step 7 Section 7.3.1 in Chapter 7. After saving, all these reports display on the Saved Reports list on toolbar. Customer name column appears as a link in Page 2 -click it to modify row (Figure 5-6).Check credit limit validation by entering more than 5000 in Credit Limit box. NOTE: You might encounter a **primary key violation message while creating first customer record**. This is because the **Sequence object for this table is created with an initial value of 1**. When you try to save the first customer record, 1 is assigned as its primary key, which already exists in the table. To cope with this situation, developers drop and re-create auto-generated sequence objects with a **higher START WITH value**. To keep things simple, I'd suggest beginners to **click the Create button on the form page several times**. After few clicks row will be saved. ## 5.5 When_window_closed - refresh Viewtbl after crUD Viewfrm is closed Add Dynamic Action to refresh interactive grid region (Customers, Page 2) when modal dialog page (Page 7) is closed. When_window_deactivated is when mouse clicks on other window. After C customer row or U existing one, **interactive grid doesn't reflect CrUD**, page doesn't get refreshed. Manually refresh your browser window eg F5. More professional approach is to refresh page automatically using dynamic action. 1. Open Page 2 (Customers) in Page Designer and click **Dynamic Actions icon (was tab)** appearing in left pane. 2. Right-click **Dialog Closed** node and select Create Dynamic Action from context menu. Figure 5-8. Set following properties for this dynamic action. **Property Value** 1. Name Refresh Interactive Grid 2. Selection Type Region 3. Region Customers 3. **Click Refresh sub-node** and set Region to Customers. Refresh is an **action which executes when the condition evaluates to true** - ee, **when modal dialog page is closed**. Save page and run it. Now you will see immediate reflection of your modifications in interactive grid. <br /><a name="gosampleIG"></a> ## 5.6 IG : Learn IG - install app "[Sample Interactive Grids](#sampleIG)" from App Gallery <br /><br /><br /><br /> <a name="prod"></a> # 06. Page Set Up Products Catalog page 177/419 [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....**Prod**.....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) ## 6.1 About Products Setup **Main Products Page 3, CRud product** - Figure 6-1 Products Interactive Report Page - will have **3 different views: Icon, Report, and Details**. Initially, wizard will create the Report View version that you'll modify with a custom SQL statement. Remaining two views (Detail and Icon) are placed on the page by enabling respective properties found under main Products region. Once you enable Detail and Icon views, their **icons appear on main Search bar**. Using these icons you can switch among different views to browse products information. **Product Details Page 6, CrUD product** . To create these two pages follow same approach as you did for Customers. >New stuff added to this module > 1. technique to **incorporate style sheet in APEX page** > 2. **image handling and styling**. This module is based on DEMO_PRODUCT_INFO table. Among conventional columns exists the following **four special columns to handle images** in DB. Normally, specialized processing is required to handle images in DB. APEX environment has **eliminated need of specialized processing** with these additional columns to properly process images in BLOB column. ### Image handling and styling columns : 1. PRODUCT_IMAGE: This column uses BLOB data type. **BLOB** (Binary Large Object) is Oracle data type that can hold **up to 4 GB** data. BLOBs we use for storing digitized information eg **images, audio, video, document files : PDF, MS Word, MS Excel, MS PowerPoint, CSV...**. 2. MIMETYPE: **Multipurpose Internet Mail Extension** (MIME) type **identifies file format**. MIME type **enables apps (Internet browsers, e-mail apps...) to read (handle) file**. Eg e-mail app can use MIME type to detect what type is file attached to e-mail. MIME types are composed of a top-level media type followed by a subtype identifier, separated by a forward slash character (/) eg image/jpeg. The top-level media type is a general categorization about **content of file**, while subtype identifier specifically identifies **format of file**. You can view via Object Browser in SQL Workshop after uploading such file types to BLOB column in your table : | File Type | MIMETYPE Metadata| | :------------------------- | :------------------- | | JPEG | image/jpeg | | PNG | image/png | | PDF | application/pdf | | WORD | application/vnd.openxmlformats-officedocument.wordprocessingml.document | | EXCEL | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | | POWERPOINT | application/vnd.openxmlformats-officedocument.presentationml.presentation | | CSV | application/vnd.ms-excel | 3. FILENAME: A case-sensitive column name used to store **filename of BLOB, such as bag.jpg or CV.pdf**. 4. IMAGE_LAST_UPDATE: A case-sensitive column name used to store the last update date of BLOB. ## 6.2 Create 2 Pgs for Products - tbl CRud report ID=3 & crUD form ID=6 Same approach as for Customers. 1. Main App Builder interface -> click "**Sales Web Application's Edit icon**" -> click "**Create Page**" button ### Create tbl IG page ID=3, Editing Enabled=Off (for "On" see [Sample Interactive Grids](#sampleIG)) >TIP: To **delete page**, open page in Page Designer by clicking its name -> select **Delete from top-right Utils menu**. 2. On first wizard screen, select **"Report"** means report of products in an interactive grid 3. On next wizard screen, **click Interactive Grid**. This screen presents sub-categories of reports and requires a single selection the report will base on. The option you selected here means an **interactive grid will act as a report** to display all customers from DB. 4. On the next wizard screen, set following ### Properties of IG tbl page 3 | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Page Number | 3 | Main page of this module (form page to be created next will have number 6) | | 2 | Page Name | **Products** | | | 3 | Page Mode | **Normal** | How you want to see page. Or **Modal** = Dialog is stand-alone page, appears only on top of its calling page and doesn't allow users to do anything else unless it is closed. | | 4 | Breadcrumb | Breadcrumb | = hierarchical list of links. **Breadcrumb shared component was created** by App Builder when you created this app (see Shared Components -> Navigation > Breadcrumbs). In this step, you selected same breadcrumb component and **added an entry name (Customers) to it**. | | 5 | Parent Entry | Home (Page 1) | | | 6 | Entry Name | Products | | 5. On **Navigation Menu wizard screen** ### Set menu item to call this page 1. set Navigation Preference = **Identify an existing navigation menu** entry for this page 2. set Existing Navigation Menu Entry = **Setup** - This step will make **Setup entry active in the main navigation menu** (created in Chapter 3, section 3.2.1) **when this page is accessed**. 3. click Next. 6. On **Report Source screen**, set following properties. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Editing Enabled | **Off** | form pg ID=6 edits cust records. Examples of editing rec. in interactive grid see later in this text | | 2 | Source Type | **Table** | Tbl data to populate this interactive grid | | 2 | Table/View Owner | | accept displayed value of Oracle **schema** (**POSSYS**) to which you are connected. | | 2 | Table/View Name drop-down list (from selected schema) | **DEMO_PRODUCT_INFO** (table) | whose data will be displayed in IG. **You can select only one table** from provided list. | **Click arrow icon next to the Column section** to see table columns - **all columns from that table are selected (moved to the right pane in the Columns section)**. Columns we want to show in IG : ... Click **Create button** to finish report page creation process. Click Application eg 145615(=appID) breadcrumb at top-left to **leave Page Designer interface** ## Create Page ID=6 to carry form "CrUD Products" 1. Click **Create Page button** -> select **"Form"** option -> click another Form option on next wizard screen -> creates form page based on DB table. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Page Number | 6 | **Page to carry form to CrUD Products** | | 2 | Page Name | **Product Details** | | | 3 | Page Mode | **Modal** Dialog | stand-alone page, appears on top of calling page | | 4 | Breadcrumb | Breadcrumb | | 5 | Parent Entry | Products (Page 3) | called from Page 3 | | 6 | Entry Name | Product Details | | 2. On **Navigation Menu** screen, set "Navigation Preference" = **Identify an existing navigation menu entry** for this page, set "Existing Navigation Menu Entry" = **Setup**, and click Next. 3. On **Source screen**, set following properties and click Next. | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Data Source | Local DB | | | 2 | Source Type | Table | | | 2 | Table/View Owner | | accept displayed value of Oracle **schema** (POSSYS) to which you are connected. | | 2 | Table/View Name | **DEMO_PRODUCT_INFO** (table) | | 4. This time, select all columns from DEMO_PRODUCT_INFO tbl to display **all of them in the input form (Page 6)** to populate backend DB tbl. For "Primary Key Type", select second option **Select Primary Key Column(s)**. Then, set first "Primary Key Column" attribute to **PRODUCT_ID**. **Click "Create" button** to complete form page creation process. >**Forms support up to 2 cols in PK**. For tbls using PK with more than two columns, ROWID option should be used. For further details, see Chapter 2. 5. Access main App Builder interface by **clicking application ID breadcrumb** to see **two new pages** (Customers and Customer Details) with their respective page numbers. **Click Products Details (Page 6)** to open its definitions in Page Designer. **Expand Pre-Rendering node** and rename process **Initialize form Products Details as "Initialize Products Details"**. Click Processing tab and rename process **Process form Products Details to "Process Products Data"**. NOTE: If you see a different process name, then there is nothing to worry about as it sometimes happens due to change in APEX version. APEX is a low-code app dev. platform. Two pages you just created have** everything you need to view and manipulate data**. Products Page 2 contains IG in which you can view all customers data. Click Product Details Page 6 to open it in Page Designer. On Rendering tab, expand Pre-Rendering node. Here, you will see an auto-generated process named **Initialize Products Details of Form Initialization type**. This Process is responsible to initialize form region items. Initialization can either be **fetching data from region source**, using PK value(s) or **simple initialization** of form region items. Process fetches and displays data in page items when you select product by clicking corresponding **edit icon on the reports page** and it initializes page items **when you create a new product record**. Product Details region is a **Form type region**, which connects to local DB and fetches data from DEMO_PRODUCT_INFO table into relevant page items listed under Items node. Same page items are used to receive user input when new customer record is created. In Buttons section, you will see a **bunch of auto-generated buttons** (Cancel, Delete, Save, and Create). **DB Action** property of these buttons specify function each button performs. When you click button (eg CREATE), corresponding DB action is submitted to process named **Process Customer Data**, which resides under Processing tab. This process is of Automatic Row Processing (DML) type and performs CrUD action on form region - Product Details region in current scenario. ## 6.3 Modify Main page of module Products Page ID=3 tbl Holds interactive grid generated by wizard with some default data source values. ### 6.3.1 Modify region Products Properties 1. click region Products of page 3 -> change Type "Table / View" to SQL Query 2. In SQL Query, replace existing SELECT statement with following to select (same in pge 6 crUD form) : ``` select PRODUCT_ID, PRODUCT_NAME , PRODUCT_DESCRIPTION, CATEGORY, PRODUCT_AVAIL , LIST_PRICE, UNITS, SALES, CUSTOMERS, LAST_DATE_SOLD , IMG, ICON_LINK, DETAIL_IMG, DETAIL_IMG_NO_STYLE from ( select p.product_id, p.product_name, p.product_description, p.category , decode(p.product_avail, 'Y','Yes','N','No') product_avail , p.list_price , (select sum(quantity) from demo_order_items where product_id = p.product_id) units , ( select sum(quantity * p.list_price) from demo_order_items where product_id = p.product_id ) sales , ( select count(o.customer_id) from demo_orders o, demo_order_items t where o.order_id = t.order_id and t.product_id = p.product_id group by p.product_id ) customers , ( select max(o.order_timestamp) od from demo_orders o, demo_order_items i where o.order_id = i.order_id and i.product_id = p.product_id ) last_date_sold , p.product_id img , apex_util.prepare_url(p_url=>'f?p='||:app_id||':6:'||:app_session||'::::P6_PRODUCT_ID:'||p.product_id) icon_link , decode( nvl(dbms_lob.getlength(p.product_image),0) ,0,null, '<img alt="'||p.product_name||'" title="'||p.product_name ||'" style="border: 4px solid #CCC; -moz-border-radius: 4px; -webkit-border-radius: 4px;" ' ||'src="'||apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',p.product_id)||'" height="75" width="75" />' ) detail_img , decode( nvl(dbms_lob.getlength(p.product_image),0) ,0,null, apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',p.product_id) ) detail_img_no_style from demo_product_info p ) ``` p.product_id is **img** column in query above ### "icon_link" to Product Details Page 6 (read_byprodID) is formed using **PREPARE_URL function** which is : 1. used **to form links** 2. is part of **APEX_UTIL package** 3. **returns f?p=URL**. p_url is VARCHAR2 parameter passed on to this fn apex_util.prepare_url(**p_url**=>'f?p='||:app_id||':6:'||:app_session||'::::**P6_PRODUCT_ID**:'||p.product_id) **icon_link** ### "detail_img" (and detail_img_no_style) **holds products img**. HTML img tag is used to display images of products in conjunction with **built-in APEX function APEX_UTIL.GET_BLOB_FILE_SRC** - which enables us to format img display with **height and width** properties. Image is styled using CSS inline styling method. **getlength fn of dbms_lob package (dbms_lob.getlength)** is used to estimate BLOB column size in table to facilitate inclusion of download link in report. **If BLOB column size length is 0, BLOB is NULL and no download link is displayed**. 3. Products region -> Content Body -> **Expand Columns** node and set meaningful column headings as follows: Product, Description, Category, Available, Price, Units, Sales, Customers, Last Sold, Image, Icon Link, Image Detail, and Detail Image No Style 4. Modify following columns. **We can use Ctrl+click or Shift+click to select multiple cols to change Type properties at once**. **Column : Property = Value...Help** 1. PRODUCT_ID : Type = **Hidden** Column...hidden to make it invisible at runtime 2. IMG : Type = **Hidden** Column 3. ICON_LINK : Type = **Hidden** Column 4. DETAIL_IMG : **Escape special characters (under Security)** = Off (otherwise image will not appear)...**Each report column IN IR (not in IG) !!** has property **Escape special characters** by default set to Yes - prevents Cross-Site Scripting (XSS) attacks and selecting **No renders** HTML tags stored in page item or in entries of **list of value**. 5. DETAIL_IMG_NO_STYLE : Type = **Hidden** Column 5. By selecting Product Name column in Link Text attribute you specify this report column to appear as a link. You created a **similar kind of link to call Customer Details page**. ### **Click PRODUCT_NAME column to transform it into a link** >1. **In Interactive Reports, you forward a value to target page** using special **substitution strings (enclosed in # symbols) ** >2. as compared to &Item. notation (for example, &CUSTOMER_ID.), which you use in the Interactive Grid - see Chapter 5 Section 5.3.1 Step 10. **Property Value** 1. **Click Link -> "Target"** attribute 2. In opened dialog : Type = Page In this application, Page = 6, Name = P6_PRODUCT_ID, Value = #PRODUCT_ID# 3. Link Text = **#PRODUCT_NAME# not &PRODUCT_NAME.** 6. If you **save and run** report page at this stage, **you will see an EDIT column** (represented with a **pencil icon**), which leads to details page. Since we have already created a link (on the Product Name column), we will eliminate this column so : Under **Products region, click its Attributes node, and set in Properties pane "Link" Column = Exclude Link Column**. Figure 6-3 7. In same Attributes node, scroll down to **Icon View section** and set following properties. >By default, **most interactive reports display as a report**. You can optionally display **columns as icons**. When configured, an **icon (View Icons) appears on Search bar**. To use this view, you must specify columns to identify **icon, label, and target (that is link)**. As a best practice Type attribute of these columns is set to **hidden** (as you did in step 4), because they are typically **not useful for end users**. Image Attributes property will style height and width of images. **Property Value** 1. Show = On 2. Columns Per Row = 5 (to display 5 images on a single row in View Icons interface) 3. Link Column = ICON_LINK 4. Image Source Column = DETAIL_IMG_NO_STYLE 5. Label Column = PRODUCT_NAME 6. Image Attributes = width="75" height="75" 8. ** Section "Detail View" under Icon View section** -> turn on Show property. When configured, **View Details icon appears on Search bar**. 9. In **Before Rows attribute** of Detail View you enter HTML code to be displayed before report rows. Eg you can use **TABLE element to put DB content in row/column format**. Besides adding HTML code, styling information can also be incorporated using this attribute. Code below uses custom CSS rules to override default Oracle APEX Interactive Report (**apexir**) styles. ``` <style> table.apexir_WORKSHEET_CUSTOM { border: none !important; box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;} .apexir_WORKSHEET_DATA td { border-bottom: none !important;} table.reportDetail td { padding: 2px 4px !important; border: none !important; font: 11px/16px Arial, sans-serif;} table.reportDetail td.separator { background: #F0F0F0 !important; padding: 0 !important; height: 1px !important; padding: 0; line-height: 2px !important; overflow: hidden;} table.reportDetail td h1 {margin: 0 !important} table.reportDetail td img { margin-top: 8px; border: 4px solid #CCC; -moz-border-radius: 4px; -webkit-border-radius: 4px;} </style> <table class="reportDetail"> ``` NOTE: Remember that all **APEX pages are HTML pages** controlled by HTML properties and cascading style sheet (CSS) settings. When you create an interactive report, Oracle APEX renders it based on CSS classes associated with current theme. Each APEX interactive report component has a CSS style definition that may be changed by applying standard CSS techniques to override defaults. CSS changes may be applied to : 1. single interactive report 2. page template to effect changes across several interactive reports 3. all page templates of a theme to enforce a common look and feel for all reports in an application In the current step, **you are changing report appearance** by overriding built-in styles for table and subordinate elements. 10. **In "For Each Row" (post_query)**, enter following code applied to each record. **In every td element** you are **referencing interactive report columns and labels with substitution string (#)** and are **styling each record using inline CSS method**. You used **substitution string to reference table column names and labels of page items as #PRODUCT_NAME# and #CATEGORY_LABEL#**. ``` <tr><td rowspan="5" valign="top"> <img width="75" height="75" src="#DETAIL_IMG_NO_STYLE#"></td> <td colspan="6"><h1><a href="#ICON_LINK#"><strong>#PRODUCT_NAME#</strong></a></h1></td> </tr> <tr> <td><strong>#CATEGORY_LABEL#:</strong></td><td>#CATEGORY#</td> <td><strong>#PRODUCT_AVAIL_LABEL#:</strong></td><td>#PRODUCT_AVAIL# </td> <td><strong>#LAST_DATE_SOLD_LABEL#:</strong></td><td>#LAST_DATE_SOLD#</td> </tr> <tr> <td align="left"><strong>#PRODUCT_DESCRIPTION_LABEL#:</strong></td> <td colspan="5">#PRODUCT_DESCRIPTION#</td> </tr> <tr> <td style="padding-bottom: 0px;"><strong>#LIST_PRICE_LABEL#</strong></td> <td style="padding-bottom: 0px;"><strong>#UNITS_LABEL#</strong></td> <td style="padding-bottom: 0px;"><strong>#SALES_LABEL#</strong></td> <td style="padding-bottom: 0px;"><strong>#CUSTOMERS_LABEL#</strong></td> </tr> <tr> <td style="padding-top: 0px;">#LIST_PRICE#</td> <td style="padding-top: 0px;">#UNITS#</td> <td style="padding-top: 0px;">#SALES#</td> <td style="padding-top: 0px;">#CUSTOMERS#</td> </tr> <tr> <td colspan="7" class="separator"></td> </tr> ``` 11. **In After Rows, enter `</table>`** to complete HTML code = HTML to be displayed after report rows. It is closing table tag to end HTML table. 12. **Save and run page 3 products tbl from Manage Products option in Setup menu** 1. Click View Reports icon (1st left to Actions list) 2. Note that **Image Detail column is blank at the moment**, because **we do not have any product image in tbl**. This is column which will hold images of products. ### Add (upload) image of product 1. ** Click some link in Product name column** to add image of this product. 2. **On Product Details page**, **???click "folder icon" representing Product Img field at page bottom**. This will bring up Open dialog box. 3. Go to BookCode\Chapter6 folder and select **1_AirMax2090.png** file, and click Open 4. image name will be displayed in **Product Image field**. 5. Click Apply Changes button on Product Details form to save image. The image will appear on the interactive report page. Repeat this step to add images of remaining products. Click **View Icons (3rd left from "Actions list")** and **View Details (1st left from "Actions list")** options on the interactive report toolbar and see output (Fig. 6-4). 13. **Filter and order cols : **Click View Reports icon. **Click Actions menu** in interactive report and select Columns. Make sure **all columns (except Description and Last Sold)** appear in Display in Report section. You can use arrow icons to arrange columns in a desired **order**. Click Apply button. Only columns you selected will appear in interactive report. 14. Click Actions menu again and select **Save Report (under Report)**. From Save drop-down list, select **As Default Report Settings**. Set Default Report Type to **Primary** and click Apply. After modifying an interactive report you must save it using this procedure, otherwise you?ll lose the applied settings when you subsequently view this report. Developers can save two types of default interactive report: **primary** and **alternative**. Both reports display on Report list on Search bar. **Primary default report (you just saved) cannot be renamed or deleted**. In next steps we **change default data source values** and **produce custom output using SQL query**. ### 6.3.1 Modify Products Region Prop. Cols hdr, order, filter and cust name as link 1. In App Builder, click Customers page (Page 2) to open it in the Page Designer for modification. ## Cols hdr, cols order, cols filter in tbl Products 2. **Click Customers region under Content Body node**. Standard method to modify properties of page component is to click corresponding node. This action refreshes Properties section (located to your right) with properties of selected page component for alteration. 3. Change **Type (under Source section)** = SQL Query to see **default query generated for interactive grid**. ``` select ROWID, CUSTOMER_ID, CUST_FIRST_NAME, CUST_LAST_NAME, CUST_STREET_ADDRESS1, CUST_STREET_ADDRESS2, CUST_CITY, CUST_STATE, CUST_POSTAL_CODE, CUST_EMAIL, PHONE_NUMBER1, PHONE_NUMBER2, URL, CREDIT_LIMIT, TAGS from DEMO_CUSTOMERS ``` Enter following SQL statement in SQL Query text area, replacing existing one: ``` SELECT customer_id, cust_last_name || ', ' || cust_first_name customer_name , CUST_STREET_ADDRESS1||decode(CUST_STREET_ADDRESS2, null, null, ', '||CUST_STREET_ADDRESS2) customer_address , cust_city, cust_state, cust_postal_code FROM demo_customers ``` Decode Syntax: decode( expression , search , result [, search , result]... [, default] ) If default is omitted, Oracle returns null. 4. Expand Customers region -> expand Columns node. Click column eg CUSTOMER_NAME and **change its heading (under Heading section in Properties pane) to Name**. Change headings of other cols : Address, City, State, and Postal Code 5. In Columns node, click the **CUSTOMER_ID** column, and change it Type property from **Number Field to Hidden** to hide col at runtime. PK cols are added to DB tbls to enforce data integrity and are not displayed in apps. This is why such column's Type property is set to hidden to make them invisible at runtime. 6. **Run page**. **Click Actions menu** (A) - select Columns. When you click column in left pane, right pane (D) shows its name and width. You can input a numeric value to **change width of col**. Using arrow icons (E), arrange selected columns in following **order**: Name, Address, City, State, and Postal Code 7. Click Save button in the Columns window to apply the changes. 8. **After you modify interactive grid in runtime save it :** Click Actions menu -> Save from Report option, otherwise you?ll lose the applied settings when you access it later. 9. **Click Edit Page2 (F) in the Developer Toolbar at the bottom of page** to access Page Designer. ## Cust name as link in tbl Customers 10. Click CUSTOMER_NAME column to set properties: **transforming cust name col into link that will lead to Page 7 cust. form**. >When you click customer's name in interactive grid report at runtime: 1. ID of that cust is stored in substitution string (&CUSTOMER_ID.) (G) 2. and is forwarded to corresponding page item (P7_CUSTOMER_ID) (H) on Page 7, which displays cust profile using this ID. >You created similar kind of link in Chapter 4 for region "Sales for this Month". Scroll down to Link section and **click "No Link Defined"** under Target to bring up **Link Builder dialog box** -> set link properties : | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Type | Page in this app | | | 2 | Page | 7 | | | 3 | Name | P7_CUSTOMER_ID | This value refers to an item on Page 7 that will be populated with the value held in #ID# . It is forwarded to Page 7 from the Home page to display **selected customer profile**. | | 4 | Value | &CUSTOMER_ID. | references third column in above SELECT query. Standard procedure in APEX to **refer to a column value** is to enclose it between # symbols. To **refer page item we use substitution strings**. | | 5 | Clear Cache | 7 | | Use LOVs (I) in Set Items section to select item name (3) and value (4). 11. **Close Link Builder dialog box using OK button**. 12. **Save and run page**. **Cust Name col will now appear as link**. Click any customer name to see details on Page 7, which pops up on top of Page 2. ### 5.3.2 Button "Create" in tbl Customers To call Page 7 with a blank form from Page 2 - Customers : 1. Rendering tab to your left click Customers interactive grid region -> set its **Template property to Standard** (was Interactiv). Selected template **will place title and border for interactive grid region**. Right-click Customers region and from context menu select **Create Button**. Button named New will be added. Set properties for new button : | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | CREATE | | | 2 | Label | Create Customer | appears as tooltip when you move over button at run-time | | 3 | Button Position | **Copy** | over dozen values, try other options as well to observe different positions | | 4 | Hot | On | renders the button in dark color | | 5 | Action | Redirect to Page in this App | (under Behavior) - **Creates link** to call Page 7. | | 6 | Target | Type = Page in this app Page = 7 Clear Cache =7 | **Creates link** to call Page 7. Clear Cache prop. makes all items on target pg 7 blank | 2. **Save and run Page 2**, which should look similar to Figure 5-1. 3. Click Create Customer button to call Customer Details Page 7 on top of calling page as a modal dialog. ### 5.3.3 Button "Call PHP page" to Call PHP script - report from APEX https://www.youtube.com/watch?v=WLE9_1I_nA0 Like 5.3.2, properties are : | | Property | Value | Help |-:| :------- | :------------ | :------------ | | 1 | Button Name | CallPHPpge | | | 2 | Label | **Call PHP page** | appears as tooltip when you move over button at run-time | | 3 | Button Position | **Copy** | over dozen values, try other options as well to observe different positions | | 4 | Hot | Off | if On : renders the button in dark color | | 5 | Action | Redirect to URL | (under Behavior) - **Creates link** to call PHP Page | | 6 | URL | "http://192.168.../" or "http://dev1:8083/fwphp/www" ?param1=&P26_PARAM | **Creates link** to call PHP Page | Open in new tab : ? ## 5.4 Modify properties of crUD form Customer Details - Page 7 With Page 7 cust. form being displayed in browser, **click Edit Page 7 in Developer Toolbar** at pge bottom to call this pge in PageDesigner. ### 5.4.1 Modify Page Items Properties >**Like region placement** in 12 cols grid layout, done for six Home pge regions, pge items can also be placed using APEX's grid layout, as follows. >**Width** property sets items width on page. >If **Value Required** is set to Yes and **page item is visible**, APEX **automatically performs NOT NULL validation when page is submitted** and **you are asked to input a value** for field. If you set Value Required to No, no validation is performed and a NULL value is accepted. Value Required attribute works in conjunction with **Template = Required** to signify (ozna?i) mandatory items visually. ### Page Id=7 Customer Details (profile) items properties and values Page flds are in 2 columns, only "Tags" fld spans both cols. Save your changes and call this Page 7 by **clicking any customer's name** on Page 2. It should come up with selected customer profile (Figure 5-6 Customer Details Page). Click each item under Items node and apply following properties. 1. P7_CUST_FIRST_NAME Label=**First Name**.....Sequence=20.....Start New Row=On.....Column=Automatic.....Column Span=Automatic .....Template=Required.....**Label Column Span=2 (becomes visible in Layout section only after setting Template property) ** .....Width=50.....Value Required=On 2. P7_CUST_LAST_NAME Label=**Last Name**.....Sequence=30.....Start New Row=**Off**.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Required.....**Label Column Span=2** .....Width=**50**.....Value Required=On 3. P7_CUST_STREET_ADDRESS1 Label=**Street Address**.....Sequence=40.....Start New Row=On.....Column=Automatic .....Column Span=Automatic.....Template=**Optional**.....Label Column Span=2 .....Width=50.....Value Required=Off 4. P7_CUST_STREET_ADDRESS2 Label=**Line 2**.....Sequence=50.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=50.....Value Required=Off 5. P7_CUST_CITY Label=City.....Sequence=60.....Start New Row=On.....Column=Automatic .....**Column Span=6**.....Template=Optional.....Label Column Span=2 .....Width=50.....Value Required=Off 6. See 5.4.2 Change cust. column "P7_CUST_STATE" to hold predefined LOV! States list 7. P7_CUST_POSTAL_CODE Label=Zip Code.....Sequence=80.....Start New Row=On.....Column=Automatic .....Column Span=6.....Template=Required.....Label Column Span=2 .....Width=8.....Value Required=On 8. P7_CREDIT_LIMIT Label=Credit Limit.....Sequence=90.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Required.....Label Column Span=2 .....Width=8.....Value Required=On 9. P7_PHONE_NUMBER1 Label=Phone Number.....Sequence=100.....Start New Row=On.....Column=Automatic.....Column Span=Automatic .....Template=Optional.....Label Column Span=2.....Width=12.....Value Required=Off 10. P7_PHONE_NUMBER2 Label=Alternate No.....Sequence=110.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=12.....Value Required=Off 11. P7_CUST_EMAIL Label=Email.....Sequence=120.....Start New Row=On.....Column=Automatic .....Column Span=Automatic.....Template=Required.....Label Column Span=2 .....Width=50.....Value Required=On 12. P7_URL Type=Text Field.....Label=URL.....Sequence=130.....Start New Row=Off.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=50.....Value Required=Off 13. P7_TAGS Type=Textarea.....Label=Tags.....Sequence=140.....Start New Row=On.....Column=Automatic .....Column Span=Automatic.....Template=Optional.....Label Column Span=2 .....Width=100.....Value Required=Off ## 5.4.2 Customer's page column "P7_CUST_STATE" to hold app-shared dynamic LOV! States list. app-shared means defined in app shared componebts in one place and reusable in all app modules pages. ### 1. In Shared Components to fetch State names from DEMO_STATES table 1. **Shared Components** -> Other Components section -> **"Lists of Values" APEX page** -> Click Create button 2. Select **From Scratch** option and click Next 3. Enter **States** in Name box, select **Dynamic for its type**, and click Next 4. On List of Values Source screen, select **SQL Query for Source Type**, and enter following query in **Enter SQL SELECT statement** box. Click Next ``` both VARCHAR2 30 : select state_name display_value, st return_value from demo_states order by 1 --select state_name display_value, state_id return_value from demo_states order by 1 ``` 5. On final Column Mappings screen, select RETURN_VALUE for Return Column, DISPLAY_VALUE for Display Column and **click Create button** to create the LOV. <br /><br /> ### 2. P7_CUST_STATE prop. Label=**State**.....Sequence=70.....Start New Row=**Off**.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=**Required**.....**Label Column Span=2** .....Width=make it **null** (this item will be transformed into a select list).....Value Required=On <br /><br /> ### 3. Type Text Field change to -> Select List and Attach STATES LOV! to it (was created in 3.4.3) 1. In Page Designer interface, **click P7_CUST_STATE item**. 2. Change its Type property from **Text Field to Select List**. 3. Set Type (under List of Values) to **Shared Components** and **select STATES for LOV**. This step ***attaches States LOV to page item***. 4. **Turn off "Display Extra Values" property**. An item may have a **session state value**, which does not occur in its LOV definition. Select whether this LOV should display this extra session state value. If you choose not to display this extra session state value and there is no matching value in list of values definition, first value will be selected value. Eg while creating new customer record you will see - Choose a State - as the first value in the list. This value is added to the list in following steps. 5. **Turn on Display Null Value property**, which is default. Display Null Value property makes it possible for a user to choose a null value instead of one of the list items. If you set this property to Yes, additional properties appear on the screen for you to specify display value for this new entry. Eg "Choose State". 6. **Enter - Choose State - in Null Display Value**. This step, along with the previous one, **generates a placeholder** that appears on top of the LOV asking for a selection whenever you call this page to create a new customer record. 7. Save your work. <br /><br /> ### 5.4.3 Apply Input Mask to Items Modify the **two phone number items in cust. form pgID=7** and set their **Value Placeholder property** (under Appearance) to 999-999-9999. When a new customer record is added, this placeholder is shown in the two phone number items to receive input in the specified format. As you type in values, the placeholders will be replaced by the numbers entered. ### 5.4.4 Create Validation 1 (logic control of user input) - Check Customer field "P7_CREDIT_LIMIT" Field "Credit Limit" is used to assign a credit cap to each customer with a figure of $5,000. **If you enter a value more than the assigned cap**, you'll be prevented by presenting an appropriate message. NOTE: Validation error messages display when : 1. validation fails the equality test 2. or evaluates to FALSE 3. or non-empty text string is returned. In left pane of Page 7 cust.form : click **Processing icon (was tab)** -> **right-click Validating node** -> **Create Validation** from context menu (Figure 5-7) -> Set following properties for this new validation : | | Property | Value | Help |-:| :------------------------ | :----------------------- | :------------ | | 1 | Name | **Check Credit Limit** | should be meaningful ! | | 2 | Type | PL/SQL Expression | expression in valid PL/SQL syntax **that evaluates to true or false** | | 3 | PL/SQL Expression | **:P7_CREDIT_LIMIT <= 5000** | If true customer record is saved to DB. Note that **you use bind variables** (item name preceded with a colon) when you reference value of a session state variable from within PL/SQL code. | | 4 | Error Message | Customer's Credit Limit must be less than or equal to $5,000 | | ## IR (Interactive report) (see 2.3.3) to display a list of products **instead of an interactive grid**. 2. 1. **Click Create Page button** in App Builder interface -> Sales web App 80858 2. **Click Form option, followed by Report with Form** option. These two selections will create a report page (Figure 6-1) to display all product records from the table (selected in step 5) and a form page (Figure 6-6) to add, modify, and delete products. 3. On the Page Attributes wizard screen, set the following properties and click Next. The form page (Page 6) is named Product Details and it will be linked to the report page (Products - Page 3). **Property Value** 1. Report Type = **Interactive Report** 2. Report Page Number = 3 3. Report Page Name = **Products** 4. Form Page Number = 6 5. Form Page Name = **Product Details** 6. Form Page Mode = Modal Dialog 7. Breadcrumb = Breadcrumb 8. >Parent Entry = Home (Page 1) 9. >Entry Name = Products 4. On Navigation Menu screen, set Navigation Preference to **"Identify an existing navigation menu entry for this page"**, **set "Existing Navigation Menu Entry" to Setup (?ifrarnici)**, and click Next. This step will **highlight Setup entry** in main navigation menu when you access products setup. 5. On Data Source screen, select **Table for Source Type**, accept default schema in Table/View Owner, and **select "DEMO_PRODUCT_INFO (table)" for Table/View Name**. **Columns** from the selected table to be shown in the interactive report will appear. **Accept all table columns** and click Next. 6. On Form Page screen, add all columns (A) from the DEMO_PRODUCT_INFO table to Page 6, **except : MIMETYPE, FILENAME, and IMAGE_LAST_UPDATE (B)**. These three columns are **used in background** to handle images of products. For Primary Key Type, choose Select **"Primary Key Column(s)"** (C). **Set "PK Column 1" attribute to PRODUCT_ID (Number) (D)**. PRODUCT_ID is populated behind the scene using **DB sequence object** (DEMO_PRODUCT_INFO_SEQ) via BI_DEMO_PRODUCT_INFO **trigger** when you add a new product - see the two objects by accessing **Object Browser**. Click Create button to complete wizard.This time, **wizard creates two pages (3 and 6) as an initial structure for this module**. ## 6.3 Modify Products tbl Page 3 ### 6.3.1 Modify Region Properties 1. Click region named Report 1 and set its **Title to Products** 2. In SQL Query, replace existing SELECT statement with following to select : Was : ``` select PRODUCT_ID, PRODUCT_NAME, PRODUCT_DESCRIPTION, CATEGORY, PRODUCT_AVAIL, LIST_PRICE, PRODUCT_IMAGE, MIMETYPE, FILENAME, IMAGE_LAST_UPDATE from DEMO_PRODUCT_INFO ``` Demo app : ``` PRODUCT_ID PRODUCT_NAME PRODUCT_DESCRIPTION CATEGORY PRODUCT_AVAIL LIST_PRICE UNITS SALES CUSTOMERS LAST_DATE_SOLD IMG ICON_LINK DETAIL_IMG DETAIL_IMG_NO_STYLE TAGS select p.product_id, p.product_name, p.product_description, p.category, decode(p.product_avail, 'Y','Yes','N','No') product_avail, p.list_price, (select sum(quantity) from demo_order_items where product_id = p.product_id) units, (select sum(quantity * p.list_price) from demo_order_items where product_id = p.product_id) sales, (select count(o.customer_id) from demo_orders o, demo_order_items t where o.order_id = t.order_id and t.product_id = p.product_id group by p.product_id) customers, (select max(o.order_timestamp) od from demo_orders o, demo_order_items i where o.order_id = i.order_id and i.product_id = p.product_id) last_date_sold, p.product_id img, apex_util.prepare_url(p_url=>'f?p='||:app_id||':6:'||:app_session||'::::P6_PRODUCT_ID,P6_BRANCH:'||p.product_id||','||3,p_dialog=> 'null') icon_link, decode(nvl(dbms_lob.getlength(p.product_image),0),0,null, '<img alt="'||apex_escape.html_attribute(p.product_name)||'" title="'||apex_escape.html_attribute(p.product_name) ||'" style="border: 4px solid #CCC; -moz-border-radius: 4px; -webkit-border-radius: 4px;" ' ||'src="'||apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',p.product_id)||'" height="75" width="75" />') detail_img, decode(nvl(dbms_lob.getlength(p.product_image),0),0,null, apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',p.product_id)) detail_img_no_style, tags from demo_product_info p ``` ``` select PRODUCT_ID, PRODUCT_NAME , PRODUCT_DESCRIPTION, CATEGORY, PRODUCT_AVAIL , LIST_PRICE, UNITS, SALES, CUSTOMERS, LAST_DATE_SOLD , IMG, ICON_LINK, DETAIL_IMG, DETAIL_IMG_NO_STYLE from ( select p.product_id, p.product_name, p.product_description, p.category , decode(p.product_avail, 'Y','Yes','N','No') product_avail , p.list_price , (select sum(quantity) from demo_order_items where product_id = p.product_id) units , ( select sum(quantity * p.list_price) from demo_order_items where product_id = p.product_id ) sales , ( select count(o.customer_id) from demo_orders o, demo_order_items t where o.order_id = t.order_id and t.product_id = p.product_id group by p.product_id ) customers , ( select max(o.order_timestamp) od from demo_orders o, demo_order_items i where o.order_id = i.order_id and i.product_id = p.product_id ) last_date_sold , p.product_id img , apex_util.prepare_url(p_url=>'f?p='||:app_id||':6:'||:app_session||'::::P6_PRODUCT_ID:'||p.product_id) icon_link , decode( nvl(dbms_lob.getlength(p.product_image),0) ,0,null, '<img alt="'||p.product_name||'" title="'||p.product_name ||'" style="border: 4px solid #CCC; -moz-border-radius: 4px; -webkit-border-radius: 4px;" ' ||'src="'||apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',p.product_id)||'" height="75" width="75" />' ) detail_img , decode( nvl(dbms_lob.getlength(p.product_image),0) ,0,null, apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',p.product_id) ) detail_img_no_style from demo_product_info p ) ``` p.product_id is **img** column in query above ### "icon_link" to Product Details Page 6 (read_byprodID) is formed using **PREPARE_URL function** which is : 1. used **to form links** 2. is part of **APEX_UTIL package** 3. **returns f?p=URL**. p_url is VARCHAR2 parameter passed on to this fn apex_util.prepare_url(**p_url**=>'f?p='||:app_id||':6:'||:app_session||'::::**P6_PRODUCT_ID**:'||p.product_id) **icon_link** ### "detail_img" (and detail_img_no_style) **holds products img**. HTML img tag is used to display images of products in conjunction with **built-in APEX function APEX_UTIL.GET_BLOB_FILE_SRC** - which enables us to format img display with **height and width** properties. Image is styled using CSS inline styling method. **getlength fn of dbms_lob package (dbms_lob.getlength)** is used to estimate BLOB column size in table to facilitate inclusion of download link in report. **If BLOB column size length is 0, BLOB is NULL and no download link is displayed**. 3. Expand Columns node (under Content Body | Products region) and set meaningful column headings as follows: Product, Description, Category, Available, Price, Units, Sales, Customers, Last Sold, Image, Icon Link, Image Detail, and Detail Image No Style 4. Modify following columns using specified properties. **We can use Ctrl+click or Shift+click to select multiple cols to change Type properties at once**. **Column : Property = Value...Help** 1. PRODUCT_ID : Type = **Hidden** Column...hidden to make it invisible at runtime 2. IMG : Type = **Hidden** Column 3. ICON_LINK : Type = **Hidden** Column 4. DETAIL_IMG : **Escape special characters (under Security)** = Off (otherwise image will not appear)...Each report column has property **Escape special characters** by default set to Yes - prevents Cross-Site Scripting (XSS) attacks and selecting **No renders** HTML tags stored in page item or in entries of **list of value**. 5. DETAIL_IMG_NO_STYLE : Type = **Hidden** Column 5. **Click PRODUCT_NAME column to transform it into a link**. By selecting Product Name column in Link Text attribute you specify this report column to appear as a link. You created a **similar kind of link in previous chapter to call Customer Details page**. 1. **In Interactive Reports, you forward a value to target page** using special **substitution strings (enclosed in # symbols) ** 2. as compared to &Item. notation (for example, &CUSTOMER_ID.), which you use in the Interactive Grid - see Chapter 5 Section 5.3.1 Step 10. **Property Value** 1. Type = Link 2. Target (under Link) : Type = Page In this application, Page = 6, Name = P6_PRODUCT_ID, Value = #PRODUCT_ID# 3. Link Text = #PRODUCT_NAME# 6. If you **save and run** report page at this stage, **you will see an EDIT column** (represented with a **pencil icon**), which leads to details page. Since we have already created a link (on the Product Name column), we will eliminate this column so : Under **Products region, click its Attributes node, and set in Properties pane "Link" Column = Exclude Link Column**. Figure 6-3 7. In same Attributes node, scroll down to **Icon View section** and set following properties. >By default, **most interactive reports display as a report**. You can optionally display **columns as icons**. When configured, an **icon (View Icons) appears on Search bar**. To use this view, you must specify columns to identify **icon, label, and target (that is link)**. As a best practice Type attribute of these columns is set to **hidden** (as you did in step 4), because they are typically **not useful for end users**. Image Attributes property will style height and width of images. **Property Value** 1. Show = On 2. Columns Per Row = 5 (to display 5 images on a single row in View Icons interface) 3. Link Column = ICON_LINK 4. Image Source Column = DETAIL_IMG_NO_STYLE 5. Label Column = PRODUCT_NAME 6. Image Attributes = width="75" height="75" 8. ** Section "Detail View" under Icon View section** -> turn on Show property. When configured, **View Details icon appears on Search bar**. 9. In **Before Rows attribute** of Detail View you enter HTML code to be displayed before report rows. Eg you can use **TABLE element to put DB content in row/column format**. Besides adding HTML code, styling information can also be incorporated using this attribute. Code below uses custom CSS rules to override default Oracle APEX Interactive Report (**apexir**) styles. ``` <style> table.apexir_WORKSHEET_CUSTOM { border: none !important; box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none;} .apexir_WORKSHEET_DATA td { border-bottom: none !important;} table.reportDetail td { padding: 2px 4px !important; border: none !important; font: 11px/16px Arial, sans-serif;} table.reportDetail td.separator { background: #F0F0F0 !important; padding: 0 !important; height: 1px !important; padding: 0; line-height: 2px !important; overflow: hidden;} table.reportDetail td h1 {margin: 0 !important} table.reportDetail td img { margin-top: 8px; border: 4px solid #CCC; -moz-border-radius: 4px; -webkit-border-radius: 4px;} </style> <table class="reportDetail"> ``` NOTE: Remember that all **APEX pages are HTML pages** controlled by HTML properties and cascading style sheet (CSS) settings. When you create an interactive report, Oracle APEX renders it based on CSS classes associated with current theme. Each APEX interactive report component has a CSS style definition that may be changed by applying standard CSS techniques to override defaults. CSS changes may be applied to : 1. single interactive report 2. page template to effect changes across several interactive reports 3. all page templates of a theme to enforce a common look and feel for all reports in an application In the current step, **you are changing report appearance** by overriding built-in styles for table and subordinate elements. 10. **In "For Each Row" (post_query)**, enter following code applied to each record. **In every td element** you are **referencing interactive report columns and labels with substitution string (#)** and are **styling each record using inline CSS method**. You used **substitution string to reference table column names and labels of page items as #PRODUCT_NAME# and #CATEGORY_LABEL#**. ``` <tr><td rowspan="5" valign="top"> <img width="75" height="75" src="#DETAIL_IMG_NO_STYLE#"></td> <td colspan="6"><h1><a href="#ICON_LINK#"><strong>#PRODUCT_NAME#</strong></a></h1></td> </tr> <tr> <td><strong>#CATEGORY_LABEL#:</strong></td><td>#CATEGORY#</td> <td><strong>#PRODUCT_AVAIL_LABEL#:</strong></td><td>#PRODUCT_AVAIL# </td> <td><strong>#LAST_DATE_SOLD_LABEL#:</strong></td><td>#LAST_DATE_SOLD#</td> </tr> <tr> <td align="left"><strong>#PRODUCT_DESCRIPTION_LABEL#:</strong></td> <td colspan="5">#PRODUCT_DESCRIPTION#</td> </tr> <tr> <td style="padding-bottom: 0px;"><strong>#LIST_PRICE_LABEL#</strong></td> <td style="padding-bottom: 0px;"><strong>#UNITS_LABEL#</strong></td> <td style="padding-bottom: 0px;"><strong>#SALES_LABEL#</strong></td> <td style="padding-bottom: 0px;"><strong>#CUSTOMERS_LABEL#</strong></td> </tr> <tr> <td style="padding-top: 0px;">#LIST_PRICE#</td> <td style="padding-top: 0px;">#UNITS#</td> <td style="padding-top: 0px;">#SALES#</td> <td style="padding-top: 0px;">#CUSTOMERS#</td> </tr> <tr> <td colspan="7" class="separator"></td> </tr> ``` 11. **In After Rows, enter `</table>`** to complete HTML code = HTML to be displayed after report rows. It is closing table tag to end HTML table. 12. **Save and run page 3 products tbl from Manage Products option in Setup menu** 1. Click View Reports icon (1st left to Actions list) 2. Note that **Image Detail column is blank at the moment**, because **we do not have any product image in tbl**. This is column which will hold images of products. ### Add (upload) image of product 1. ** Click some link in Product name column** to add image of this product. 2. **On Product Details page**, **???click "folder icon" representing Product Img field at page bottom**. This will bring up Open dialog box. 3. Go to BookCode\Chapter6 folder and select **1_AirMax2090.png** file, and click Open 4. image name will be displayed in **Product Image field**. 5. Click Apply Changes button on Product Details form to save image. The image will appear on the interactive report page. Repeat this step to add images of remaining products. Click **View Icons (3rd left from "Actions list")** and **View Details (1st left from "Actions list")** options on the interactive report toolbar and see output (Fig. 6-4). 13. **Filter and order cols : **Click View Reports icon. **Click Actions menu** in interactive report and select Columns. Make sure **all columns (except Description and Last Sold)** appear in Display in Report section. You can use arrow icons to arrange columns in a desired **order**. Click Apply button. Only columns you selected will appear in interactive report. 14. Click Actions menu again and select **Save Report (under Report)**. From Save drop-down list, select **As Default Report Settings**. Set Default Report Type to **Primary** and click Apply. After modifying an interactive report you must save it using this procedure, otherwise you?ll lose the applied settings when you subsequently view this report. Developers can save two types of default interactive report: **primary** and **alternative**. Both reports display on Report list on Search bar. **Primary default report (you just saved) cannot be renamed or deleted**. ## 6.4 Modify Product Details (form) Page 6 ### Adjust dimension of Product Details page Page Designer toolbar carries a section called **Page Selector** - **fld** : enter page number and click Go. Navigate to **Next/prev Page (up/down arrow)** - Figure 6-5. Using Page Selector **call Page 6** in Page Designer. **Click root node** and set following properties. **Property Value** 1. Title = Product Details 2. Width (under Dialog) = 900 3. Height = 620 4. Maximum Width = 1000 5. Img rule in inline CSS property (under CSS) to make products images responsive. ::before selector (used in second rule) will insert word 'Nike' before images of products - see Figure 6-6. ``` img { width: 100%; max-width: 100%; height: auto; } .imgItem::before { content: 'Nike'; position: absolute; top: 30px; left: 20px;color: #000; opacity: 0.1; font-size: 8em; font-weight: 800; } ``` ### 6.4.1 Making Page Item Mandatory P6_PRODUCT_NAME, P6_CATEGORY, P6_PRODUCT_AVAIL, and P6_LIST_PRICE 1. Click on P6_PRODUCT_NAME item, **press and hold the Ctrl key** , and then **click the other items to select them all** **Property Value** 1. Template (under Appearance) Required 2. Value Required (under Validation) On 2. Set Template property of P6_PRODUCT_DESCRIPTION and P6_PRODUCT_IMAGE page items to Optional. ### 6.4.2 Attach Categories LOV! to page item P6_CATEGORY ### 1. In Shared Components 3.4.1 LOV CATEGORIES (U, T) - STATIC to fetch Product categories from list 1. Shared Components (pyramid of 3) -> Other Components section -> **Lists of Values APEX page** 2. Click Create button (9 LOVs are created by APEX). 3. Select From Scratch option and click Next. 4. LOV Name = **Categories**, select LOV type = **Static**, click Next. 5. Fill in values as shown in following table. At runtime these entries will display in order they are entered. Return Value does not display, but is the value that is returned to APEX engine as user selection (user event). | Sequence | Display val | Rerturn val (user event) | Help | | -: | :----------------------- | :---------------------------- | :----------------------------- | | 1 | Mens | Mens | Men ?| | 2 | Womens | Womens | Women ? | | 3 | Accessories | Accessories | Kids ? | 6. Click Create LOV button <br /><br /> ### 2. P6_CATEGORY prop. Label=**Category**.....Sequence=70.....Start New Row=**On**.....Column=Automatic .....New Column=On.....Column Span=Automatic.....Template=**Required**.....**Label Column Span=2** .....Width=make it **null** (this item will be transformed into a select list).....Value Required=On <br /><br /> ### 3. Type Text Field change to -> Select List and Attach Categories LOV! to it Here we're going to use LOV Categories to which page item P6_CATEGORY will bound, to display predefined values of categories in Select List - see Manage Customers module to display STATES LOV. 1. Page Designer interface -> Items node under Product Details region **click P6_CATEGORY item**. 2. In Property Editor (right pane) change its Type property (under Identification) from **Text Field to Select List**. 3. Set Type (under List of Values) to **Shared Components** and **select CATEGORIES for LOV**. This step ***attaches Categories LOV to page item P6_CATEGORY***. 4. **Turn off "Display Extra Values" property** 5. **Turn off Display Null Value property** 6. Save your work. ### 6.4.3 Attach LOV to Product Available Column Next, you will change the Product Available field to a Switch comprising two options: On and Off. Just like the previous steps, here as well, you?re changing the item type from Text to Switch. At runtime, this item will show two options to specify whether the selected product is available or not. If you ignore this exercise and leave the item to its default type, users can enter whatever value they like, resulting in compromising application?s integrity. This is a good example to restrict users to select valid values. Select the P6_PRODUCT_AVAIL item and set the following properties. Note that the last two properties in the table sets Y (which stands for On) as the default value for this item. **Property Value** 1. Type (under Identification) = Switch 2. Label = Product Available 3. Type (under Default) = Static 4. Static Value = Y ### 6.4.4 Handling Image (Handle Image Exercise A) Modify following properties (in Settings section) for the** P6_PRODUCT_IMAGE item to map table columns**. This mapping is necessary to display product images on details form. **Property Value** 1. MIME Type Column = MIMETYPE 2. Filename Column = FILENAME 3. BLOB Last Update Column = IMAGE_LAST_UPDATE In the Settings section, the Storage Type attribute is set to BLOB column specified in item Source attribute by default. The Storage Type attribute specifies where the uploaded file should be stored at. It has two values: BLOB column specified in item source attribute. Stores the uploaded file in the table used by the "Automatic Row Processing (DML)" process and the column specified in the item sourceattribute. The column has to be of data type BLOB. Table APEX_APPLICATION_TEMP_FILE. Stores the uploaded file in a table named APEX_APPLICATION_TEMP_FILE. ### 6.4.5 Create Region - Product Image (Handle Image Exercise B) To show images of selected products on Product Details page, we will create a Static Content sub-region. Note that this section will only create a blank region to hold an image. The image will be added to this region in a subsequent section. Right-click the Regions node and select Create Region from the context menu. Select the new region and modify the following properties. The region will have a blue background and it will be displayed only when there exists an image for a product and this evaluation is made using a condition based on a PL/SQL function. **Property Value** 1. Title = Product Image 2. Type = Static Content 3. Sequence = 5 (to place this region before the Product Details region) 4. Custom Attributes = style="background: #006bdc;" 5. Type (under Server-side Condition) = PL/SQL Function Body 5. PL/SQL Function Body ``` declare begin if :P6_PRODUCT_ID is not null then for c1 in ( select nvl(dbms_lob.getlength(product_image),0) A from demo_product_info where product_id = :P6_PRODUCT_ID ) loop if c1.A > 0 then return true; end if; end loop; end if; return false; end; ``` Click the Product Details region and turn off the Start New Row property to place this region beside the Product Image region you just added. NOTE: Page items are referenced in a PL/SQL block using bind variables inwhich a colon(:) is prefixed to the item name ? :P6_PRODUCT_ID, for example. Code Explained In Oracle APEX you make use of conditions to control the appearance of page components. The ability to dynamically show or hide a page component is referred to as conditional rendering. You define conditional rendering for regions, items, and buttons. These page components have a Condition section in the property editor, where you select a condition type from a list. In the current scenario, you set a condition based on a PL/SQL function, which returns a single Boolean value: True or False. If the code returns True, the region is displayed carrying the image of the selected product. After selecting a condition type, you inform Oracle APEX to execute the defined PL/SQL code. The code first executes an IF condition (line 3) to check whether the product ID is not null by evaluating the value of the page item P6_PRODUCT_ID. If the value is null, the flow of the code is transferred to line 13, where a false value is returned and the function is terminated. If there exists a value for the product ID, then line 4 is executed, which creates a FOR loop to loop through all records in the DEMO_PRODUCT_INFO table to find the record (and consequently the image) of the selected product (line 4-11). On line 8, another IF condition is used to assess whether the image exists. If so, a true value is returned on line 9 and the function is terminated. ### 6.4.6 Create Item (Handle Image Exercise C) In this section, you will create a new item named P6_IMAGE to display the product image in the Product Image region. Right-click the Product Image region and select Create Page Item from the context menu. Set the following properties for the new item. The code defined in the PL/SQL Function Body fetches image of the selected product using a function (apex_util.get_blob_file_src). By setting the Rows Returned condition and using a SQL query we ensured the existence of an image in the table. The imgItem class defined for this page item was referenced in section 6.4 to show some content before product images. **Property Value** 1. Name = P6_IMAGE 2. Type = Display Only 3. Label = Clear the Label box to make it empty 4. Region = Product Image 5. Template = No template (Set it to -Select- placeholder) 6. CSS Classes = imgItem 7. Type (under Source) = PL/SQL Function Body 8. PL/SQL Function Body = ``` return '<img src="'||apex_util.get_blob_file_src('P6_PRODUCT_IMAGE',:P6_PRODUCT_ID)||'" />'; ``` 9. Type (under Server- side Condition) = Rows Returned 10. SQL Query ``` SELECT mimetype from demo_product_info WHERE product_id = :P6_PRODUCT_ID AND mimetype like 'image%' ``` 10 Escape special characters = Off (Otherwise the image won?t appear) ### 6.4.7 Create Button to Remove Image (Handle Image Exercise D) An image can be removed from the Product Details page and consequently from the underlying table by clicking this button. It is attached to a process (Delete Image) defined in the next section. Right-click the Product Image region and select Create Button. Set the following properties for the new button. The button will appear on top of the region. The Target value calls a confirmation box. This call is made using an Oracle APEX function (apex.confirm) by passing a message and the name of the Delete button. If you click Yes in the confirmation box, the process associated with the Delete button removes image references from the products table. **Property Value** 1. Name DELETE_IMAGE 2. Label Remove Image 3. Region Product Image 4. Button Position Copy 5. Button Template Icon 6. Hot On 7. Icon fa-image 8. Action (under Behavior) 9. Redirect to URL 10. URL (under Target) ``` javascript:apex.confirm('Are you sure you want to delete this image? It will no longer be available for others to see if you continue.','DELETE_IMAGE'); ``` ## 6.5 Create a Process Under Processing to Delete Image (Handle Image Exercise E) This is the process I mentioned in the previous section. It is associated with the Delete button to remove a product image. To remove an image stored in a database table, you are required to just replace the content of the relevant columns with a null. Click the Processing tab and then right-click the Processing node. From the context menu select Create Process. Set the following properties for the new process: **Property Value** 1. Name Delete Image 2. Type PL/SQL Code 3. PL/SQL Code ``` UPDATE demo_product_info SET product_image=null, mimetype=null, filename=null, image_last_update=null WHERE product_id = :P6_PRODUCT_ID; ``` 4. Sequence 15 (to place it before the Close Dialog process) 5. Success Message Product image deleted 6. When Button Pressed DELETE_IMAGE NOTE: The Processing node contains two processes (Process form Product Details and Close Dialog) that were created by the page creation wizard. The first one is created to handle DML operations, while the second one closes Page 6 when you click Create, Save, or Delete button. The values of these buttons are mentioned in Server-side Condition of the process, which specifies that the dialog is to be closed only when any of the three buttons are clicked. Clicking the DELETE_IMAGE button won't close the page, because the name of this button is not in the Value list. Similarly, the Delete Image process will only be executed when the DELETE_IMAGE button is pressed. Test Your Work Save your work and run the application. From the main navigation menu, select Manage Products from the Setup menu. On the main interactive report page (Figure 6-1), click the three report icons individually to see different views of products information. Clicking View Icons will present small icons of products. Each product is presented as a linked icon. If you click any icon, you'll be taken to the form page (Page 6 - Figure 6-6) where you'll see details of the selected product. Click the Report View icon. TheReport View presents data in a table. Here, you can access the details page by clicking products? names. Click the Detail View icon. This View presents products information from a different perspective. You can access details of a product by clicking its name. This is the view that was styled in section 6.3.1 steps 8-11. Click any product's name to call its details page (as illustrated in Figure 6-6). The form region (Product Details) was created by the wizard incorporating all relevant fields. The Product Image region was created in section 6.4.5. Also, note that the Remove Image button (you created in section 6.4.7) appears within this region. Figure 6-6 Product Details Page Create a new product record using the Add Product button on the Products report page. Click the Browse button and select any small image file to test image upload. You can use an existing product image by right-clicking the image and selecting Save Image As from the context menu. Or, use the Download link provided on the Product Details form page to get one for testing.Once you have an image in place, fill in all the fields except List Price. Try to save this record by clicking the Create button. A message ?Please fill out this field? will appear informing you to provide some value for the List Price. Now, provide some alpha-numeric value like abc123 in the List Price. Again, a message will come up reminding you to put a numeric value. Finally, input a numeric value in the List Price field and save the record. You'll see the new product appears on the Products page among others with the image you uploaded. Edit this record and see the image. Change the category of this product, switch availability to the other option and apply changes. Call the product again and observe the changes you just made to it. Click the Remove Image button and see what happens. Click the Delete button followed by OK in the confirmation box. The product will vanish from the list. NOTE: You might encounter a primary key violation message (ORA-00001: unique constraint (DEMO_PRODUCT_INFO_PK) violated) while creating first product record. This is because the Sequence object for this table is created with an initial value of 1. When you try to save the first product record, 1 is assigned as the first primary key value, which already exists in the table. To cope with this situation, just click the Create button on the form page several times. After ten clicks the record will be save. ## 6.6 Uploading and Viewing PDF and Other Types of Files As mentioned earlier in this chapter, you can store different types of files (upto 4 GB), such as images, audio, video, PDF, CSV, XLSX, DOC and more, in the BLOB column of your table. In this exercise, I?ll demonstrate how to save and view a PDF. As far as the uploading is concerned, you are not required to perform any special steps to handle PDF or any other file type. You have already set the stage in the previous sections where you handled JPEG images. Here, you will just create two new pages that will be apart from your application. 1. Click the Create Page button in the App Builder interface. 2. Click the Report option. 3. Select Interactive Report.4. On Page Attributes wizard screen, enter 303 for Page Number and Products Catalog for Page Name. Click Next. 5. On the Navigation Menu screen, set Navigation Preference to Do not associate this page with a navigation menu entry and click Next. 6. On Report Source screen, select SQL Query for Source Type and enter the following statement in the Enter a SQL SELECT statement area. ``` select p.product_id, p.product_name, dbms_lob.getlength(p.product_image) document from demo_product_info p ``` 7. Click the Create button to complete the page creation process. ### 6.6.1 Modify BLOB Column Execute the following steps to modify the BLOB column attributes. In the Page Designer, expand the Columns node (under the Products Catalog interactive report region), click the Document column and set the following attributes for this column. In the Download Text property you set a string used for the download link. If nothing is provided, Download is used. The Content Disposition specifies how the browser handles the content when downloading. If a MIME type is provided and the file is a type that can be displayed, the file is displayed. If MIME type is not provided, or the file cannot be displayed inline, the user is prompted to download. **Property Value** 1. Type = Download BLOB 2. Table Name (under BLOB Attributes) = DEMO_PRODUCT_INFO 3. BLOB Column = PRODUCT_IMAGE 4. Primary Key Column 1 = PRODUCT_ID 5. Mime Type Column = MIMETYPE 6. Filename Column = FILENAME 7. Last Updated Column = IMAGE_LAST_UPDATE 8. Download Text (under Appearance) = View 9. Content Disposition = Inline ### 6.6.2 Upload and View PDF As just mentioned the product setup module created earlier in this chapter is ready to upload any type of file, so to save some precious time we are going to use that module to upload a PDF. 1. Run the application and select Setup | Manage Products. 2. Click the Create button on the main Products interactive report page. 3. Fill in the mandatory fields. Click the Choose File button, select product_catalog.pdf file, which is available in the source code, and click Create. The pdf will be uploaded to the DEMO_PRODUCT_INFO table. Take some time to verify the upload from SQL Workshop | Object Browser. 4. Switch back to Page Designer. With Page 303 appearing on your screen click the Save and Run page button. The Product Catalog page will appear displaying data from the corresponding table. Click the View link for the Product Catalog PDF document. The PDF will be opened in your browser.Figure 6-7 Play around with this module by tweaking the saved properties to see resulting effects on two pages. You can always **restore properties** to their original values by referencing exercises provided in the chapter. <br /><br /><br /><br /><br /><br /> <a name="order"></a> # 07. Taking Orders page 201/419 [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....**Order**.....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) ## 7.1 About Sale Orders This chapter will teach you how to create professional looking order forms. Orders from customers will be taken through a sequence of wizard steps. The first wizard step will allow you to select an existing customer or create a new one. In the second step, you will select ordered products. After placing the order, the last step will show summary of the placed order. Once an order is created, you can view, modify, or delete it through Order Details page using a link in orders main page. The list presented below displays the application pages you will create in this chapter: Page No. Page Name Purpose 4 Orders The main page to display all existing orders 29 Order Details Display a complete order with details for modification 11 Identify Customer (Wizard Step 1) Select an existing customer or create a new one 12 Select Order Items (Wizard Step 2) Add products to an order 14 Order Summary (Wizard Step 3) Show summary of the placed order You?ll build this module sequentially in the sequence specified above. The first two pages (Page 4 and 29) will be created initially using a new wizard option: Master Detail. Both these pages are not part of the Order Wizard and will be utilized for order modification and deletion after recording an order. Page 4 is similar to the pages you created in Customer and Product modules and lists all placed orders, while Page 29 will be used to manipulate order details. For example, you can call an order in the usual way using the provided link in the master page. The called order will appear in the details page where you can: Add/Remove products to and from an order Delete the order itself The purpose of each chapter in this book is to teach you some new features. Here as well, you?ll get some new stuff. This chapter will walk you through to get detailed practical exposure to the techniques this module contains. After completing the two main pages, you will work on actual order wizardsteps to create other pages of the module. Recall that in the previous chapter you modified the main interactive report (Page 3) to create a couple of views (Icon and Detail) and used the Actions menu to select and sort table columns. In this chapter, many other utilities provided under the Actions menu will be exposed. But first, let?s create the two main pages using the conventional route. ## 7.2 Create Order Master and Order Detail Pages 1. Click the Create Page button in the App Builder. 2. On the first wizard screen, click the Master Detail option. A master detail page reflects a one-to-many relationship between two tables in a database. Typically, a master detail page displays a master row and multiple detail rows within a single HTML form. With this form, users can insert, update, and delete values from two tables or views. On the Master Detail page, the master record displays as a standard form and the detail records appear in an interactive grid region under the master section. 3. On the next wizard screen, select the Drill Down option, which opens input form in a separate page. 4. Fill in the next screen (Page Attributes) as illustrated below, and click Next.Figure 7-1 5. On the Navigation Menu screen, set Navigation Preference to Identify an existing navigation menu entry for this page, set Existing Navigation Menu Entry to Orders, and click Next. 6. Select the values in the Master Source screen (as shown in the following figure), and click Next. In this step, you select the parent table, which contains the master information for each order. You also specify the primary key column, which will be populated automatically behind the scene using a trigger named BI_DEMO_ORDERS via a sequence named DEMO_ORDERS_SEQ. You can view both these database objects from SQL Workshop > Object Browser interface. The ORDER_ID column selected in the Form Navigation Order list is the navigation order column used by the previous and next buttons on the Order Details page to navigate to a different master record.Figure 7-2 7. Set properties on the Detail Source screen as illustrated below and click Create to finish the wizard. On this screen, you specify the relational child table, which carries line item information for each order. The primary key column of this table will be populated automatically via a trigger named BI_DEMO_ORDER_ITEMS, which gets the next primary key values from a sequence named DEMO_ORDER_ITEMS_SEQ. In the Master Detail Foreign Key list you select the sole auto-generated foreign key, which creates a relationship between the master and detail tables.Figure 7-3 Before running these pages, let?s see what the wizard has done for us. The master page (Page 4) is created with an Interactive Report to display a list of all order from the Orders Mater table. The details page (Page 29), on the other hand, has many things to reveal. The following table lists all those components created automatically by the wizard with complete functionalities to manage this module. Component: Pre-Rendering Process Name: Initialize form Form on DEMO_ORDERS Description: Fetches master row from DEMO_ORDERS table. This process was briefed in Chapter 5 Section 5.4.5. If you see a different process name, then there is nothing to worry about as it sometimes happens due to change in APEX version. Component: Region Name: Form on DEMO_ORDERSDescription: The page has two regions. The Form on DEMO_ORDERS region, which is a Static Content region, displays master information like customer ID, order date, and so on. The lower region shows product details along with quantity and price in an Interactive Grid. Component: Buttons Names: GET_PREVIOUS_ORDER_ID and GET_NEXT_ORDER_ID Description: These buttons are added to the master region to fetch previous and next orders, respectively. For example, when you click the Next button , the page is submitted to get the next order record from the server by triggering the Initialize form Form on DEMO_ORDERS process using the value set for Next Primary Key Item(s) property in this process. The Next Primary Key Item(s) and Previous Primary Key Item(s) properties in this process are associated with respective hidden page items to fetch next and previous order ids. Based on the currently fetched order number, which is held in the page item P29_ORDER_ID, the process dynamically obtains the next and previous order numbers and stores them in two hidden page items: P29_ORDER_ID_NEXT and P29_ORDER_ID_PREV. The visibility of the Next and Previous buttons is controlled by a Server-side Condition (Item is NOT NULL), which says that these buttons will be visible only when their corresponding hidden items have some values. If you make any modification to an order on Page 29 and navigate to another order record using any of these buttons, the changes are saved to the two database tables. This is because the Action property of the two buttons is set to Submit Page. When the page is submitted, two processes (Process form Form on DEMO_ORDERS and Order Details - Save Interactive Grid Data defined later in this section) are executed to make the changes permanent. Component: Button Name: Cancel Description: The Cancel button closes Page 29 and takes you back to Page 4 without saving an order. For this, a redirect action is generated in the Behavior section with Page 4 set as the target. Component: ButtonName: Delete Description: The Delete button removes a complete order. When this button is clicked, a confirmation dialog pops up using its Target property, which is set to: javascript:apex.confirm(htmldb_delete_message,'DELETE'); When you confirm the deletion, a SQL DELETE action (specified in Database Action property for this button) is executed within the built-in Automatic Row Processing (DML) processes?Process form Form on DEMO_ORDERS and Order Details - Save Interactive Grid Data. Component: Button Name: Save Description: The Save button records updates to an existing order in the corresponding database table. This button is visible when you call an order for modification, in other words, P29_ORDER_ID is NOT NULL. The process behind this button is controlled by a SQL UPDATE action within the two built-in Automatic Row Processing (DML) processes. Component: Button Name: Create Description: The Create button is used for new orders to handle the INSERT operation. This button is visible when you are creating a new order ? that is, the page item P29_ORDER_ID is NULL. It uses the SQL INSERT action within the two built-in Automatic Row Processing (DML) processes. Component: Region Name: Order Details Description: This is an Interactive Grid region, which is generated to view, add, modify, and delete line items using the parameters set in step 7. The information you provided in this interactive grid is saved to the DEMO_ORDER_ITEMS table through a process named Order Details - Save Interactive Grid Data ? discussed next. Component: Process Name: Process form Form on DEMO_ORDERSDescription: This Automatic Row Processing (DML) type process is generated by the wizard to handle DML operations performed on the master row of an order, which gets into the DEMO_ORDERS table. It comes into action when you click Delete, Save, or Create buttons. The three buttons and their associated actions are depicted in the following figure. Component: Process Name: Order Details ? Save Interactive Grid Data Description: The Save Interactive Grid Data process is responsible to handle DML operations on the details table (DEMO_ORDER_ITEMS). This process is associated with the details section (Interactive Grid) to insert, update, or delete Interactive Grid rows. Component: Branches Name: Go To Page 29, Go To Page 29, and Go To Page 4 When you submit a page, the Oracle APEX server receives a submit request and performs the processes and validations associated with that request. After this, it evaluates where to land in the application via these branches. By default, it selects the current page as the target page. For example, when you click the Next or Previous buttons on Page 29, you stay on the same page. If you want to land users to some other page, youcan do this as well by creating branches. In the current scenario, you are moved back to Page 4 when you click any other button on Page 29. A branch has two important properties: Behavior and Server-side Condition. In the Behavior section you specify the page (or URL) to redirect to, and in Condition you specify when the branch is to be fired. Here, the first two branches are created to keep you on Page 29. These branches are associated with Next and Previous buttons?see When Button Pressed properties of these branches. The third one takes you back to Page 4 when you click any other button on this page ? see the Behavior section that specifies the redirect. Run this module from the Orders navigation menu entry. The first page (Page 4) you see is an interactive report. It is similar to the one you created in Chapter 6. It has a Create button, which is used to create a new order. Click the edit link (represented with a pencil icon) in front of any record to call the Order Details page (Page 29). The Order Details page has two regions. The upper region, which is called the master region, displays information from the DEMO_ORDERS table, while the lower interactive grid region shows relevant line item information from the DEMO_ORDER_ITEMS table. Besides usual buttons, the master region has two navigational buttons at the top. These buttons help you move forward and backward to browse orders. The Order Timestamp field is supplemented with a Date Picker control. You can add more products to the details section by clicking the Add Row button. From a professional viewpoint this page is not user friendly. If you try to add a new product, you have to enter its ID manually. Moreover, if you try to create a new order, you won?t see the interactive grid. By default, this grid is visible only when you modify an existing order and it hides when you try to create a new order. This behavior is controlled by a server side condition (Item is NOT NULL) set for the Interactive Grid region (Order Details). With this condition set, the region is rendered only when the page item P29_ORDER_ID has some value. Choosing the ? Select ? placeholder for the Server-side Condition Type property removes this condition and makes the interactive grid visible every time you access Page 29. Even after this adjustment, you will face some constraint issues related to a backend table. To avoid all such problems, execute the instructions provided in subsequentsections to make the module user-friendly. ## 7.3 Modify Orders Page - Page 4 Execute the instructions provided in the following sub-sections to modify the Orders page. 7.3.1 Modify the Orders Interactive Report Region on Page 4 The Orders interactive report region on Page 4 fetches orders information from the DEMO_ORDERS table. Let?s replace the existing auto-generated data fetching mechanism with a custom SQL query, which incorporates customers information from the DEMO_CUSTOMERS table. 1. Open Page 4 in the Page Designer, and click the Orders region. Modify the region using the values set in the following table: Property Value Location Local Database Type SQL Query SQL Query select lpad(to_char(o.order_id),4,'0000') order_number, o.order_id, to_char(o.order_timestamp,'Month YYYY') order_month, trunc(o.order_timestamp) order_date, o.user_name sales_rep, o.order_total, c.cust_last_name||', '||c.cust_first_name customer_name, (select count(\*) from demo_order_items oi where oi.order_id = o.order_id and oi.quantity != 0) order_i o.tags tags from demo_orders o, demo_customers c where o.customer_id = c.customer_id 2. Expand the Columns node under the Orders region and set the Type property for the ORDER_ID column to Hidden Column. 3. Set meaningful headings for all interactive report columns as follows. Order #, Order Month, Order Date, Customer, Sales Rep, Order Items, Order Total, and Tags 4. Edit the ORDER_TOTAL column and select the value $5,234.10 for its Format Mask property.5. Select the Order Number column (not Order ID) and turn it into a link using the following properties: Property Value Type Link Target (in Link section) Type = Page in this application Page = 29 Name = P29_ORDER_ID Value = #ORDER_ID# Clear Cache = 29 Link Text #ORDER_NUMBER# 6. Click the Attributes node under the Orders interactive report region. Select Exclude Link Column for Link Column property in the Property Editor. This action will exclude the default link column (denoted with a pencil icon) from the report as we have a custom link created in the previous step. 7. In the Attribute node, scroll down to the Actions Menu section, and turn on the Save Public Report option, to include this option in the Actions menu at runtime. By enabling this option you can create a public report ? see section 7.3.4. 8. Click the Create button and set the following properties for this button. New customer orders in this module will be recorded via some wizards steps, and Page 11 (to be created in a subsequent section) will be the first order wizard step. Property Value Label Enter New Order Target (in Behavior section) Type = Page in this application Page = 11 Clear Cache = 11 9. Save your modifications. 7.3.2 Modify Interactive Report Perform the following steps to change the look and feel of the default interactive report. After performing these steps, the interactive report will besaved as the Default Primary Report, which cannot be renamed or deleted. Note that these modifications are made using the Actions menu at runtime. 1. Click the Save and Run Page button to run Page 4. 2. Click the Actions menu, select the Columns option, arrange the report columns as depicted in the following screen shot, and click Apply. This action will arrange the report columns in the specified order. Figure 7-4 3. Click the Actions menu again, and select Data followed by the Sort option. 4. In the Sort grid, select the Order # column in the first row, set the corresponding Direction to Descending, and click Apply. This action will display most current orders on top.Figure 7-5 4. Click Actions | Report | Save Report. In the Save Report dialog box, select As Default Report Settings from the Save list, select Primary for Default Report Type, and click Apply. NOTE: Always save a report via the Actions menu whenever you make changes to it; otherwise, your modifications will not be reflected the next time you log in to the application. In Interactive Reports, you can apply a number of filters, highlights, and other customizations. Rather than having to re-enter these customizations each time you run the report, you tell Oracle APEX to remember them so that they are applied automatically on every next run. The application users can save multiple reports based on the default primary report, as discussed in the next couple of sections. 7.3.3 Create Alternative Report Alternative report enables developers to create multiple report layouts. Only developers can save, rename, or delete an Alternative Report. This report (named Monthly Review) is based on the default primary report and will be rendered in a different layout using the Control Break utility on Order Month column. Execute the following steps on the primary interactive report on Page 4 to create three different views of the report. A. Report View 1. From the Actions menu, select Save Report (under Report). In the Save Report dialog box, select As Default Report Settings from the Save list. This time, select the Alternative option for Default Report Type, enter Monthly Review in the Name box, and click Apply. You will see a drop down list between the Search bar andthe Actions menu carrying two reports: Primary Report and Monthly Review. 2. From the list, select the Monthly Review alternative report. 3. Click Actions | Format | Control Break. Under Column, select Order Month in the first row (A), set Status to Enabled (B), and click Apply. The Control Break feature enables grouping to be added to your report on one or more columns. The Column attribute defines which column to group on and the Status attribute determines whether the control break is active. When you click the Apply button, you will see the report results are grouped by the Order Month column and the Control Break column rule (C) is listed under the toolbar. A checkbox (D) is displayed next to the Control Break column and it is used to turn the control break rule on or off. The control break can be deleted from the report by clicking the small cross icon (E). 4. Click Actions | Format | Highlight. Type Display Orders >$1000 (A) in the Name box, set Highlight Type to Cell (B), select green (C) for Background Color, and click red (D) for Text Color. In the Highlight Condition section, set Column to Order Total (E), Operator to > greater than (F), Expression to 1000 (G), and click Apply. To distinguish important data from the rest, Oracle APEX provides you with conditional highlighting feature in interactive reports. The highlight feature in the Actions menu enables users to display data in different colors based on a condition. You can define multiple highlight conditions for a report. In this step, you're instructing to highlight the Order Total column in the report with green background and red text color where the value of this column is greater than 1000. Since you set the Highlight Type to Cell, the condition will apply only to the Order Total column. To modify an existing highlight rule, click its entry under the interactive report toolbar. 5. Click Actions | Format | Highlight. Type Display Orders <= $999 in the Name field, set Highlight Type to Row, click yellow for Background Color, click Red for Text Color, in HighlightCondition set Column to Order Total, Operator to <= (less than or equal to), Expression to 999 and click Apply. This step is similar to the previous one with different parameters. In contrast to the previous action, where only a single cell was highlighted, this one highlights a complete row with yellow background and red text color and applies it to all rows in the report that have Order Total equaling $999 or less. The resulting output should resemble the following figure. Figure 7-8 Monthly Order Review ReportB. Chart View You can generate charts in Interactive Reports based on the results of a report. You can specify the type of chart together with the data in the report you want to chart. In the following exercise, you will create a horizontal bar chart to present monthly sales figures using the Order Month column for the chart labels and a sum of the Order Total column for the chart values. Figure 7-9 1. Click Actions | Chart. 2. Select the first option (Bar) for the Chart Type. 3. Select Order Month for Label. 4. Enter Month in Axis Title for Label. 5. Select Order Total for Value. 6. Enter Sales in Axis Title for Value.7. Select Sum for Function. 8. Set Orientation to Horizontal. 9. Select Label-Ascending for Sort. 10. Click Apply. The chart should resemble the following figure. Note that the toolbar now has two icons: View Report and View Chart. If the chart doesn?t appear, click the View Chart icon in the toolbar. Move your mouse over each bar to see total amount for the month. Figure 7-10 Chart View C. Group By View Group By enables users to group the result set by one or more columns and perform mathematical computations against the columns. Once users define the group by, a corresponding icon is placed in the toolbar, which they can use to switch among the three report views.1. Click the View Report icon in the interactive report toolbar to switch back to the report view interface. 2. Click Actions | Group By. 3. Set the properties as show in the following figure and click Apply. Use the Add Function button to add the second function (Count). The first function calculates the monthly average of orders, while the second function counts the number of orders placed in each month. Figure 7-11 4. Click Actions | Report | Save Report. Select As Default Report Setting from the Save list. Select Alternative for the Default Report Type. The Name box should display Monthly Review. Click Apply. The output of this view is illustrated in the following figure. Note that a third icon (View Group By) is also added to the toolbar.Figure 7-12 Group By View 7.3.4 Create Public Report This type of report can be saved, renamed, or deleted by end users who created it. Other users can view and save the layout as another report. Execute the following instructions to create the three views Report, Chart, and Group by of a public report. The Alternative report created in the previous section focused on orders, while this one is created from customers perspective. A. Report View 1. Select the default 1. Primary Report from the Reports drop-down list in the toolbar. 2. From the Actions menu, select Save Report (under Report). 3. From the Save drop-down list select As Named Report. For report Name, enter Customer Review, put a check on Public and click the Apply button. A new report group (Public) will be added to the reports list in the toolbar, carrying a new report named Customer Review. Users can create multiple variations of a report and save them as named reports for either public or private viewing. When you click the Apply button, the report is displayed on your screen. 4. With the Customer Review report being displayed on your screen, click Actions | Format | Control Break. Select Customer in the first row under Column, set Status to Enabled, and click Apply to see the following output.Figure 7-13 B. Chart ViewFigure 7-14 1. Click Actions | Chart. 2. Set parameters for the chart as illustrated in the figure 7-14. 3. Click the Apply button. The output is illustrated in figure 7-15. NOTE: The chart uses the Average function (as compared to the Sum function used in the previous exercise). William Hartsfield has placed two orders amounting to $2,370. The average for this customer comes to $1,185 (2,370/2) and this is what you see when you move your mouse over the bar representing this customer.Figure 7-15 Chart View C. Group By View 1. Click the View Report icon to switch back. 2. Click Actions | Group By. 3. Set parameters for this view as show in the following illustration. Turn on the Sum switch for all three functions to display grand totals.Figure 7-16 4. Click Apply. 5. Save your work using the Actions menu. Select As Named Report from the Save list. The Name box should be displaying Customer Review. Click Apply. Select Customer Review from the report list in the toolbar, and click the View Group By icon. The following figure displays the output for the selections you just made. In this view, you utilized Sum and Count functions on two columns: Order Total and Order Items. This view displays total amount of orders placed by each customer with number of orders and the total number of items ordered.Figure 7-17 Group By View D. Pivot View The Pivot option is the Actions menu is used to create a cross tab view based on the data in the report. Let's see an instance of this option as well. 1. Click the View Report icon to switch back. 2. Click Actions | Pivot. 3. Set parameters as show in the following illustration. Don?t forget to turn on the Sum switch to produce grand totals on the page.Figure 7-18 4. Click Apply. 5. Save your work using the Actions menu. The following figure illustrates the output of these actions. Figure 7-19 Pivot ViewIn the previous few sections you used some options from the Actions menu to customize the interactive report. However, the menu contains a few more, as listed below: Filter focuses the report by adding or modifying the WHERE clause on the query. Rows Per Page determines how many rows display in the current report. Data contains the following submenu: Sort - Changes the columns to sort on and determines whether to sort in ascending or descending order. Compute - Enables users to add computed columns to a report. Flashback enables you to view the data as it existed at a previous point in time by specifying number of minutes. To use this option, the Oracle database FLASHBACK feature must be turned on. Reset is used to reorganize the report back to the default report settings. Help provides descriptions of how to customize interactive reports. Download enables users to download a report. Available download formats depend upon your installation and report definition. To see these formats, click a region's Attribute node and check the Download section in the Property Editor. ## 7.4 Modify Order Details Page - Page 29 Execute the instructions provided in the following sub-sections to modify the Order Details Page. 7.4.1 Modify Master Region Properties Page 29 contains two regions. The master region (Form on DEMO_ORDERS) is of Form type and carries order header information, while the second region (Order Details) is an interactive grid, which containsline item details. Modify the master region using the following steps: 1. Open Page 29 in the Page Designer, click the root node (Page 29: Order Details) and set the Page Mode property to Modal Dialog to open it on top of Page 4. Set Width, Height, and Maximum Width properties to 900, 700, and 1200, respectively. Also, set Dialog Template (in the Appearance section) to Wizard Modal Dialog. Dialog templates are defined in the application theme. When a dialog page is created, the template is automatically set to Theme Default, which will render the page using the default page template defined in the current theme. The Wizard Modal Dialog provides a streamlined user interface suitable for input forms. When you switch to this template, the name of Content Body changes to Wizard Body and a new node named Wizard Buttons is added. We will use this node to place all our page buttons to make them visible all the time. 2. Click the Form on DEMO_ORDERS region and enter Order #&P29_ORDER_ID. (including the terminating period) for its Title. The expression consists of two parts. The first one (Order #) is a string concatenated to a page item (P29_ORDER_ID), which carries the order number. The string, when combined, would be presented as: Order # 1. Make sure that region?s Template attribute (under Appearance) is set to Standard to show this title. 3. Create a new page item in the Items node under the master region and set the following properties. This item will present customer information on each order as display-only text. Display Only items are shown as non-enterable text item. Note that you may get an error message (ORA-20999) when you enter the SQL query specified in the table below. Save the page by clicking the Save button to get rid of this message. Moreover, if you keep the default value (On) for Escape Special Characters property, the customer information appears on a single line with <br/> tags Property Value Name P29_CUSTOMER_INFO Type Display OnlyLabel Customer Template Optional Type (under Source) SQL Query (return single value) SQL Query select apex_escape.html(cust_first_name) || ' ' || apex_escape.html(cust_last_name) || '<br />' || apex_escape.html(cust_street_address1) || decode(cust_street_address2, null, null, '<br />' || apex_escape.html(cust_street_address2)) || '</br>' || apex_escape.html(cust_city) || ', ' || apex_escape.html(cust_state) || ' ' || apex_escape.html(cust_postal_code) from demo_customers where customer_id = :P29_CUSTOMER_ID Escape Special Characters Off NOTE: If you see an error message after providing the SQL query, ignore it and click the Save button to save the page. The error will vanish. 1. Using drag and drop arrange page items in the master region as illustrated in the following screenshot. Figure 7-20 2. Edit the following items individually and set the corresponding properties shown under each item.a. P29_ORDER_TIMESTAMP Property Value Type Display Only Label Order Date Template Optional Format Mask DD-MON-YYYY HH:MIPM b. P29_ORDER_TOTAL Property Value Type Display Only Template Optional Format Mask $5,234.10 c. P29_USER_NAME Property Value Type Select List Label Sales Rep Template Optional Type (List of Values) SQL Query SQL Query select distinct user_name d, user_name r from demo_orders union select upper(:APP_USER) d, upper(:APP_US from dual order by 1 Display Extra Values Off Display Null Value Off Help Text Use this list to change the Sales Rep associate In the Help Text attribute you specify help text for an item. The help text may be used to provide field level, context sensitive help. At run-time you will see a small help icon in-front of this item. When you click this icon, a window pops up to show the help text.d. P29_TAGS Property Value Template Optional e. P29_CUSTOMER_ID Property Value Type Hidden Value Protected Off f. P29_ORDER_ID Property Value Type Hidden Value Protected Off 6. In the Region Buttons node, set Button Position property to Edit for GET_PREVIOUS_ORDER_ID and GET_NEXT_ORDER_ID buttons to place them on top of the region. 7.4.2 Modify Details Region?s Properties After setting the master region, let?s modify the details region to give it a desirable look. 1. Click the Order Details interactive grid region and set its Title to Items for Order #&P29_ORDER_ID. ? including the terminating period. 2. Replace the auto-generated source attributes of the region with the followings: Property Value Location Location Database Type SQL Query SQL Query select oi.order_item_id, oi.order_id, oi.product_id, oi.uni oi.quantity, (oi.unit_price * oi.quantity) extended_price from DEMO_ORDER_ITEMS oi, DEMO_PRODUCT_INFO piwhere oi.ORDER_ID = :P29_ORDER_ID and oi.product_id = pi.product_id (+) 3. Save the page. 4. Under the Columns node, edit the following columns using the specified properties. Column Property Value ORDER_ITEM_ID Type Value Protected Primary Key Hidden On On ORDER_ID Type Value Protected Hidden On PRODUCT_ID Type Heading Alignment Type (LOV) List of Values Display Null Value Select List Product Select the left icon Shared Components Products With Price Off UNIT_PRICE Alignment Column Alignment Format Mask Select the right icon Select the right icon $5,234.10 QUANTITY Width (under Appearance) Type (under Default) PL/SQL Expression 5 PL/SQL Expression 1 (sets 1 as the default quan EXTENDED_PRICE Type Heading Alignment Column Alignment Format Mask Query Only ( under Source ) Display Only Price Select the right icon Select the right icon $5,234.10 On After modifying an interactive grid query you must specify a primary column, which is required for editing and to specify master detail relationship. If not defined, you will encounter " Interactive Grid doesn't have a primary key column defined which is required for editing or in a master detail relationship " message . By setting the ORDER_ITEM_ID column as the primary key you eliminate this error. The Alignment property sets the heading alignment, while the ColumnAlignment specifies the column display alignment. For product ID column, we changed two properties. First, we set its Type property to Select List. Secondly, we associated an LOV (Products with Price) to it. This LOV was created in Chapter 3 section 3.4.2 to display a list of products along with respective prices. The Query Only property (under Source section) set for the Extended Price column specifies whether to exclude the column from DML operations. If set to On, Application Express will not utilize the column when executing the Interactive Grid - Automatic Row Processing (DML) process. In the current scenario, you excluded the Extended Price column, because it is not a physical table column and is calculated in the SELECT query stated above. If you keep the default value of this property for the Extended Price column, you will get ?Virtual column not allowed here? error message when you try to save an existing order. All columns whose definitions include concatenations, inner selects, functions call, or a column in an updateable view that is based on an expression should be excluded. All columns that need to be included in any INSERT or UPDATE statements must have this option set to Off. Note that columns of type Display Only are also included in the Automatic Row Processing unless this option is turned on. 5. Using drag and drop arrange the five visible columns in the following order: PRODUCT_ID, UNIT_PRICE, QUANTITY, and EXTENDED_PRICE 6. Right-click the Wizard Buttons node and select Create Region. Set Title of the new region to Buttons and Template to Buttons Container. In the Region Buttons node, click the Cancel button, and set its Region property to Buttons. Set the same Buttons region for Delete, Save, and Create buttons, too. This action will place the four buttons under the Buttons region in the interactive grid. 7. On the Processing tab, make sure that the process ?Process form Form on DEMO_ORDERS? sits before the Order Details ? Save Interactive Grid Data process. If not, drag and place it before the Order Details ? Save Interactive Grid Data process or set itsSequence property to a number lower than that of the Save Interactive Grid Data process. Note that this process must precede the Save Interactive Grid Data process; otherwise, you will get the error ?Current version of data in database has changed since user initiated update process? when you try to manipulate data in the interactive grid. 8. Save the changes. NOTE: If you see a different process name, then there is nothing to worry about as it sometimes happens due to change in APEX version. Test Your Work Run the application and click the Orders option in the main navigation menu. The page that comes up should look like Figure 7-21. Click any order number to call the Order Details page (Figure 7-22). Try to navigate forward and backward using the Next and Previous buttons. At the moment, you can only use these two pages to manipulate existing orders. In the next sections, you will create some more pages to enter new orders. Call order number 0002 and click the Add Row button appearing in the Interactive Grid's toolbar. A new row will be added to the grid just under the first row with the Product column appearing as a list of values carrying all products with their respective prices. Select Air Max 2090 (A) from this list, enter 1500 (B) in the Unit Price column, and put some value in the Quantity column (or accept the default quantity 1). Now, remove the checkmark appearing in the first column of the new record and put a check on the previous Air Max 2090 record (C). From the Row Actions menu (D), select Delete Row (E). The previous record will be marked as deleted (F). Click the Apply Changes button (G). Call the order again. The new record will be added to the table with the correct price of the product and the previous record will be removed.Figure 7-21 ? Orders Interactive Report Page Figure 7-22 ? Order Details ## Page7.5 Create a Page to Enter a New Order - Page 11 As mentioned earlier, you will go through a series of steps to enter a new order. You identified and created these steps in Order Wizard list in Chapter 3 section 3.2.3. The top section (A) in Figure 7-23 reflects these steps. Each step will be associated to an application page. The rest of this chapter will guide you to create the three pages individually. In this exercise, you will create Page 11 - Enter New Order. The order recording process initiates when you click the button Enter New Order on the Orders page (Page 4). The button calls Page 11, where you select a customer who placed the order. Besides selecting an existing customer, you can also create record of a new customer on this page. The Customer LOV button (B) calls a list of existing customers from which you can select one for the order. If you select the New Customer option (C), a region (New Customer Details) will be shown under the existing region. By default, this region is hidden and becomes visible when you click the New Customer option. This functionality is controlled by a dynamic action (Hide / Show Customer), which will also be created for this page. In addition to various techniques taught in this part, you?ll create this page from an existing page - Customer Details (Page 7) - to generate a new customer record. Here, you?ll make a copy of that page and will tweak it for the current scenario. Let?s see how it is done. Figure 7-23 Identify Customer Page1. In the App Builder interface, click the Customer Details - Page 7 to open its definitions in Page Designer. 2. Click the Create menu at top-right in the toolbar and select Page as copy. 3. On the first wizard screen, select the option Page in this application for Create a page as a copy of and click Next. 4. Fill in the following values on Page To Copy screen and click Next. Figure 7-24 5. On the Navigation Menu screen select Identify an existing navigation menu entry for this page, select Orders for Existing Navigation Menu, and click Next. 6. Accept the names of existing page buttons and items on the New Names screen and click the Copy button to finish the wizard. Look at the Page Designer. All the elements from Page 7 appear on the new page, especially the items section, which carries all input elements (with P11 prefix) to create a new customer record. This is the section we needed on our new page to spare some time. 7.5.1 Modify Page Properties 1. In Page 11, click the root node (Page 11: Identify Customer). In the Properties pane, set Dialog Template (under Appearance) toWizard Modal Dialog. The template creates a region (Wizard Progress Bar) to hold the order progress list (A), as shown in Figure 7-23, and alters the name of the main region from Content Body to Wizard Body. 2. Set Width and Height properties to 700 and 500, respectively. 3. Remove htmldb_delete_message variable from Function and Global Variable Declaration property. Save the page after removing the variable. This is an auto-generated variable associated with the customer record deletion process handled transparently by Oracle APEX. It is removed because the customer record deletion process is not required here. 4. Change Maintain Session State property (in Source section) of P11_CUST_FIRST_NAME, P11_CUST_LAST_NAME, P11_CUST_STREET_ADDRESS1, P11_CUST_STREET_ADDRESS2, P11_CUST_CITY, and P11_CUST_STATE,P11_CUST_POSTAL_CODE, P11_CREDIT_LIMIT, P11_PHONE_NUMBER1, P11_PHONE_NUMBER2, P11_CUST_EMAIL, P11_URL, and P11_TAGS page items to Per Session (Disk). Switching to this value maintains the item value to access it across requests. See PL/SQL code line 22-30 in section 7.6.3 and Place Order process in section 7.6.8 later in this chapter where these items are referenced. If you keep the default Per Request (Memory Only) value for this property, none of the page item values can be referenced on other module pages and will not be inserted in the database table. 7.5.2 Create Region ? Order Progress Right-click the Wizard Progress Bar node (under Regions) and select Create Region. Set the following properties for the new region. The Order Wizard list used here was created in Chapter 3 - section 3.2.3. The Wizard Progress value specified for the List Template property displays a progress train based on the list items and is well suited for wizards and multi-step flows. Property ValueTitle Order Progress Type List List Order Wizard Template Blank with Attributes List Template (under Attributes node) Wizard Progress Label Display ( under Attributes |Template Options ) All Steps ( displays labels of all wizard steps ) 7.5.3 Create Region ? Identify Customer Right-click the Wizard Body node and select Create Region. Drag the new region and place it above the Customer Details region. Set the following properties for it. This region is created to act as a main container to hold a radio group item and a couple of sub-regions. Property Value Title Identify Customer Type Static Content Template Standard 7.5.4 Create Item Right-click the new Identify Customer region and select Create Page Item. Set the following properties for the new item, which is a Radio Group. The list of values attached to this radio group item (NEW OR EXISTING CUSTOMER) was created in Chapter 3 - section 3.4.4 with two static values to create a new customer or select an existing one for a new order. The value set for the Number of Columns property displays these values in two separate columns. The first Type and Static Value properties (under Source) specify the source type the value of this item will based on when you access this page, whereas the second pair sets the EXISTING value as the default choice. **Property Value** Name P11_CUSTOMER_OPTIONS Type Radio Group Label <b>Create Order for:</b> Number of Columns 2 Template Required Label Column Span 3 Type (under List of Values) Shared ComponentList of Values NEW OR EXISTING CUSTOMER Display Null Value Off Type (under Source) Static Value Static Value (under Source) EXISTING Type (under Default) Static Static Value (under Default) EXISTING 7.5.5 Create a Sub Region ? Existing Customer Right-click the Identify Customer region and select Create Sub Region. This will add a sub region under the page item P11_CUSTOMER_OPTIONS. Set the following properties from the sub region. Property Value Title Existing Customer Type Static Content Template Blank with Attributes 7.5.6 Modify Item ? P11_CUSTOMER_ID In the Items section, click P11_CUSTOMER_ID. Set the Name property of this hidden item to P11_CUSTOMER_ID_XYZ. Set Server-side Condition Type to Never (last in the list). This item is renamed and suppressed from being rendered because a new item (of Popup LOV type) with the same name is created in the next section to display a list of customers, instead. By selecting the Never value for the Server-side Condition Type property, you permanently disable a page component. That is, the component is never rendered. 7.5.7 Add LOV Right-click the Existing Customer sub-region and select Create Page Item. Set the following properties for this item. The Type value (under Source) is set to Null, because the IDs and names of customers are retreived using a SQL query and displayed in a Popup LOV. Property Value Name P11_CUSTOMER_ID Type Popup LOV Label Customer Template Required Width 70Value Required Off Type (under List of Values) SQL Query SQL Query select cust_last_name || ', ' || cust_first_name d, customer_id r from demo_customers order by cust_last_name Display Extra Values Off Display Null Value Off Type (under Source) Null Help Text Choose a customer using the pop-up selector, or to create a new customer, select the <strong>New customer</strong> option. 7.5.8 Modify Customer Details Region Click the Customer Details region and set the following properties for this region. When you specify a parent region you make a region child of a parent region. Property Value Title New Customer Details Parent Region Identify Customer 7.5.9 Delete Validation, Processes, and Buttons 1. On the Processing tab, right-click the entry Can?t Delete Customer with Orders under Validations, and select Delete from the context menu. Similarly, delete the process Process Customer Data. 2. Also, remove Delete, Save, and Create buttons from the Buttons region on the Rendering tab. 7.5.10 Delete Process On the Rendering tab, expand the Pre-Rendering | Before Header | Processes node and delete the process named Initialize Customer Details. This is a default process created in the Customers module and is not required in the current scenario. 7.5.11 Create Button Create a new button in the Buttons region and set the following properties for it. After identifying a customer, you click this button to advance to the secondorder wizard step. This button will appear under the Cancel button in the Page Designer. When this button is clicked, the Action property submits the page and a branch (created in section 7.5.18) takes control of the application flow and moves you on to the next wizard step. Property Value Button Name NEXT Label Next Button Position Next Button Template Text with Icon Hot On Icon fa-chevron-right Action Submit Page (default) 7.5.12 Create Process - Create or Truncate Order Collection When developing web applications in Oracle APEX, you often need a mechanism to store an unknown number of items in a temporary location. The most common example of this is an online shopping cart where a user can add a large number of items. To cope with this situation in Oracle APEX, you use Collections to store variable information. Before using a collection, it is necessary to initialize it in the context of the current application session. After clicking the Enter New Order button, you?re brought to this page (Page 11) and this is where your collection (named ORDER) is initialized using a PL/SQL process that fires Before Header when the user enters into the interface of Page 11. See sections 7.6.7 and 7.6.8 for relevant details on collections. On the Rendering tab, expand the Pre-Rendering node. Right-click the Before Header node and select Create Process. Set the following properties for the new process. Property Value Name Create or Truncate ORDER Collection Type PL/SQL Code PL/SQL Code apex_collection.create_or_truncate_collection (p_collection_name => 'ORDER');Figure 7-25 7.5.13 Create Dynamic Action (Hide / Show Customer) Click the Dynamic Actions tab. Right-click the Change node and select Create Dynamic Action. Click the New node and set the following properties. The following settings inform Oracle APEX to fire the dynamic action when user changes (Event) the radio group item (Selection Type) P11_CUSTOMER_OPTIONS (Item) from New Customer to Existing. Property Value Name Hide / Show Customer Event Change Selection Type Item(s) Item(s) P11_CUSTOMER_OPTIONS Type (under Client-side Condition) Item = value Item (under Client-side Condition) P11_CUSTOMER_OPTIONS Value EXISTING Click the Show node to set the following properties. The values for these properties are set to show the Existing Customer region when the EXISTING option is selected from the radio group. The On value set for the Fire on Initialization property specifies to fire the action when the page loads. Property Value Action Show Selection Type Region Region ..Existing Customer Fire When Event Result is True Fire on Initialization OnRight-click the Show node and select Create Action. Another Show node will be added just under the previous one. Set the following properties for it. This action is also assoicated with the previous two and is added to hide New Customer Details region when the EXISTING option is selected. Property Value Action Hide Selection Type Region Region ..New Customer Details Fire When Event Result is True Fire on Initialization On Right-click the Show node again and select Create Opposite Action. This will add an opposite Hide action under the False node (with all properties set) to hide the Existing Customer region. Right-click the Hide node under the True node and select Create Opposite Action. This will add a Show action under the False node to show the New Customer Details region. If you run the page at this stage (by clicking the Enter New Order button on Page 4), you'll see the P11_CUSTOMER_ID item (in the Existing Customer region) is shown on the page. Now, select the New Customer option. The item P11_CUSTOMER_ID disappears from the page and the New Customer Details region becomes visible. Select the Existing Customer option again, the item becomes visible and the New Customer Details region hides. 7.5.14 Modify Validation ? Check Credit Limit On the Processing tab, click the Check Credit Limit validation. Set its Sequence to 100 and save the change to place this validation in a proper sequence after the following validations. Note that the Sequence property determines the order of evaluation. 7.5.15 Create Validation ? Customer ID Not Null Right-click the Validations node and select Create Validation. Set the following properties for the new validation. You can control when a validation is performed by configuring its Server-side Condition property. Select a condition type from the list that must meet in order for a validation to process. In the current scenario, the condition (item=value) is formed likethis: P11_CUSTOMER_OPTIONS = EXISTING . The validation fires when you select the Existing Customer option on the application page, and do not select a customer from the provided list. In case of an error at runtime, the #LABEL# substitution string specified in the Error Message property is replaced with the label of the associated item P11_CUSTOMER_ID ? that is, Customer. Property Value Name Customer ID Not Null Sequence 10 Type (Validation) Item is NOT NULL Item P11_CUSTOMER_ID Error Message Select a #LABEL# from the provided list. Associated Item P11_CUSTOMER_ID Type (Server-side Condition) Item = Value Item P11_CUSTOMER_OPTIONS Value EXISTING 7.5.16 Create Validation ? First Name Not Null Create another validation. This validation will check whether the first name of a new customer is provided. It is fired only when the New Customer option is selected. Property Value Name First Name is Not Null Sequence 20 Type (Validation) Item is NOT NULL Item P11_CUST_FIRST_NAME Error Message #LABEL# must have some value. Associated Item P11_CUST_FIRST_NAME Type (Server-side Condition) Item = Value Item P11_CUSTOMER_OPTIONS Value NEW Using the previous table, create NOT NULL validations for Last Name, State, Postal Code, and Credit Limit items. 7.5.17 Create Validation ? Phone Number Create the following validation to check input of proper phone numbers.Regular Expressions enable you to search for patterns in string data by using standardized syntax conventions, rather than just a straight character comparisons. The validation passes if the phone numbers matches the regular expression attribute and fails if the item value does not match the regular expression. The last three properties inform Oracle APEX to execute the validation only when a new customer is created. Property Value Name Phone Number Format Type (Validation) Item matches Regular Expression Item P11_PHONE_NUMBER1 Regular Expression ^\(?[[:digit:]]{3}\)?[-. ][[:digit:]]{3}[-. ][[:digit:]]{4}$ Error Message Phone number format not recognized Associated Item P11_PHONE_NUMBER1 Type (Server-side Condition) Item = Value Item P11_CUSTOMER_OPTIONS Value NEW Create a similar validation for P11_PHONE_NUMBER2 item. Next, you have to turn off the Value Required attribute for P11_CUSTOMER_ID (in Existing Customer region) , and P11_CUST_FIRST_NAME, P11_CUST_LAST_NAME, P11_CUST_STATE, P11_CUST_POSTAL_CODE, P11_CREDIT_LIMIT and P11_CUST_EMAIL (in New Customer Details region). The Value Required properties for these items were inherited from Page 7 where they were set to On, to mark them as mandatory. In the previous two sections, you used an alternate method to manually control the validation process for these items. If you don?t reverse the Value Required status, then the application will throw NOT NULL errors for these items, even if you select an existing customer. 7.5.18 Create Branch When the Next button is clicked, the defined button action (Submit Page) triggers after performing all validations. The submit page process executes instructions specified in this branch and moves the user to the next order wizard step. On the Processing tab, right-click the After Processing node and select Create Branch. Set the following properties for the new branch. Property ValueName Go To Page 12 Type (under Behavior) Page or URL (Redirect) Target Type = Page in this Application Page = 12 Clear Cache = 12 When Button Pressed NEXT Test Your Work From the main menu, select Orders and click the Enter New Order button. Your page should look like Figure 7-23. Select Existing Customer and click the LOV button to call list of customers. Click the name of a customer from the list. The name of the selected customer appears in the Customer box. This is how an existing customer is selected for an order. Now, click the New Customer option, the Dynamic Action created in section 7.5.13 invokes and performs two actions. First, it hides the Customer box and the LOV. Second, it shows a form similar to the one you created in Chapter 5 to add a new customer record. Click the Next button without putting any value in the provided form. An inline message box will appear with six errors. This is the procedure you handled in the validation sections. After correcting all the form errors if you click Next, the message ?Sorry, this page isn't available? pops up indicating that Page 12 doesn?t exist. Your next task is to create Page 12 where you?ll select products for an order. ## 7.6 Create Select Items Page - Pages 12 Having identified the customer, the second step in the order wizard is to add products to the order. In this exercise, you will create Page 12 of the application to select ordered items and input the required quantities. 1. Click the Create Page button in the App Builder interface. 2. This time, select the Blank Page option. This option is selected to create an application page from scratch. Using this option you can create and customize a page according to your own specific needs. 3. Complete the first Page Attributes screen as show in the following figure and click Next.Figure 7-26 4. On the Navigation Menu screen, set Navigation Preference to Identify an existing navigation menu entry for this page, Existing Navigation Menu Entry to Orders, and click Next. 5. Click Finish to end the wizard. ### 7.6.1 Modify Page Properties You styled the Detail View of an interactive report in the previous chapter to customize its look. Here as well, you will apply some styling rules to give the page a professional touch. Previously, you added rules to a single page element: HTML table. In the following exercise you?ll apply rules to the whole page. Before getting your feet wet, go through the following topic to understand Cascading Style Sheets (CSS). Cascading Style Sheets A cascading style sheet (CSS) provides a way to control the style of a web page without changing its structure. When used properly, a CSS separates visual properties such as color, margins, and fonts from the structure of the HTML document. In this chapter, you will use CSS to style Page 12 (Select Items - Figure 7- 27). On this page you will add class properties to PL/SQL code and will reference them in CSS in the HTML Head section. Before moving on to understand the actual functionality, let?s first take a look at a simple example on how to use class attribute in an HTML document. The class attribute is mostly used to point to a class in a style sheet. The syntax is ``` <element class="classname">. <html><head> <style type="text/css"> h1.header {color:blue;} p.styledpara {color:red;} </style> </head> <body> <h1 class="header">Class Referenced in CSS</h1> <p>A normal paragraph.</p> <p class="styledpara">Note that this is an important paragraph.</p> </body> </html> The body of this web page contains three sections: <h1 class="header">Class Referenced in CSS</h1> ``` The text ?Class Referenced in CSS? is enclosed in h1 html tag. It is called level 1 heading and is the most important heading in a document. It is usually used to indicate the title of the document. The text is preceded by a class named ?header?. Considering the class syntax, h1 is the element and header is the classname. This class is referenced in the style section using a CSS rule ? h1.header {color:blue;} ? to present the heading in blue color. A CSS rule has two main parts: a selector and one or more declarations. The selector is normally the HTML element you want to style. Each declaration consists of a property and a value. The property is the style attribute you want to change. Each property has a value. In the h1.header {color:blue;} rule, h1 is the selector, header is the classname, and {color:blue;} is the declaration. <p>A normal paragraph.</p> ? It is a plain paragraph without any style applied to it. HTML documents are divided into paragraphs and paragraphs are defined with the <p> tag. The <p> tag is called the start tag or opening tag, while </p> is called the end or closing tag. <p class="styledpara">Note that this is an importantparagraph.</p> ? It is a paragraph with a class named ?styledpara?. In the style section, the selector ?p? followed by the classname ?styledpara? with the declaration{color:red;} is referencing this section to present the paragraph text in red color. Now that you have understood how CSS is used in web pages, let?s figure out how it is used in Oracle APEX. 1. Click the root node ? Page 12: Order Items. 2. Set Dialog Template to Wizard Modal Dialog. 3. Set Width and Height to 500 and 600, respectively. 4. Enter the following code for inline property under CSS section and save your work. You can find this code in BookCode\Chapter7\7.6.1.txt file. CSS rules entered in this box will be applied to all the referenced elements on the current page, as illustrated in Figure 7-27. ``` div.CustomerInfo{margin: 10px 10px 0;} div.CustomerInfo strong{font:bold 12px/16px Arial,sans-serif;display:block;width:120px;} div.CustomerInfo p{display:block;margin:0; font: normal 12px/16px Arial, sans-serif;} div.Products{clear:both;margin:16px 0 0 0;padding:0 8px 0 0;} div.Products table{border:1px solid #CCC;border-bottom:none;} div.Products table th{background-color:#DDD;color:#000;font:bold 12px/16px Arial,sans-serif;padding:4px 10px;text-align:right;border-bottom:1px solid #CCC;} div.Products table td{border-bottom:1px solid #CCC;font:normal 12px/16px Arial,sans-serif; padding:4px 10px;text-align:right;} div.Products table td a{color:#000;} div.Products .left{text-align:left;} div.CartItem{padding:8px 8px 0 8px;font:normal 11px/14px Arial,sans-serif;} div.CartItem a{color:#000;} div.CartItem span{display:block;text-align:right;padding:8px 0 0 0;} div.CartItem span.subtotal{font-weight:bold;} div.CartTotal{margin-top:8px;padding:8px;border-top:1px dotted #AAA;} div.CartTotal span{display:block;text-align:right;font:normal 11px/14px Arial,sans-serif;padding:0 0 4px 0;} div.CartTotal p{padding:0;margin:0;font:normal 11px/14px Arial,sans-serif;position:relative;} div.CartTotal p.CartTotal{font:bold 12px/14px Arial,sans-serif;padding:8px 0 0 0;} div.CartTotal p.CartTotal span{font:bold 12px/14px Arial,sans-serif;padding:8px 0 0 0;} div.CartTotal p span{padding:0;position:absolute;right:0;top:0;} ``` ### 7.6.2 Create Region ? Order Progress Right-click the Wizard Progress Bar node and select Create Region. Set the following properties for the new region. A similar region was added previously to Page 11 to display the Order Progress bar. Property ValueTitle Order Progress Type List List Order Wizard Template Blank with Attributes List Template (under Attributes node) Wizard Progress ### 7.6.3 Create Region ? Select Items The region being created in this section is based on a custom PL/SQL code. The code references CSS rules (defined in the previous section) to design the Select Items page, as illustrated in Figure 7-27. What is PL/SQL? PL/SQL stands for Procedural Language/Structured Query Language. It is a programming language that uses detailed sequential instructions to process data. A PL/SQL program combines SQL command (such as Select and Update) with procedural commands for tasks, such as manipulating variable values, evaluating IF/THEN logic structure, and creating loop structures that repeat instructions multiple times until the condition satisfies the defined criteria. PL/SQL was expressly designed for this purpose. The structure of a PL/SQL program block is: ``` Declare Variable declaration Begin Program statements Exception Error-handling statements End; ``` PL/SQL program variables are declared in the program?s declaration section. The beginning of the declaration section is marked with the reserved word DECLARE . You can declare multiple variables in the declaration section. The body of a PL/SQL block consists of program statements, which can be assigned statements, conditional statements, loop statements, and so on. The body lies between the BEGIN and EXCEPTION statements. The exception section contains program statements for error handling. Finally, PL/SQL programs end with the END; statement. Comments in PL/SQL code are added by prefixing them with double hyphens.In a PL/SQL program block, the DECLARE and EXCEPTION sections are optional. If there are no variables to declare, you can omit the DECLARE section and start the program with the BEGIN command. 1. Right-click the Order Progress region and select Create Sub Region from the context menu. 2. Enter Select Items for its Title and set its Type to PL/SQL Dynamic Content to display the page content using PL/SQL code. PL/SQL Dynamic Content displays the HTML output from the PL/SQL code. 3. Add the code defined in the PL/SQL Code column (Table 7-1) in the PL/SQL Code property (in the Source section). You can find this code in BookCode\Chapter7\7.6.3.txt file. The first column (CSS Rule) in the following table references the rules defined in the previous section. These rules are applied to the injected HTML elements in the PL/SQL code. The second table column is populated with a serial number assigned to each PL/SQL code. These numbers are referenced in the explanation section underneath. 4. Do not set any option for the Template property (in other words, change it from the default Standard value to the -Select- placeholder). ``` declare l_customer_id varchar2(30) := :P11_CUSTOMER_ID; begin -- -- display customer information -- sys.htp.p('<div class="CustomerInfo">'); if :P11_CUSTOMER_OPTIONS = 'EXISTING' then for x in (select * from demo_customers where customer_id = l_customer_id) loop sys.htp.p('<div class="CustomerInfo">'); sys.htp.p('<strong>Customer:</strong>'); sys.htp.p('<p>'); sys.htp.p(sys.htf.escape_sc(x.cust_first_name) || ' ' || sys.htf.escape_sc(x.cust_last_name) || '<br />'); sys.htp.p(sys.htf.escape_sc(x.cust_street_address1) || '<br />'); if x.cust_street_address2 is not null then sys.htp.p(sys.htf.escape_sc(x.cust_street_address2) || '<br />'); end if; sys.htp.p(sys.htf.escape_sc(x.cust_city) || ', ' || sys.htf.escape_sc(x.cust_state) || ' ' || sys.htf.escape_sc(x.cust_postal_code)); sys.htp.p('</p>'); end loop; else sys.htp.p('<strong>Customer:</strong>'); sys.htp.p('<p>'); sys.htp.p(sys.htf.escape_sc(:P11_CUST_FIRST_NAME) || ' ' || sys.htf.escape_sc(:P11_CUST_LAST_NAME) || '<br />'); sys.htp.p(sys.htf.escape_sc(:P11_CUST_STREET_ADDRESS1) || '<br />'); if :P11_CUST_STREET_ADDRESS2 is not null then sys.htp.p(sys.htf.escape_sc(:P11_CUST_STREET_ADDRESS2) || '<br />'); end if; sys.htp.p(sys.htf.escape_sc(:P11_CUST_CITY) || ', ' || sys.htf.escape_sc(:P11_CUST_STATE) || ' ' || sys.htf.escape_sc(:P11_CUST_POSTAL_CODE)); sys.htp.p('</p>'); end if; sys.htp.p('</div>'); -- display products -- sys.htp.p('<div class="Products" >'); sys.htp.p('<table width="100%" cellspacing="0" cellpadding="0" border="0"> <thead> <tr><th class="left">Product</th><th>Price</th><th></th></tr> </thead> <tbody>'); for c1 in (select product_id, product_name, list_price, 'Add to Cart' add_to_order from demo_product_info where product_avail = 'Y' order by product_name) loop sys.htp.p('<tr><td class="left">'||sys.htf.escape_sc(c1.product_name)||'</td> <td>'||trim(to_char(c1.list_price,'999G999G990D00')) || '</td> <td><a href="'||apex_util.prepare_url('f?p=&APP_ID.:12:'||:app_session||':ADD:::P12_PRODUCT_ID:'|| c1.product_id)||'" class="t-Button t-Button--simple t-Button--hot"><span>Add<i class="iR"></i></span></a></td> </tr>'); end loop; sys.htp.p('</tbody></table>'); sys.htp.p('</div>'); -- -- display current order -- sys.htp.p('<div class="Products" >'); sys.htp.p('<table width="100%" cellspacing="0" cellpadding="0" border="0"> <thead> <tr><th class="left">Current Order</th></tr> </thead> </table> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tbody>'); declare c number := 0; t number := 0; begin -- loop over cart values for c1 in (select c001 pid, c002 i, to_number(c003) p, count(c002) q, sum(c003) ep, 'Remove' remove from apex_collections where collection_name = 'ORDER' group by c001, c002, c003 order by c002) loop sys.htp.p('<div class="CartItem"> <a href="'||apex_util.prepare_url('f?p=&APP_ID.:12:&SESSION.:REMOVE:::P12_PRODUCT_ID:'||sys.htf.escape_sc(c1.pid))||'"><img src="#IMAGE_PREFIX#delete.gif" alt="Remove from cart" title="Remove from cart" /></a>   '||sys.htf.escape_sc(c1.i)||' <span>'||trim(to_char(c1.p,'$999G999G999D00'))||'</span> <span>Quantity: '||c1.q||'</span> <span class="subtotal">Subtotal: '||trim(to_char(c1.ep,'$999G999G999D00'))||'</span> </div>'); c := c + 1; t := t + c1.ep; end loop; sys.htp.p('</tbody></table>'); if c > 0 then sys.htp.p('<div class="CartTotal"> <p>Items: <span>'||c||'</span></p> <p class="CartTotal">Total: <span>'||trim(to_char(t,'$999G999G999D00'))||'</span></p> </div>'); else sys.htp.p('<div class="alertMessage info" style="margin-top: 8px;">'); sys.htp.p('<img src="#IMAGE_PREFIX#f_spacer.gif">'); sys.htp.p('<div class="innerMessage">'); sys.htp.p('<h3>Note</h3>'); sys.htp.p('<p>You have no items in your current order.</p>'); sys.htp.p('</div>'); sys.htp.p('</div>'); end if; end; sys.htp.p('</div>'); end; ``` NOTE: The ELSE block (lines 70-76) executes when the user tries to move on without selecting a product in the current order. The block uses a built-in class (alertMessage info) that carries an image (f_spacer.gif) followed by the message specified on lines 73-74. In this PL/SQL code you merged some HTML elements to deliver the page in your browser. Before getting into the code details, let?s first acquaint ourselves with some specific terms and objects used in the PL/SQL code. Using HTML in PL/SQL Code Oracle APEX installs with your Oracle database and is comprised of data in tables and PL/SQL code. Whether you are running the Oracle APEX development environment or an application you built using Oracle APEX, the process is the same. Your browser sends a URL request, which is translated into an appropriate Oracle APEX PL/SQL call. After the database processes the PL/SQL, the results are relayed back to your browser as HTML. This cycle happens each time you either request or submit a page. Specific HTML content not handled by Oracle APEX (forms, reports, and charts) are generated using the PL/SQL region type. You can use PL/SQL to have more control over dynamically generated HTML within a region, as you do here. Let?s see how these two core technologies are used together. htp and htf Packages: htp (hypertext procedures) and htf (hypertext functions) are part of PL/SQL Web Toolkit package to generate HTML tags. These packages translate PL/SQL into HTML understood by a web browser. For instance, the htp.anchor procedure generates the HTML anchor tag a. The following PL/SQL block generate a simple HTML document: ``` CREATE OR REPLACE PROCEDURE hello AS BEGIN htp.htmlopen; -- generates <HTML> htp.headopen; -- generates <HEAD> htp.title('Hello'); -- generates <TITLE>Hello</TITLE> htp.headclose; -- generates </HEAD> htp.bodyopen; -- generates <BODY> htp.header(1, 'Hello'); -- generates <H1>Hello</H1> htp.bodyclose; -- generates </BODY> htp.htmlclose; -- generates </HTML> END; ``` Oracle provided the htp.p tag to allow you to override any PL/SQL-HTML procedure or even a tag that did not exist. If a developer wishes to use a new HTML tag or simply is unaware of the PL/SQL analog to the html tag, s/he can use the htp.p procedure. For every htp procedure that generates HTML tags, there is a corresponding htf function with identical parameters. The function versions do not directly generate output in your web page. Instead, they pass their output as return values to the statements that invoked them. htp.p / htp.print: Generates the specified parameter as a string ``` htp.p(?<p>?): Indicates that the text coming after the tag is to be formatted as a paragraph <strong>Customer:</strong>: Renders the text they surround in bold htf.escape_sc: Escape_sc is a function, which replaces characters that have special meaning in HTML with their escape sequence. converts occurrence of & to & converts occurrence of ? to " converts occurrence of < to < converts occurrence of > to > ``` To prevent XSS (Cross Site Scripting) attacks, you must call SYS.HTF.ESCAPE_SC to prevent embedded JavaScript code from being executed when you inject the string into an HTML page. The SYS prefix isused to signify Oracle?s SYS schema. The HTP and HTF packages normally exist in the SYS schema and Oracle APEX relies on them. Cursor FOR LOOP Statement The cursor FOR LOOP statement implicitly declares its loop index as a record variable of the row type that a specified cursor returns and then opens a cursor. With each iteration, the cursor FOR LOOP statement fetches a row from the result set into the record. When there are no more rows to fetch, the cursor FOR LOOP statement closes the cursor. The cursor also closes if a statement inside the loop transfers control outside the loop or raises an exception. The cursor FOR LOOP statement lets you run a SELECT statement and then immediately loop through the rows of the result set. This statement can use either an implicit or explicit cursor. If you use the SELECT statement only in the cursor FOR LOOP statement, then specify the SELECT statement inside the cursor FOR LOOP statement, as in Example A. This form of the cursor FOR LOOP statement uses an implicit cursor and is called an implicit cursor FOR LOOP statement. Because the implicit cursor is internal to the statement, you cannot reference it with the name SQL. Example A - Implicit Cursor FOR LOOP Statement ``` BEGIN FOR item IN ( SELECT last_name, job_id FROM employees WHERE job_id LIKE '%CLERK%' AND manager_id > 120 ORDER BY last_name ) LOOP DBMS_OUTPUT.PUT_LINE ('Name = ' || item.last_name || ', Job = ' || item.job_id); END LOOP; END; / ``` If you use the SELECT statement multiple times in the same PL/SQL unit, define an explicit cursor for it and specify that cursor in the cursor FOR LOOP statement, as shown in Example B. This form of the cursor FOR LOOP statement is called an explicit cursor FOR LOOP statement. You can use the same explicit cursor elsewhere in the same PL/SQL unit. Example B - Explicit Cursor FOR LOOP Statement ``` DECLARE CURSOR c1 IS SELECT last_name, job_id FROM employees WHERE job_id LIKE '%CLERK%' AND manager_id > 120 ORDER BY last_name; BEGIN FOR item IN c1 LOOP DBMS_OUTPUT.PUT_LINE ('Name = ' || item.last_name || ', Job = ' || item.job_id); END LOOP; END; / ``` TABLE 7-1 PL/SQL CODE EXPLAINED Display Customer Information (Lines 7-32) This procedure fetches information of the selected customer and presents it in a desirable format (as shown in Figure 7-27) using the CSS rules defined under the class CustomerInfo. Declare (Line: 1) This is the parent PL/SQL block. A nested block is also used under the Display Current Order section on line:48.l_customer_id varchar2(30) := :P11_CUSTOMER_ID; (Line: 2) Assigns customer ID, which is retrieved from the previous order wizard step (Page 11), to the variable l_customer_id. This variable is used in a SQL statement (on Line No. 9) to fetch details of the selected customer. In PL/SQL, the symbol := is called the assignment operator. The variable, which is being assigned the new value, is placed on the left side of the assignment operator and the value is placed on the right side of the operator. :P11_CUSTOMER_ID is called a bind variable. Bind variables are substituion variables that are used in place of literals. You can use bind variables syntax anywhere in Oracle APEX where you are using SQL or PL/SQL to reference session state of a specified item. For example: SELECT * FROM employees WHERE last_name like '%' || :P99_SEARCH_STRING || '%' In this example, the search string is a page item. If the region type is defined as SQL Query, then you can reference the value using standard SQL bind variable syntax. Using bind variables ensures that parsed representations of SQL queries are reused by the database, optimizing memory usage by the server. The use of bind variables is encouraged in Oracle APEX. Bind variables help you protect your Oracle APEX application from SQL injection attacks. Bind variables work in much the same way as passing data to a stored procedure. Bind variables automatically treat all input data as ?flat? data and never mistake it for SQL code. Besides the prevention of SQL injection attacks, there are other performance-related benefits to its use. You declare a page item as a bind variable by prefixing a colon character (:) like this: :P11_CUSTOMER_OPTIONS. When using bind variable syntax, remember the following rules: 1. Bind variable names must correspond to an item name 2. Bind variable names are not case-sensitive 3. Bind variable names cannot be longer than 30 characters Although page item and application item names can be up to 255 characters, if you intend to use an application item within SQL using bind variablesyntax, the item name must be 30 characters or less. Begin (Line: 3) Read What is PL/SQL at the beginning of this section. The code block from line number 7 to 32 creates the first section on the page (marked as A in Figure 7-27) using div HTML element and styles it using Rule 1 and 2. The code between lines 9-20 is executed when the user selects an existing customer from the previous wizard step. ``` sys.htp.p('<div class="CustomerInfo">'); (Line: 7) The <div> tag defines a division or a section in an HTML document. This is the opening tag, which references the CustomerInfo class in CSS rules to format the following elements. The ending tag is defined on Line 32. for x in (select * from demo_customers where customer_id = l_customer_id) loop (Line: 9) Initiates the FOR loop to locate and fetch record of the selected customer from the demo_customers table. sys.htp.p('<strong>Customer:</strong>'); (Line: 11) Displays the label ?Customer:? in bold. sys.htp.p('<p>'); (Line: 12) The paragraph opening tag. It ends on Line 19. sys.htp.p(sys.htf.escape_sc(x.cust_first_name) || ' ' ||sys.htf.escape_sc(x.cust_last_name) || '<br />'); (Line: 13) Concatenates customer?s first and last names using the concatenation characters (||). The <br /> tag inserts a single line break. sys.htp.p(sys.htf.escape_sc(x.cust_street_address1) || '<br />'); (Line: 14) Show customer?s first address on a new line. if x.cust_street_address2 is not null then (Lines: 15-17) sys.htp.p(sys.htf.escape_sc(x.cust_street_address2) || '<br />'); end if; It?s a condition to check whether the customer?s second address is not null. If it?s not, print it on a new line. sys.htp.p(sys.htf.escape_sc(x.cust_city) || ', ' || sys.htf.escapte_sc(x.cust_state) || ' ' ||sys.htf.escape_sc(x.cust_postal_code)); (Line: 18) Displays city, state, and postal code data on the same row separating each other with a comma and a blank space. sys.htp.p('</p>'); (Line: 19) The paragraph end tag. end loop; (Line: 20) The loop terminates here after fetching details of an existing customer from the database table. sys.htp.p('</div>'); (Line: 32) The div tag terminates here. The output of this section is illustrated in Figure 7-27: A - CustomerInfo. The ELSE block (line 22-30) is executed when a new customer is added to the database from the order interface. In that situation, all values on the current page are fetched from the previous wizard step (Page 11). Display Products (Lines: 36-42) Here you create a section on your web page to display all products along with their prices and include an option, which allows users to add products to their cart. sys.htp.p('<div class="Products" >'); (Line: 36) Creates a division based on the Products class. HTML elements under this division are styled using rules 4-9. sys.htp.p('<table width="100%" cellspacing="0" cellpadding="0" border="0"> (Line: 37) Here you are initiating to draw an HTML table. The <table> tag defines an HTML table. An HTML table consists of the <table> element and one or more <tr>, <th>, and <td> elements. The <tr> element defines a table row, the <th> element defines a table header, and the <td> element defines a table cell. The Width attribute specifies the width of the table. Setting 100% width instructs the browser to consume the full screen width to display the table element. <thead> (Line: 37) <tr><th class="left">Product</th><th>Price</th><th></th></tr> </thead>The <thead> tag is used to group header content in an HTML table. The <thead> element is used in conjunction with the <tbody> and <tfoot> elements to specify each part of a table (header, body, footer). The <tr> tag creates a row for column heading. The three <th> tags specify the headings. The first two columns are labeled Product and Price, respectively. The third column heading is left blank. A specific declaration (class=?left?) is included that points toward the CSS rule (9) div.Products .left{text-align:left;} to align the title of the first column (Product) to the left. The second column (Price) is styled using a general rule (6). <tbody>?); (Line: 37) The <tbody> tag is used to group the body content in an HTML table. This section spans up to line 41 and is marked as B in Figure 7-27. for c1 in (select product_id, product_name, list_price, 'Add to Cart' add_to_order from demo_product_info where product_avail = 'Y' order by product_name) loop (Line: 38) The FOR loop fetches Product ID, Product Name, and List Price columns from the products table. To display a button (Add) in the table, we appended a column aliased add_to_order and populated all rows with a constant value 'Add to Cart'. For further information on FOR LOOP, see the Cursor FOR LOOP Statement section earlier in this section. sys.htp.p('<tr><td class="left">' ||sys.htf.escape_sc(c1.product_name)||'</td> <td>'||trim(to_char(c1.list_price,'999G999G990D00') || '</td> <td><a href=" '||apex_util.prepare_url('f? p=&APP_ID.:12:'||:app_session||' :ADD:::P12_PRODUCT_ID:'|| c1.product_id)||' " class="t-Button t-Button--simple t-Button--hot"> <span>Add<i class="iR"></i> </span></a></td> </tr>'); (Line: 39) ``` This line displays product names with respective prices in two separate columns. The product column is styled using Rule 9, while the price column is styled using Rule 6. There is an Add button in the third column of the table, which is presented as a link using the HTML anchor tag \<a> and is styled #using a built-in class (t-Button). An anchor can be used in two ways: 1. To create a link to another document by using the href attribute. 2. To create a bookmark inside a document by using the name attribute. It is usually referred to as a link or a hyperlink. The most important attribute of \<a> element is the href attribute, which specifies the URL of the page to which the link goes. When this button is clicked, the product it represents is moved to the Current Order section with the help of a process (Add Product to the Order Collection) defined in section 7.6.7. c1 prefix in front of column names, points to the FOR LOOP cursor. The TRIM function in the expression, trim(to_char(c1.list_price,'999G999G990D00')), takes a character expression and returns that expression with leading and/or trailing pad characters removed. This expression initially formats the list price column to add thousand separators and decimal place. Next, it converts the numeric price value to text expression using the TO_CHAR function and finally applies the TRIM function. The TO_CHAR function converts a DATETIME, number, or NTEXT expression to a TEXT expression in a specified format. The table that follows lists the elements of a number format model with some examples. Element Example Description 0 0999 Returns leading zeros. 9990 Returns trailing zeros. 9 9999 Returns value with the specified number of digits with a leading space if positive or with a leading minus if negative. Leading zeros are blank, except for a zero value, which returns a zero for the integer part of the fixed-point number. D 99D99 Returns in the specified position the decimal character, which is the current value of the NLS_NUMERIC_CHARACTER parameter. The default is a period (.).G 9G999 Returns the group separator (which is usually comma) in the specified position. You can specify multiple group separators in a number format model. Use the following SQL statement to check the current value for decimal and group separator characters: ``` SELECT value FROM v$nls_parameters WHERE parameter='NLS_NUMERIC_CHARACTERS'; The code, <a href="'||apex_util.prepare_url('f?p=&APP_ID.:12:'||:app_session||':ADD:::P12_PRODUCT_ID:'|| c1.product_id)||'" class="t-Button t-Button--simple t-Button--hot"> <span>Add<iclass="iR"></i> </span></a>, ``` creates a link with an ADD request. The value of REQUEST is the name of the button the user clicks. For example, suppose you have a button with a name of CHANGE and a label Apply Changes. When a user clicks the button, the value of REQUEST is CHANGE. In section 7.6.7, you will create the following process named Add Product to the order collection. ``` for x in (select p.rowid, p.* from demo_product_info p where product_id=:P12_PRODUCT_ID) loop select count(*) into l_count from wwv_flow_collections where collection_name = 'ORDER' and c001 = x.product_id; if l_count >= 10 then exit; end if; apex_collection.add_member(p_collection_name => 'ORDER', p_c001 => x.product_id, p_c002 => x.product_name, p_c003 => x.list_price, p_c004 => 1, p_c010 => x.rowid); end loop; ``` During the process creation, you?ll select Request=Value in Condition Type and will enter ADD for Value. The ADD request in the \<a> tag is referencing the same expression. When a user clicks the ADD button on the web page, the URL sends the ADD request to the process along with the selected product ID using a hidden item named P12_PRODUCT_ID to be created in section 7.6.4. In turn, the process adds the product to the Current Order section. The URL generated from this code looks something like this at runtime: ``` f?p=18132:12:13238397476902:ADD:::P12_PRODUCT_ID:10end loop; (Line: 40) End of FOR loop. sys.htp.p('</tbody></table>'); (Line: 41) Table and body closing tags. sys.htp.p('</div>'); (Line: 42) The closing div tag. Display Current Order (Lines: 46-79) This section acts as a shopping cart. The products selected by a user are placed in this section. sys.htp.p('<div class="Products" >'); (Line: 46) Defines the <div> tag and utilizes the Products class referenced in rules 4-9. sys.htp.p('<table width="100%" cellspacing="0" cellpadding="0" border="0"> <thead> <tr><th class="left">Current Order</th></tr> </thead> </table> (Line: 47) Displays section heading as follows in the first row of a separate table. Declare (Line: 48) This is a nested or child block. To nest a block means to embed one or more PL/SQL block inside another PL/SQL block to have better control over program?s execution. c number := 0; t number := 0; (Line: 49) Declared two numeric counter variables and initialized them with zero. The variable c is used to evaluate whether any product is selected in the current order, while the variable t stores total value for the order. Begin (Line: 50) for c1 in (select c001 pid, c002 i, to_number(c003) p, count(c002) q, sum(c003) ep, 'Remove' remove from apex_collections where collection_name = 'ORDER'group by c001, c002, c003 order by c001) loop (Line: 52) ``` APEX Collection enables you to temporarily capture one or more non-scalar values. You can use collections to store rows and columns currently in session state so they can be accessed, manipulated, or processed during a user?s specific session. You can think of a collection as a bucket in which you temporarily store and name rows of information. Every collection contains a named list of data elements (or members), which can have up to 50 character properties (varchar2 (4000)), 5 number, 5 date, 1 XML type, 1 BLOB, and 1 CLOB attribute. You insert, update, and delete collection information using the PL/SQL API APEX_COLLECTION. When you create a new collection, you must give it a name that cannot exceed 255 characters. Note that collection names are not case-sensitive and will be converted to uppercase. Once the collection is named, you can access the values (members of a collection) in the collection by running a SQL query against the database view APEX_COLLECTIONS. The APEX_COLLECTIONS view has the following definition: ``` COLLECTION_NAME NOT NULL VARCHAR2(255) SEQ_ID NOT NULL NUMBER C001 VARCHAR2(4000) C002 VARCHAR2(4000) C003 VARCHAR2(4000) C004 VARCHAR2(4000) C005 VARCHAR2(4000) ... C050 VARCHAR2(4000) N001 NUMBER N002 NUMBER N003 NUMBER N004 NUMBER N005 NUMBER CLOB001 CLOB BLOB001 BLOB XMLTYPE001 XMLTYPEMD5_ORIGINAL VARCHAR2(4000) ``` Use the APEX_COLLECTIONS view in an application just as you would use any other table or view in an application, for example: ``` SELECT c001, c002, c003, n001, clob001 FROM APEX_collections WHERE collection_name = 'DEPARTMENTS' ``` The CREATE_OR_TRUNCATE_COLLECTION method creates a new collection if the named collection does not exist. If the named collection already exists, this method truncates it. Truncating a collection empties it, but leaves it in place. In section 7.5.12, we created a process named Create or Truncate Order Collection under the page rendering section and used the following statement to create a collection named ORDER: apex_collection.create_or_truncate_collection (p_collection_name => 'ORDER'); In the ?For C1 in? loop, we?re selecting records from the same ORDER collection. Columns from apex_collections in the SELECT statement correspond to: ``` Column Corresponds To C001 ? pid Product ID (9) C002 ? i Product Name (Men Shoes) C003 ? p List Price (110) C002 - q Quantity (1) C003 - ep Extended Price (110) This value will increase with each Add button click to accumulate total cost of a product. sys.htp.p('<div class="CartItem"> (Line: 53) This line references another class (CartItem) to style the actual Current Order section. <a href="'||apex_util.prepare_url('f? p=&APP_ID.:12:&SESSION.:REMOVE:::P12_PRODUCT_ID:'||sys.htf. <img src="#IMAGE_PREFIX#delete.gif" alt="Remove from cart" title="Remove from cart" /> </a>   (Line: 54) ``` \<a> tag creates a link with a REMOVE request. This time, it usesproduct ID from the collection. In section 7.6.7 (B), there is a process named Remove product from the Order Collection (as shown below) where the request expression is set to REMOVE. ``` for x in (select seq_id, c001 from apex_collections where collection_name = 'ORDER' and c001 = :P12_PRODUCT_ID) loop apex_collection.delete_member(p_collection_name => 'ORDER', p_seq => x.seq_id); end loop; ``` In HTML, images are defined with the \<img> tag. The \<img> tag has no closing tag. To display an image on a page, you need to use the src attribute. Src stands for "source". The value of the src attribute is the URL of the image you want to display. Syntax for defining an image: <img src="url" alt="some_text"/> The URL points to the location where the image is stored. The value of IMAGE_PREFIX determines the virtual path the web server uses to point to the images directory distributed with Oracle APEX. We used ?delete.gif? that is displayed in front of the product name. The required alt attribute specifies an alternate text for an image, if the image cannot be displayed. When a user clicks the remove link [X] in the Current Order section, the URL sends a REMOVE request to the process along with the product ID. The DELETE_MEMBER procedure deletes a specified member from a given named collection using the p_seq => x.seq_id parameter, which is the sequence ID of the collection member to be deleted. ``` '||sys.htf.escape_sc(c1.i)||' (Line: 55) Displays name of the selected product in the Current Order section. <span>'||trim(to_char(c1.p,'$999G999G999D00'))||'</span> (Line: 56) <span>Quantity: '||c1.q||'</span> (Line: 57) <span class="subtotal">Subtotal: '||trim(to_char(c1.ep,'$999G999G999D00'))||'</span> (Line: 58) The three lines display price, quantity, and sub-total of the selected product in the Current Order section, as shown below:</div>'); (Line: 59) The ending div tag. c := c + 1; (Line: 60) This counter increments the value of c with 1 at the end of each loop. The variable c is used to calculate number of items selected in the current order. t := t + c1.ep; (Line: 61) Similar to the variable c, t is also incremented to sum up extended price (c1.ep) to calculate total order value. if c > 0 then sys.htp.p('<div class="CartTotal"> <p>Items: <span>'||c||'</span></p> <p class="CartTotal">Total: <span>'||trim(to_char(t,'$999G999G999D00'))||'</span></p> </div>'); else sys.htp.p('<div class="alertMessage info" style="margin-top: 8px;">'); sys.htp.p('<img src="#IMAGE_PREFIX#f_spacer.gif">'); sys.htp.p('<div class="innerMessage">'); sys.htp.p('<h3>Note</h3>'); sys.htp.p('<p>You have no items in your current order.</p>'); sys.htp.p('</div>'); sys.htp.p('</div>'); end if; ``` (Line: 64-77) The condition (IF c > 0) evaluates whether a product is selected in the current order. A value other than zero in this variable indicates addition of product(s). If the current order has some items added, the label Total: along with the value is displayed, which is stored in the variable t. If no items are selected, the message defined in the else block is shown using a couple of built-in classes. ### 7.6.4 Create Hidden Item Create a hidden item in the Select Items region. When you click the Add button on Page 12 to add a product to an order, the ID of that product is stored in this hidden item using a URL specified in the PL/SQL code on line 39. Property Value 1. Name P12_PRODUCT_ID 2. Type Hidden ### 7.6.5 Create Region to hold Buttons Right-click the Wizard Buttons node and select Create Region. Enter Buttons for the Title of this region and set its Template to Buttons Container. The region will hold three buttons: Cancel, Previous, and Next. These buttons are created in the next section. ### 7.6.6 Create Buttons All the three buttons created in this section have one thing in common, the Action property, which is set to Submit Page. When you click any of these three buttons, the page is submitted and a corresponding branch (to be created in section 7.6.9) is fired to take you to the specified location. For example, if you click the Cancel button, the corresponding branch takes you back to the main Orders page (Page 4). Right-click the new Buttons region and select Create Button. Set the following properties for the new button: Property Value 1. Button Name CANCEL 2. Label Cancel 3. Button Position Close 4. Action Submit Page Create another button under the Cancel button and set the following properties: Property Value 1. Button Name PREVIOUS 2. Label Previous 3. Button Position Previous 4. Button Template Icon 5. Icon fa-chevron-left 6. Action Submit Page Create the final button under the Previous button and set the following properties: Property Value 1. Button Name NEXT 2. Label Place Order 3. Button Position Next 4. Button Template Text with Icon 5. Hot On 6. Icon fa-chevron-right 7. Action Submit Page ### 7.6.7 Create Processes The two processes created in this section handle the routine to either add a product to the Current Order section or remove one from it. The add_member function references the collection (ORDER created in section 7.5.12) to populate the collection with a new product. In Table 7-1, the link defined on line 39 in the PL/SQL code forwards an ADD request, which is entertained here after evaluating the request in step 4 below. A. Add Product to the Order Collection 1. On Page 12, expand the Pre-Rendering node (on the Rendering tab) and create a process under Before Header node. 2. Enter Add Product to the ORDER Collection for the name of this new process and set its Type to PL/SQL Code.Figure 7-28 3. Enter the following code in the PL/SQL Code box. Locate this code under BookCode\Chapter7\7.6.7A.txt file. ``` declare l_count number := 0; begin for x in (select p.rowid, p.* from demo_product_info p where product_id = :P12_PRODUCT_ID) loop select count(*) into l_count from wwv_flow_collections where collection_name = 'ORDER' and c001 = x.product_id; if l_count >= 10 then exit; end if; apex_collection.add_member(p_collection_name => 'ORDER', p_c001 => x.product_id, p_c002 => x.product_name, p_c003 => x.list_price, p_c004 => 1, p_c010 => x.rowid); end loop; end; ``` 4. In Server-side Condition section, set Type to Request=Value, and enter ADD in the Value property box. B. Remove Product from the Order Collection The delete_member function is just opposite to the add_member function. It is called by a link (Table 7-1 line 54), which carries a REMOVE request. Therequest is evaluated by a condition set in Step 3 below. If the request matches, the selected product is deleted from the ORDER collection. 1. Create another process under the previous one. Name it Remove Product from the ORDER Collection and set its Type to PL/SQL Code. 2. Enter the following code in the PL/SQL Code property box. Get this code from BookCode\Chapter7\7.6.7B.txt file. ``` for x in (select seq_id, c001 from apex_collections where collection_name = 'ORDER' and c001 = :P12_PRODUCT_ID) loop apex_collection.delete_member(p_collection_name => 'ORDER', p_seq => x.seq_id); end loop; ``` 3. In Server-side Condition section, set Type to Request=Value, and enter REMOVE in the Value property box. ### 7.6.8 Create Process - Place Order After selecting products for an order, you click the Next button. The process defined in this section is associated with this button. The PL/SQL code specified in this process adds new customer and order information in relevant database tables using a few SQL INSERT statements. After committing the DML statement, the process truncates the ORDER collection. 1. On the Processing tab, create a new process under the Processing node.Figure 7-29 2. Enter Place Order for the name of this new process and set its Type to PL/SQL Code. Enter the following code in the PL/SQL Code box. Also, select NEXT for When Button Pressed property. The code is stored under BookCode\Chapter7\7.6.8.txt file. ``` declare l_order_id number; l_customer_id varchar2(30) := :P11_CUSTOMER_ID; begin -- Create New Customer if :P11_CUSTOMER_OPTIONS = 'NEW' then insert into DEMO_CUSTOMERS ( CUST_FIRST_NAME, CUST_LAST_NAME, CUST_STREET_ADDRESS1, CUST_STREET_ADDRESS2, CUST_CITY, CUST_STATE, CUST_POSTAL_CODE, CUST_EMAIL, PHONE_NUMBER1, PHONE_NUMBER2, URL, CREDIT_LIMIT, TAGS) values ( :P11_CUST_FIRST_NAME, :P11_CUST_LAST_NAME, :P11_CUST_STREET_ADDRESS1, :P11_CUST_STREET_ADDRESS2, :P11_CUST_CITY, :P11_CUST_STATE, :P11_CUST_POSTAL_CODE, :P11_CUST_EMAIL, :P11_PHONE_NUMBER1, :P11_PHONE_NUMBER2, :P11_URL, :P11_CREDIT_LIMIT, :P11_TAGS) returning customer_id into l_customer_id; :P11_CUSTOMER_ID := l_customer_id; end if; -- Insert a row into the Order Header table insert into demo_orders(customer_id, order_total, order_timestamp, user_name) values (l_customer_id, null, systimestamp, upper(:APP_USER)) returning order_id into l_order_id; commit; -- Loop through the ORDER collection and insert rows into the Order Line Item table for x in (select c001, c003, sum(c004) c004 from apex_collections where collection_name = 'ORDER' group by c001, c003) loop insert into demo_order_items(order_item_id, order_id, product_id, unit_price, quantity) values (null, l_order_id, to_number(x.c001), to_number(x.c003),to_number(x.c004)); end loop; commit; -- Set the item P14_ORDER_ID to the order which was just placed :P14_ORDER_ID := l_order_id; -- Truncate the collection after the order has been placed apex_collection.truncate_collection(p_collection_name => 'ORDER'); end; ``` ### 7.6.9 Create Branches Create the following three branches under the After Processing node on the Processing tab. The buttons referenced in these branches were created in section 7.6.6. Property Value 1. Name Go To Page 14 2. Type (under Behavior) Page or URL (Redirect) 3. Target Type = Page in this Application Page = 14 4. When Button Pressed NEXT Property Value 1. Name Go To Page 4 2. Type (under Behavior) Page or URL (Redirect) 3. Target Type = Page in this Application Page = 4 4. When Button Pressed CANCEL Property Value 1. Name Go To Page 11 2. Type (under Behavior) Page or URL (Redirect) 3. Target Type = Page in this Application Page = 11 4. When Button Pressed PREVIOUS Test Your Work Navigate to the Orders page using the main menu route and click the Enter New Order button. Select a customer using the Existing Customer option and click Next. Click the Add button next to Air Jordan 6 shoes to add this product to the Current Order pane. Click the Add button again for this product and see increase in Quantity and Total. Add some more products and observe the change in the Current Order section. Click the cross sign to remove a product from the Current Order section. Click Cancel to return to Page 4 without saving the order. ## 7.7 Create Order Summary Page - Page 14 After adding products to the Order form, you click the Place Order button. The next page, Order Summary, comes up to show details of the placed order. In this section, you will create this page. It is the last step in the order creation wizard. 1. Create one more Blank Page. 2. Complete the first wizard step as show in the following figure and click Next. 3. On the Navigation Menu screen, set Navigation Preference to Identify an existing navigation menu entry for this page, and set Existing Navigation Menu Entry to Orders. Click Next. 4. Click Finish to end the wizard. 5. Click the root node (Page 14: Order Summary) and set Dialog Template to Wizard Modal Dialog. ### 7.7.1 Create Region ? Order Progress Right-click the Wizard Progress Bar node and select Create Region. Set following properties for the new region. Property Value 1. Title Order Progress 2. Type List 3. List Order Wizard 4. Template Blank with Attributes 5. List Template (under Attributes node) Wizard Progress ### 7.7.2 Create Region ? Order Header Right-click the Wizard Body node and select Create Region. Set the following properties for this region. Just like section 7.6.3, you define the region as PL/SQL Dynamic Content, which is based on PL/SQL that enables you to render any HTML or text. Property Value 1. Title Order Header 2. Type PL/SQL Dynamic Content 3. PL/SQL Code ``` begin for x in ( select c.cust_first_name, c.cust_last_name, cust_street_address1, cust_street_address2, cust_city, cust_state, cust_postal_code from demo_customers c, demo_orders o where c.customer_id = o.customer_id and o.order_id = :P14_ORDER_ID ) loop htp.p('<span style="font-size:16px;font-weight:bold;">ORDER #' ||sys.htf.escape_sc(:P14_ORDER_ID) || '</span><br />'); htp.p(sys.htf.escape_sc(x.cust_first_name) || ' ' ||sys.htf.escape_sc(x.cust_last_name) || '<br />'); htp.p(sys.htf.escape_sc(x.cust_street_address1) || '<br />'); if x.cust_street_address2 is not null then htp.p(sys.htf.escape_sc(x.cust_street_address2) || '<br />'); end if; htp.p(sys.htf.escape_sc(x.cust_city) || ', ' || sys.htf.escape_sc(x.cust_state) || ' ' ||sys.htf.escape_sc(x.cust_postal_code) || '<br /><br />'); end loop; end; ``` ### 7.7.3 Create Region ? Order Lines Add another region under the Wizard Body node and set the following properties for this region. After creating this region expand its Columns node and set suitable heading for each column. This region will carry line item information. Property Value 1. Title Order LinesType Classic Report 2. Location Local Database 3. Type SQL Query 4. SQL Query ``` select p.product_name, oi.unit_price, oi.quantity, (oi.unit_price * oi.quantity) extended_price from demo_order_items oi, demo_product_info p where oi.product_id = p.product_id and oi.order_id = :P14_ORDER_ID ``` ### 7.7.4 Create Item Right-click the Order Lines region and select Create Page Item. Set the following properties for the new item. The value for this item was set in the PL/SQL code defined in section 7.6.8 and was utilized in the codes defined in section 7.7.2 and in section 7.7.3 to fetch order information. Property Value Name P14_ORDER_ID Type Hidden 7.7.5 Create Region ? Buttons Right-click the Wizard Buttons node and select Create Region. Enter Buttons for its Name and set its Template to Buttons Container. The region will hold the following button. 7.7.6 Create Button Right-click the new Buttons region node and select Create Button. Set the following properties for the new button: Property Value Button Name BACK Label Back To Orders Button Position Next Hot On Action Redirect to Page in this Application Target Type = Page in this application Page = 4 7.7.7 Create Trigger As the final step of this module, add the following trigger to your schema. The trigger will fire to write order total to the DEMO_ORDERS table when any order item is changed.1. From the main Oracle APEX menu, select SQL Workshop | SQL Commands. Figure 7-31 2. In the SQL Commands interface, enter the code for the new trigger named DEMO_ORDER_ITEMS_AIUD_TOTAL, as illustrated in the following figure, and hit the Run button. The trigger will be created and you will see a confirmation on the Results tab. The code for this trigger is available in BookCode\Chapter7\7.7.7.txt file.Figure 7-32 Complete Testing Congratulation! You have completed the most tiresome but interesting chapter of the book in which you learned numerous techniques. Now you are in a position to test the whole work you performed in this chapter. 1. Select Orders from the main navigation menu and then click the Enter New Order button. 2. Select New Customer. 3. Fill in the New Customer form using your own name, address, and so on. Click Next to proceed. 4. On the Select Items page add some products to the Current Order pane. 5. Click the Place Order button to see the Order Summary page, as illustrated in figure 7-33.Figure 7-33 Order Summary Page NOTE: You might encounter a primary key violation message (ORA-00001: unique constraint (DEMO_ORDERS_PK) violated) while creating first product record. This is because the Sequence object for this table is created with an initial value of 1. Keep clicking the Place Order button unless the record is saved. 6. Click the Back To Orders button in the Order Summary page to return to the orders main page. The newly created order will appear in the orders list. 7. Click the number of the new order to modify it in Order Details page (Page 29). Try to add or remove products on this page and save your modifications.8. Also, try the delete operation by deleting this new order. ## 7.8 Sending Email from Oracle APEX Application You can use the APEX_MAIL package to send an email from an Oracle Application Express application. This package is built on top of the Oracle supplied UTL_SMTP package. Because of this dependence, the UTL_SMTP package must be installed and functioning to use APEX_MAIL. Since we are using the online APEX version, this package is already configured and we can give it a test run. In this section we are going to send an order confirmation email to customers, whose emails exists in the DEMO_CUSTOMERS table. The email will contain a link to access the placed order. 1. Open Page 12 (Order Items) and create a new process under the Place Order process. Set the attributes for this new process as shown on the next page. The PL/SQL code for this process is provided in BookCode\Chapter7\7.8.txt file. The PL/SQL code starts with the declaration of some variables. You can use VARCHAR type for Vbody and Vbody_html variables. Passing values to these variables yield a multi-part message that includes both plain text and HTML content. The settings and capabilities of the recipient's email client determine what displays. Although most modern email clients can read an HTML formatted email, remember that some users disable this functionality to address security issues. On line 7 we fetch email address of the ordering customer, and on line 8 we store customer name in a variable. The CSS code defined on line 10 formats different parts of the email. Line 11 creates the greeting line, while line 12 forms a paragraph containing a link to the customer order. The order is displayed on Page 30 of the application. Remember, you must include a carriage return or line feed (CRLF) every 1000 characters because the SMTP/MIME specification dictates that no single line shall exceed 1000 characters. We used utl_tcp.crlf for the same purpose. Finally, the APEX_MAIL.SEND procedure sends an outbound email message. The following table describes the parameters used in this SEND procedure. Parameter Descriptionp_to (required) Valid email address to which the email is sent. For multiple email addresses, use a comma-separated list. p_from (required) Email address from which the email is sent. This email address must be a valid address. Otherwise, the message is not sent. p_body (required) Body of the email in plain text. If a value is passed to p_body_html, then this is the only text the recipient sees. If a value is not passed to p_body_html, then this text only displays for email clients that do not support HTML or have HTML disabled. A carriage return or line feed (CRLF) must be included every 1000 characters. p_body_html Body of the email in HTML format. p_subj Subject of the email. Property Value Name Send Confirmation Email Type PL/SQL Code PL/SQL Code ``` DECLARE Vbody CLOB; Vbody_html CLOB; Vcust_email varchar2(100); Vcust_name varchar2(100); BEGIN select cust_email into Vcust_email from DEMO_CUSTOMERS where customer_id = :P11_CUSTOMER_ID; select CUST_FIRST_NAME into Vcust_name from DEMO_CUSTOMERS where customer_id = :P11_CUSTOMER_ID; Vbody := 'To view the content of this message, please use an HTML enabled mail client.'||utl_tcp.crlf; Vbody_html := '<html> <head> <style type="text/css"> body{font-family: Arial, Helvetica, sans-serif; font-size:10pt;margin:30px; background-color:#ffffff;} span.sig{font-size: 20px; font-weight:bold; color:#811919;} </style> </head> <body>'||utl_tcp.crlf; Vbody_html := Vbody_html || 'Hi '|| Vcust_name ||','||utl_tcp.crlf||utl_tcp.crlf; Vbody_html := Vbody_html ||'<p> Your order has been confirmed which you can access by clicking <a href="'||APEX_UTIL.HOST_URL('SCRIPT')||'f?p='||:APP_ID|| ':30'||':0::::P30_ORDER_ID:'||:P14_ORDER_ID ||'"> here. </a></p>' ||utl_tcp.crlf; Vbody_html := Vbody_html ||'<p> Regards,</p>'||utl_tcp.crlf; Vbody_html := Vbody_html ||' <span class="sig">Sales Team</span><br />'||utl_tcp.crlf; apex_mail.send( p_to => Vcust_email, p_from => 'sales@abc.com', p_body => Vbody, p_body_html => Vbody_html, p_subj => 'Order Confirmation'); END; ``` Success Message Order confirmation email sent to customer Error Message There was some problem in sending email When Button Pressed NEXT When a customer clicks the link in the email, he is routed to Page 30 (after providing his credentials on the sign in page) to see his order. This page will be created by making a copy of Page 29. There are a couple of default security setting on this page that we need to change as well to allow access to the order. 2. Open Page 29 in Page Designer. From the Create menu, select Page as Copy ? see section 7.5. Enter 30 for New Page Number and Customer Order for New Page Name. On the Navigation Menu screen, select Identify an existing navigation menu entry for this page, and select Orders for Existing Navigation Menu Entry. 3. Open Page 29 (Order Details) and click the root node. Scroll down to the Security section, and set Page Access Protection attribute to Unrestricted. This value is set for a page that is requested using a URL, with or without session state arguments, and having nochecksum. 4. Delete all six buttons and their regions from Page 30. 5. Next, click the P30_ORDER_ID page item located under Wizard Body | Order #&P30_ORDER_ID. region. Set Session State Protection under Security to Unrestricted. By setting this value the item's value can be set by passing the item in a URL or in a form and no checksum is required in the URL. All is set. Modify a customer record by entering your email account. Create a new order for this customer. After clicking the Place Order button on the second wizard screen, you will see the message ? Order confirmation email sent to customer. ? Log out from the application. After a while, you will receive an order confirmation email in your email account. Click the ? here ? link in the email that will take you to the application login page. Immediately after providing your credentials, the copied order details page (Page 30) will appear on your screen displaying the order you just entered. NOTE: If you get ?Your session has expired. Please close this dialog and press your browser's reload button to obtain a new session.? message, then open Page 30, click its root node, and set Page Mode to Normal. ## 7.9 A More Simple Approach I know as a beginner you might be confused with the stuff described in section 7.5 onward. I added this stuff purposely to present something that would be helpful to you in your future endeavors. However, in this section I?ll demonstrate a simpler approach to add, modify, and delete orders using just one interface. 1. Execute all the steps mentioned in section 7.2 to create the two master and details pages. In step 4, set number of the Master Page to 404, and number of the Details Page to 429. NOTE: Make the Interactive Grid visible on the Order Details page (Page 429), as instructed at the end of section 7.2. 2. Open Page 404 and execute the instructions provided in section 7.3.1. In step 5 of section 7.3.1, set Page and Clear Cacheproperties to 429 to point to the correct page number and set the Name property to P429_ORDER_ID. Skip the optional report sections (spanning from 7.3.2 to 7.3.4) at this stage to preserve some time. 3. Set the following attributes for the CREATE button. Note that previously this buttons was used to initiate the order wizard by calling Page 11. Here, we are calling Page 429 to directly enter a new order. Property Value Button Name CREATE Label Enter New Order Button Template Text with Icon Hot On Icon fa-chevron-right Action Redirect to Page in this Application Target Type = Page in this Application Page = 429 Clear Cache = 429 4. Save Page 404. 5. In the Page Finder box, enter 429 and press the Enter key to call Page 429 in the Page Designer. 6. Click the root node (Page 429: Order Details) and set the Page Mode property to Modal Dialog. Set Width, Height, and Maximum Width properties to 900, 800, and 1200, respectively. Also, set Dialog Template (in the Appearance section) to Wizard Modal Dialog. 7. Edit the following items individually and set the corresponding properties shown under each item. The customer ID item, which was displayed as Display Only item in the previous method, will now be rendered as a Select List carrying the names of all customers. The SQL query defined for the Select List automatically shows the correct customer name when you navigate from oneorder to another. P429_CUSTOMER_ID Property Value Type Select List Label Customer Type (List of Values) SQL Query SQL Query select cust_first_name ||' '|| cust_last_name d, customer_id r from demo_customers P429_USER_NAME Property Value Type Select List Label Sales Rep Type (List of Values) SQL Query SQL Query select distinct user_name d, user_name r from demo_orders union select upper(:APP_USER) d, upper(:APP_USER) r from dual order by 1 Display Extra Values Off Display Null Value Off Help Text Use this list to change the Sales Rep associated with the order. 8. In the Region Buttons node, set Button Position property to Edit for GET_PREVIOUS_ORDER_ID and GET_NEXT_ORDER_ID buttons to place them on top of the region. 9. Click the Order Details interactive grid region. Set its Source Type to SQL Query, and replace the default query with the one that follows: select oi.order_item_id, oi.order_id, oi.product_id, pi.product_name, oi.unit_price, oi.quantity, (oi.unit_price * oi.quantity) extended_price from DEMO_ORDER_ITEMS oi, DEMO_PRODUCT_INFO piwhere oi.ORDER_ID = :P429_ORDER_ID and oi.product_id = pi.product_id (+) 10. Under the Columns node, edit the following columns using the specified properties and values. Column Property Value PRODUCT_ID Type Heading Alignment Type (LOV) List of Values Display Null Value Select List Product left Shared Components Products With Price Off PRODUCT_NAME Type Hidden QUANTITY Width (Appearance) Type (Default) PL/SQL Expression 5 PL/SQL Expression 1 (sets 1 as the default q EXTENDED_PRICE Type Heading Alignment Column Alignment Format Mask Query Only ( Source ) Display Only Price right right $5,234.10 On 11. Right-click the Wizard Buttons node and select Create Region. Set Title of the new region to Buttons and Template to Buttons Container. In Regions Buttons node, click the Cancel button and set its Region property (under Layout) to Buttons. Set this region for Delete, Save, and Create buttons, too. This action will place all the four buttons under the Buttons region. 12. Open Page 429 in the Page Designer. On the Processing tab make sure that the Process form Form on DEMO_ORDERS sits before the Order Details - Save Interactive Grid Data process. 13. Click the Save Interactive Grid Data process and switch its Type from Interactive Grid - Automatic Row Processing (DML) to PL/SQL Code. Enter the following code in the PL/SQL Code box. In this code, you specify SQL Insert, Update, and Delete statements to manually handle the three operations for the Interactive Griddata. The :APEX$ROW_STATUS is a built-in substitution string, which is used to refer to the row status in an Interactive Grid. This placeholder returns the status of C if created, U if updated, or D if deleted for the currently processed interactive grid row. Enter "The DML operation performed successfully" in the Success Message box. Similarly, enter "Could not perform the DML operation" in the Error Message box, and save your work. begin case :APEX$ROW_STATUS when 'C' then insert into DEMO_ORDER_ITEMS (order_item_id, order_id, product_id, unit_price, quantity) values (null, :P429_ORDER_ID, :PRODUCT_ID, :UNIT_PRICE, :QUANTITY); when 'U' then update DEMO_ORDER_ITEMS set product_id = :PRODUCT_ID, unit_price = :UNIT_PRICE, quantity = :QUANTITY where order_item_id = :ORDER_ITEM_ID and order_id = :ORDER_ID; when 'D' then delete DEMO_ORDER_ITEMS where order_item_id = :ORDER_ITEM_ID and order_id = :P429_ORDER_ID; end case; end; NOTE: All four input items in the Order Master section on Page 429 are rendered as floating elements (see Template property under Appearance section) in which the label is displayed inside of the input item, and it automatically shrinks once the input field has a value. Test Your Work Click the Enter New Order button (A) on Page 404. Select a customer (B) and pick an order date (C). Click the Edit button (D) in the Order Details region. With a product appearing in the first row (E) along with its default quantity (G), enter some value in the Unit Price column (F), and click the Create button (H). The order will be saved and you will see the success message. On the Order Master page, click the order number you just saved, and then click Add Row (I) to add some more products. Just select aproduct, enter some value in the Quantity column, and click Save. The modified order will be saved as well. Try to remove a product from this order using the Delete Rows option in the Row Actions menu. Finally, click the Delete button on the Order Details page to test order deletion. You?re done! Figure 7-34 Order Master and Detail Pages ## 7.10 Looping Through Interactive Grid If you are an absolute beginner, I would recommend you to skip this section for the time being. Once you get a firm grip on APEX, revert to this section to learn some beyond stuff. In this section, you learn how to loop through each record in an interactive grid to perform some kind of validation. For example, here you will prevent addition of duplicate products in a single order. Of course, you can add a composite unique key constraint on the corresponding table to prevent duplication. But, there are some scenarios where this solution doesn?t fit. For example, if you provide some free samples of a product in an invoice, you need to create two line item entries in your order screen for the same product ? one with a price tag and another free. Execute the following steps to prevent product duplication in an order.1. Open Page 429 in page designer. Click the Form on DEMO_ORDERS static content region (under Wizard Body) and set it Title to Order Master. 2. Click the Order Details interactive grid region and enter ORDER for its Static ID attribute (under Advanced). The ORDER static id will be used as the ID for the interactive grid region, which is useful in developing custom JavaScript behavior for the region, as you will see later in this exercise. 3. Right-click the Items node under the Order Master static content region (under Wizard Body) and select Create Page Item. Set the following attributes for this new item. It is a hidden item that will store 0 (as default) or 1 behind the scene. The value 1 in this item means that there are some duplicate products in the order. This evaluation will be done by a validation ? Check Duplicate Product. Property Value Name P429_PRODDUP Type Hidden Value Protected Off Type (under Source) Null Type (under Default) Static Static Value 0 4. Expand the Columns node (under the Order Details region), and set the following attributes for PRODUCT_NAME column: Property Value Type Text Field Heading Product Name 5. Switch to the Dynamic Actions tab. Right-click the main Events node and select Create Dynamic Action. Set the following attributes for this dynamic action. The dynamic action will execute a JavaScript code that will be fired before submitting the page. The JavaScript code is defined as a custom function ? chkDUP() in step7. Property Value Name Check Duplicate Product Event Before Page Submit Click the Show node (under True) to set the following attributes: Action Execute JavaScript Code Code chkDUP() 6. Create another dynamic action. This time right-click the Change node and select Create Dynamic Action from the context menu. Set the following attributes for this dynamic action, which is being created to fetch product name when a user selects a different product in the Order Details interactive grid. Property Value Name Fetch Product Name Event Change Selection Type Column(s) Region Order Details Column PRODUCT_ID Click the Show node (under True) to set the following attributes: Action Execute PL/SQL Code PL/SQL Code select product_name into :PRODUCT_NA from DEMO_PRODUCT_INFO where product_id = :PRODUCT_ID; Items to submit PRODUCT_ID Items to Return PRODUCT_NAME 7. On the Rendering tab, click the root node - Page 429: Order Details. Scroll down to the Function and Global Variable Declaration section and append the following JavaScript function after the existing code: function chkDUP() { var record; var prodDUP=0;//Identify the particular interactive grid var ig$ = apex.region("ORDER").widget(); var grid = ig$.interactiveGrid("getViews","grid"); //Fetch the model for the interactive grid var model = grid.model; //Select all rows ig$.interactiveGrid("getViews").grid.view$.grid("selectAll"); //Fetch selected records var selectedRecords = grid.view$.grid("getSelectedRecords"); for (idx1=0; idx1 < selectedRecords.length; idx1++) { record = model.getRecord(selectedRecords[idx1][0]); prodcode1 = model.getValue(record,"PRODUCT_NAME"); for (idx2=0; idx2 < selectedRecords.length; idx2++) { record = model.getRecord(selectedRecords[idx2][0]); prodcode2 = model.getValue(record,"PRODUCT_NAME"); if (prodcode1 == prodcode2 && idx1 != idx2) { prodDUP=1; break; } } if (prodDUP == 1) { break; } } $s("P429_PRODDUP",prodDUP); if (prodDUP == 1) { alert("Duplication of product occurred - "+prodcode2); } } The function is called from the Check Duplicate Product dynamic action before the page is submitted. Initially the function identifies the Order Details interactive grid through its static ID. Then, after fetching the interactive grid's model, all rows in the interactive grid are selected. The function then initiates a FOR loop, which loops through every record in the interactive grid. In every loop, value from the Product Name column is stored (in prodcode1 variable) and then compared with another variable in an inner FOR loop. If a duplicate is found, the duplicate switch is turned on ? prodDUP=1. If the switch is turned on, you see the client-side message specified in the alert function. 8. The JavaScript function in the previous step alerts you of duplicateproducts. After the alert, the page is submitted and the order is saved with duplication. A server-side validation must also be created to prevent this situation. On the Processing tab, right-click the Validations node and select Create Validation. Set the following attributes for the new validation, which evaluates the value of P429_PRODDUP hidden page item when either Save or Create buttons are clicked. If the value of this item is zero, the order is processed. If it is set as 1 by the chkDUP function, an error message is fired. Note that if a validation passes the equality test, or evaluates to TRUE, then the validation error message does not display. Validation error messages display when the validation fails the equality test, or evaluates to FALSE, or a non-empty text string is returned. Subsequent processes and branches are not executed if one or more validations fail evaluation. Property Value Name Check Duplicate Products Type (under Validation) Item = Value Item P429_PRODDUP Value 0 Error Message Duplicated product found ? cannot proceed further Display Location Inline in Notification Server-side Condition section Type Request is contained in Value Value SAVE,CREATE Save and run the module. Create a new order. Initially the Product column in the interactive grid defaults to Air Jordan 6. Select a different product to fire the dynamic action and fetch the product name in the Product Name column. Add another row and select the same product on the new row. Input unit price in both rows and click Create. First, you will get the client-side product duplication message from the JavaScript function followed by the error message defined in the validation. ## 7.11 Interactive Grid Native PDF Printing Interactive Grid Downloads includes native PDF Printing which allows youto print PDF files directly from Interactive Grids. This feature produces a PDF file which retains Grid formatting such as highlighting, column grouping, and column breaks. Let?s go through a simple demonstration to explore this feature. 1. Open the Orders Interactive Report page (Page 4) in Page Designer. 2. Right-click the Orders interactive report region, and select Duplicate from the context menu. A copy of this region will be created. Figure 7-35 3. Click the new Orders region, and change its Type property in the Identification section from Interactive Report to Interactive Grid. 4. Click the Attributes node under the new Orders region. In the properties pane, scroll down to Download section and ensure that PDF option (under Download | Formats) is checked. The checkeddownload formats can be utilized by users to download the currently displayed columns in the interactive grid. 5. Save and run the page. The page should now have two regions. Scroll down a bit to see the interactive grid region. From the interactive grid?s Actions menu, select Format | Control Break. 6. On the Control Break dialog, select Order Month from the Column list and click Save. Figure 7-36 7. Next, select Actions | Format | Highlight. Set the following parameters in the Highlight dialog. Once you hit Save in the Highlight dialog, rows with 1000 or greater amount in the Order Total column will be highlighted.Figure 7-37 8. Click the Actions menu again and select Download. In the Download dialog, select PDF and other options as illustrated in the following figure and click the Download button. The output of the interactive grid will be downloaded as a PDF to your device.Figure 7-38 The following figure illustrates the downloaded PDF. As you can see both highlight and control break formattings are preserved in the PDF.Figure 7-39 Summary Here are the highlights of this chapter: Master Detail ? You learned how to implement Master Detail page feature to handle data in two relational tables and went through theauto-generated page components added by the wizard to transparently manage the order processing module. Interactive Report ? Created an interactive report and learned how to alter the report layout by applying highlighting, sorting, and using aggregate functions. You also applied Control Breaks to group related data and added Chart and Group By Views. Primary, Public, and Alternative Interactive Report ? You created three variants of the interactive report and went through the concepts behind these variants. Wizard Steps ? Learned how to create wizard-like interfaces to perform related tasks in a sequence. Copy Page Utility ? The chapter provided a shortcut to utilize an existing page with all functionalities using a different number and for a different scenario. Oracle APEX Collection ? You learned how to use collections to store and retrieve rows and columns information in session state. Custom Processes and Dynamic Actions ? In addition to the auto- generated components and processes, you learned how to manually add your own processes and other components. Using HTML in PL/SQL Code ? You used PL/SQL to have more control over dynamically generated HTML within a region. Using CSS in Oracle APEX Pages ? You applied styling rules to give the page a more professional look. Simple Approach ? Besides the advance techniques, you also learned how to create this module using a simple approach. Looping through Interactive Grid ? In the final section of this chapter you learned how to loop through interactive grid records. You usually execute this procedure when you need to perform some sort of validation on the data in an interactive grid prior to storing it in your database. <br /><br /><br /><br /><br /><br /><a name="gra_mob"></a> # 08. Graphical Reports & Mobile Integration page 304/419 [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....**Graph. & Mobile**.....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) <br /><br /><br /><br /><br /><br /> <a name="advrep"></a> # 09. Produce Advance Reports [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....**Adv. Rep**.....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) <br /><br /><br /><br /><br /><br /> <a name="authoriz"></a> # 10. Authorization - Managing Users & App Access [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....**Authoriz**.....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) <br /><br /><br /><br /><br /><br /><a name="searchstylecal"></a> ## 11.1 Faceted Search [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz)....**Search**.....[Style Theme r.](#themeroll).....[Style buttons](#style_buttons).....[Calendar](#calendar).....[ Deploy](#deploy) <br /><br /><br /><a name="themeroll"></a> ## 11.2 Theme Roller ? Style Your Application [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search, style, calendar](#searchstylecal).....**Style Theme r.**.....[Style buttons](#style_buttons).....[Calendar](#calendar).....[ Deploy](#deploy) <br /><br /><br /><a name="style_buttons"></a> ## 11.3 Styling Buttons [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz)....[Search, style, calendar](#searchstylecal).....[Style Theme r.](#themeroll).....**Style buttons**.....[Calendar](#calendar).....[ Deploy](#deploy) <br /><br /><br /><a name="calendar"></a> ## 11.4 Manage Events via Calendar component [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz)....[Search, style, calendar](#searchstylecal).....[Style Theme r.](#themeroll).....[Style buttons](#style_buttons).....**Calendar**.....[ Deploy](#deploy) <br /><br /><br /><br /><br /><br /> <a name="deploy"></a> # 12. Deploy [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....**Deploy** ## 12.1 About App Deployment dev to production environment Consists of two steps : Export desired components to a script file and import script file into your production environment. Decide where and how app will run. 1. **No Deployment**: dev environment becomes prod environment and nothing is moved to another computer. In this option **users are provided with URL** to access app. 2. **App**: if target computer is already running production Ora DB with all objects. You export app and import it into target DB. 3. **App and Table Structures**: you create two scripts, one for your app and another for DB tbl structures using **Generate DDL utility** in SQL Workshop. 4. **App and DB obj. with Data**: you deploy your app along with all DB objects using **data pump utility** 5. **Individual Components**: With dev phase going on, you can supplement your deployment plan by exporting only selected components. ## 12.2 Export App https://docs.oracle.com/en/database/oracle/application-express/20.1//htmdb/managing-application-backups.html For simplicity, we will **deploy app in the same workspace**. Same technique is applicable to new workspace or prod env. 1. Sign in to APEX and edit (click) Sales Web Application. 2. Click Export/Import icon. On the ensuing page, click Export icon. 4. In "Choose App" section, set App to Sales Web App, and click Export button. 5. A file something like **f145615.sql** will be saved in Download folder under My Doc or in another folder specified in your browser. ## 12.3 Data pump utils DB 20.1c expdp/impdp (since 10g) Up to 40x faster than Exp/Imp Data. Very high-speed movement of data and metadata from one DB to another for a complete DB or subsets of a DB. In addition to basic import and export functionality data pump provides a PL/SQL API and support for external tables. **See oracle_DB18c_devsuite10g_F6i_to_apex.txt**. ## 12.4 Import App Import exported app **f145615.sql into existing workspace you are connected to with a different WS ID**. 1. Go to App Builder interface and click Import icon. 2. On the Import screen, click the Choose File button and select exported file (f145615.sql). For File Type, select **DB App, Page or Component** Export and click Next. 3. After a while a message The export file has been imported successfully will appear. The status bar at the bottom of your screen will show progress during the upload process. Click Next to move on. 4. On the **Install screen**, select default value for Parsing Schema. Set **Build Status** to Run and Build App, Install As Application to Auto Assign New Application ID, and click the Install Application button. After a short while, the application will be installed with a new ID for you to give it a test-run. 5. On the Install page, click the Run Application button. You will encounter an error saying ? You are not authorized to view this application, either because you have not been granted access, or your account has been locked. Please contact the application administrator. ? Application users are not exported as part of your application. When you deploy your application you will need to manually manage your user to role assignments. Roles are exported as part of an application export and imported with application imports. Execute the following step to cope with this error. 6. On the Install page, click the Edit Application button. Go to Shared Components, and click Application Access Control in the Security section. Using the Add User Role Assignment button (A) add the three users as shown in the following figure. In Shared Components, click Security Attributes. Click the Authorization tab, and set Authorization Scheme to No application authorization required (A). Apply the change. Now you will be able to access the application. ## 12.5 Prevent App Modification and Remove Developers Toolbar The Developers Toolbar is used to access the application source. In this exercise, we are going to prevent users from modifying the application by suppressing the toolbar. 1. Open the new application you just imported in the designer interface. 2. Click Shared Components. 3. Click the Globalization Attributes link (under Globalization). 4. Click the Definition tab. 5. Click the Availability tab, set Build Status to Run Application Only, and click Apply Changes. 6. Go to the App Builder interface and see that the new application doesnt have the Edit link. Click the Run button and provide yoursign in credentials. Note that the Developer Toolbar has disappeared as well. 7. To make the application editable again, select App Builder | Workspace Utilities | All Workspace Utilities (A), as illustrated in the following figure. On the Workspace Utilities page, select Build and App Status (B) from the right sidebar. On Build Status and Application Status page, click the application ID in the first report column, change the Build Status to Run and Build Application, and apply the change. Thats it. You have successfully deployed your application in the same workspace. You can apply the same procedure to deploy the application to another environment. Conclusion Oracle APEX has come a long way from its simple beginning. Sky is the limit, you are limited by your imagination. <br /><br /><br /><br /><a name="app_builder"></a>[Top](#top).....[Back](#goAPEXConcepts) ## 2.2 Applications, App. builder [Top](#top).....[Apexws_cloud](#Apexws_cloud).....**App. builder**.....[Page](#page).....[Environm](#environm).....[URL](#url) .....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) 1. ## https://apex.oracle.com/pls/apex/ (+ f?p=4550:1:117485610537637:::::) 2. button "Sign in" opens same URL, page "App Builder" : Page "App Builder" : Create and manage my apps and their pages : 1. "**Create**" icon functionality : 1. New App based on **tables** you select or by providing a valid **SQL** 2. New App from File : **Load** Data Wizard appears to load definitions & data in : CSV, XLSX, XML, TXT or JSON or Copy and Paste **column delimited** data. After loading data into DB tbl, **wizard creates some app. pages based on new tbl** 3. **"App Gallery" -> "Productivity Apps"** eg proj. mngmnt, surveys, shared calendars, and tracking apps, can be installed, run, and removed. 2. "**Import**" icon 3. "**Dashboard**" icon 4. "**Workspace**" Utilities icon <br /><br /><br /><a name="page"></a> ## 2.3 Page eg App. builder -> click my "Sales Web app" icon [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....**Page**.....[Environm](#environm).....[URL](#url) .....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) **Page creation wizards** - option to create a blank page and add components manually, **Page Designer** interface to add more controls after page creation. When you run app requested with a URL, APEX engine relies on **two processes**: 1. **Show Page** is page rendering process, runs **when you request page** using a URL. It assembles all the page attributes including regions (stacked canvases), items, and buttons into a viewable HTML page. When you request a page using a URL, the engine is running Show Page. 2. **Accept Page** performs page processing **when you submit page**. It performs computations, validations, processes, and branching. 1. APEX engine is running **Accept Page** then performing page **processing** during which it 2. saves submitted values in session cache 3. and then performs any computations, validations, or processes. You can create following **types of pages** for your app : 1. **Blank Page** Creates a page without any built-in functionality 2. Report Used to present a SQL query in a formatted style 1. Interactive Report 2. **Interactive Grid** 3. Classic Report 3. Form 1. Editable Interactive **Grid** 2. **Report with Form** 4. **Master Detail** 1. Stacked 2. Side by Side 3. Drill Down 4. Plug-ins 5. Chart 6. Tree 7. Calendar 8. Data Loading <br /><br /><br /> ## 2.4 Region, Items, Buttons ### 1. Region (stacked canvas) serves as container for content **Region template** controls region look, size, determines whether there is border or background color, and what type of fonts to display. Also determines standard placement for any buttons placed in region positions. You can use regions **to group page elements** (such as items or buttons). APEX supports many different **region types** eg **Static Content, Classic Report, Interactive Report, Interactive Grid, Chart**, and more. ### 2. Items Text Field, Textarea, Password, Select List, Checkbox... Item properties : where a label displays, how large an item is, and **if item displays next to or below previous item**. Page item name is eg P7_CUSTOMER_ID = custID item on page 7 (preceded P followed by number pageID). ### 3. Buttons to submit page or to take users to another page Redirect : 1. within the same site where a user submits a page, the Oracle APEX engine executes some processes associated with a particular button and uploads the page's item values to the server - see Figure 1-3 in chapter 1 2. or to a different site In case of a **redirect : nothing is uploaded to the server**. If you change some items values on a page and press a **button created with a redirect action**, those changes will be lost. Button options are: **Icon, Text, and Text with Icon**. You can place buttons either in predefined region positions or with other items in a form - see Figures 1-1, 1-3, and 1-7 in chapter 1. Buttons **control flow of DB apps, are created by right-clicking region** -> select "Create Button" from context menu. By placing buttons (such as Create, Delete, Cancel, Next, Previous , and more) on your web page, you can **post or process by customer provided information** or you can **direct user to another app pg or to another URL**. #### Buttons are used to: 1. **Submit a page** eg to save user input in a DB tbl. When a button on a page is clicked, pg is submitted with REQUEST value that carries btnname. You can **reference value of REQUEST from within PL/SQL using bind variable " :REQUEST.". ** By using this bind variable, you can conditionally process, validate, or branch based on which button the user clicks. You can create processes that execute when the clicks a button. And you can use a more complex condition as demonstrated in the following examples: ``` If :REQUEST in ('EDIT','DELETE') then ... If :REQUEST != 'DELETE' then ... ``` These examples assume existence of buttons named EDIT and DELETE. **You can also use this syntax in PL/SQL Expression conditions**. If you name a button LOGIN, then request looking for Login fails - btnname is case sensitive. 2. Take user to another page within the same app with optional additional properties for **resetting pagination**, setting request value, clearing cache, and setting item values on the target page. 3. Redirect to another URL. 4. Do nothing eg if buttons behavior is defined in a Dynamic Action. 5. Download Printable Report Query. This creates a Submit Page button and also a corresponding branch. When the button is clicked, the output is downloaded from Report Query. <br /><br /><br /><a name="environm"></a> ## 2.5 APEX Web-based app Development Environment to build web apps [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....**Environment**.....[URL](#url) [Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) You are not required to install any client software to develop, deploy, or run Oracle APEX applications. Primary APEX **tools** : 1. **App Builder** - to create dynamic database driven web appls. Here you create and modify your applications and pages. It comprises following : 1. Create: new apps. See section 2.3.2 2. Import: entire Oracle APEX apps developed somewhere else, along with related files. 3. Dashboard: metrics about apps in your workspace eg: Developer Activity, Page Events, Page Count by App, Most Active Pages... 4. Workspace Utilities: Most significant is **Export** app and component metadata to **SQL script file format** that you can import on the same or another compatible instance of APEX. 2. **SQL Workshop** - to browse your DB objects, to run ad-hoc SQL queries, allow App Developers to maintain DB objects eg tables, packages, functions, views... It is beneficial in **hosted environments like apex.oracle.com where direct access to underlying schemas is not provided**. It has five basic components: 1. Object Browser: to review and maintain database objects (tables, views, functions, triggers...). 2. SQL Commands: to run SQL queries. 3. SQL Scripts: to **upload and execute** script files. 4. Utilities: eg Query Builder, Data Workshop, Generate DDL, Schema Comparison... 5. RESTful Services: to define Web Services using SQL and PL/SQL against DB 3. **Team Development** - allows development teams to better manage their Oracle APEX projects by defining **milestones, features, to-dos, and bugs**. Features, to-dos, and bugs can be **associated with specific apps and pages** as necessary. Developers can readily configure feedback to allow their end-users to provide **comments on app**. The feedback also **captures relevant session state details** and can be readily converted to a feature, to-do or bug. 4. **App Gallery - Productivity apps** are a suite of business productivity applications, easily installed with only a few clicks. These solutions can be readily used as production applications to improve business processes and are fully supported by Oracle. Oracle APEX environment has two broad categories: 1. **Development** Environment: Here you have complete control to build and test your applications. 2. **Runtime** Environment: After completing **development** and **testing** phase, you implement your apps in a **production** environment where users can only run these applications and do not have the right to modify them. <br /><br /><br /> ## 2.6 Page Designer : App Builder -> Sales app -> some page 1. **page top, right** ### 2.6.1 Page Designer toolbar (A) It comprises various tools to find a page, lock/unlock a page, undo/redo actions, Create menu, Utilities menu, shared components, save and run page (see tooltips). **Utilities menu** has an option that lets you delete the page being displayed in your browser. **Lock icon (padlock - lokot)** indicates whether a page is currently locked. Is also displayed in Page Designer as well as on App home page - Figure 2-5. This feature enables you **to prevent conflicts during app development**. By locking a page you prevent other developers from editing it. 2. **page top, left** ### 2.6.2 Tree Pane contains four icons (were tabs) and tree nodes Tree nodes : regions, items, buttons, app logic (eg computations, processes, validations), dynamic actions, branches, shared components. 4 icons : 1. **Rendering icon** (B) - contains as nodes in a tree : regions, page items, page buttons, and app logic. **Components** defined in this section appear when a page is rendered. These components can be viewed as a tree, organized either by **processing order** (the default) or by **component type**. The first two buttons to the right of the Rendering label can be used to toggle between rendering trees. Rendering is divided in three stages : 1. pre-Rendering stage **pre**liminary **computations** are performed 2. main rendering stage comprises **regions and its components** 3. **Post**-Rendering stage also carries **computations** that occur after rendering a page. 2. **Dynamic Actions icon** (C) - Displays dynamic actions defined on this page. By creating a dynamic action, you can define complex client-side behavior declaratively without the need for JavaScript. Refer to Dynamic Actions entry in the book?s index to see its utilization in the project application. 3. **Processing icon** (D) - Use this icon to specify app logic eg : 1. **Computations** are APEX's declarative way of **setting an item's values** on page. These are units of logic used to **assign session state to items** and are executed ** at the time page is processed**. 2. **Validation** is **server-side** mechanism designed to check and validate quality, accuracy, and consistency of page submitted data, prior to saving it into DB. If a validation fails, further processing is aborted by the server and existing page is redisplayed with all inline validation errors. 3. **Processing** are **logic controls used to execute DML** (Data Manipulation Language) **or PL/SQL**. Processes are executed **after page is submitted** - typically when user clicks button. 4. **Branches** enable you to create logic controls that **determine how user navigates through app**. The left iconic button to the right of the Processing label displays the components under this tab according to the servers processing order. The middle button organizes these components according to their type, while the third one provides a menu to create a new component in the selected folder. 4. **Page Shared Components icon** (E) - Displays shared components associated with this page. The list on this tab gets populated automatically when you use shared components on a page. 3. ### 2.6.3 Central Pane has two sections Upper section contains three tabs: Layout, Page Search, Help. Lower pane is called **Gallery** and it is **associated with Layout tab**. 1. Layout (F) is a **visual representation of the regions, items, and buttons** that define a page. You can add new regions, items and buttons to a page by selecting them from Gallery at the bottom of the page, drag, drop. 2. Page Search (G) - to search all **page metadata** including regions, items, buttons, dynamic actions, columns, and so on. 3. Help (H) displays **help text for properties (purpose) in Property Editor (right pane)**. Click a property in the Property Editor and then click Help tab (in the Central pane). As you move from one property to next in property editor, Help tab displays it's help text. 4. **right pane** ### 2.6.4 Property Editor (prop, value) for current component in either Tree View or Layout tab As you select component Property Editor updates to reflect current selection. Properties are organized into **functional groups** (Identification, Source, Layout, Appearance, and more) that describe their **purpose**. When you modify or add a value to a property, a **colored vertical bar** appears as a visual **modification indicator** before the property name. <br /><br /><br /><a name="url"></a> ## 2.7 APEX URL Syntax [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page) [Environm](#environm).....**URL** .....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy) ### f?p URL Syntax is a legacy syntax that creates a unique URL structure that identifies address of APEX, app ID, page number, and session ID. **https://apex.oracle.com/pls/apex/f?p=4500:1000:706440515653484** **In code: https://apex.oracle.com/pls/apex/f?p=&APP_ID.:1000:&APP_SESSION.:::::** https:// URL of the server / **pls** is indicator to use the mod_plsql cartridge / **apex** is (default) DAD (database access descriptor) name. DAD describes how HTTP server connects to DB server to fulfill HTTP request. / **f?p=** is a prefix used by Oracle APEX to route the request to the correct engine process **4500** is appID being called : 1000 is page within app to be displayed : 440323506685863558 is **session number** to keep track of user?s session state Developer Toolbar among other tools for developers contains a **Session option**, which shows you the current session state. Clicking it opens a window (called **Session Page**, shown in Figure 2-6) carrying all **items and their current session values**. It is useful for developers to debug pages. When you change some item value on a page and submit it, the value in the session window for that item changes to reflect the current state. Use Page, Find, and View parameters to view session state for the page. The drop-down View menu comprises Page Items, Application Items, Session State, Collections, and All options. Select an option from this list and click the Set button to **refresh the Session State report**. ### Friendly URL Syntax (APEX release >= 20) creates a URL structure that identifies the address of APEX, app, page, and uses a standard URL hierarchy and passes parameters in a similar fashion. You can change existing apps to use Friendly URLs by editing Friendly URLs attribute in app definition : Shared Components | Application Definition Attributes | Properties. **https://apex.oracle.com/pls/apex/POSSYS/r/4500/home?session=702685162362252** Friendly URL Syntax creates a URL with the following directory hierarchy and syntax: https:// apex.oracle.com / pls /apex / myws/ r / 4500 / home?session=16167973992554 Where: 1. myws is the path_prefix which is URI path prefix used to access RESTful Services. When you create a workspace, this value defaults to workspace name. You can customize the URI path prefix by editing the Path Prefix attribute in : Administration | Manage Service | Set Workspace Preferences | SQL Workshop 2. r is the router shortcut. This value is a constant and should never be changed 3. 4500 is the application id 4. home is the alias of the page being displayed. **If no alias is defined, the page number is displayed instead**. 5. ?session=16167973992554 identifies the session ID. <br /><br /><br /> ## 2.8 Substitution Strings (&varname.) and Bind Variables (:item_name) &varname. means prefix ampersand to item name and append period at its end to reference item. :item_name means precede item name with colon. **To make your app more portable**, APEX provides many features. On top of the list are the Substitution Strings that help you **avoid hard-coded references** in your app. Every app has its own unique ID used to identify app and it's metadata within APEX repository. When you move app from your dev. envir. to prod. envir, and if you've hard-coded app references, eg you hard-coded the application ID (101) like this: f?p=101:1:&APP_SESSION and prod. environ. already has an app ID=101, you will be forced to use a different ID, which will **point all your links within app to the wrong ID**. To avoid such situations, you should always use substitution strings. You can avoid hard-coding appID by using **APP_ID substitution string**, which identifies ID of the currently executing app. With the substitution string, the URL looks like: **f?p=&APP_ID.:1:&APP_SESSION.**. Supported syntax for referencing APP_ID : | Reference Type | Syntax | Help | | :------------------------------------------------------------------------- | :---------------------: | :--------------------------- | | Bind variable | :APP_ID | | | Substitution string | &APP_ID. | | There are two ways to get a page to access value of a session state variable: 1. Use **bind variable** to reference the variable from **within SQL or PL/SQL** code, 2. Use **substitution string** from **within an HTML expression** so : ## Using Substitution Strings 1. Include a substitution string **within a template to reference component values** Special substitution strings available within a template are denoted by the number symbol (#). For example: #PRODUCT_ID# - see Chapter 4 Section 4.3.2, 4.3.5, and 4.3.6. 2. **Reference page or app items** using &ITEM. syntax - all capital letters ! For example, you would **refer to a page item named P7_CUSTOMER_ID** in a region, a region title, an item label, or **in any of numerous other contexts in which static text is used**, like this: "&CUSTOMER_ID." Notice required trailing period. When the page is rendered, APEX engine replaces the value of the substitution string **&CUSTOMER_ID. with the value of item P7_CUSTOMER_ID** 3. Use one of many APEX **built-in** substitution strings to achieve specific types of functionality. Eg APP_ID, APP_IMAGES, APP_PAGE_ID, APP_SESSION, APP_USER, LOGIN_URL, LOGOUT_URL. <br /><br /><br /><br /><a name="shared_about"></a>[Top](#top).....[Back](#shared) ## 3.1 Shared (common, appglobal) Components across all app pages eg menu options "Page Shared Components" tab **top left icon (pyramid of 3) in Page Designer (App Builder -> App)** displays a list of **APPLEVEL common elements** applied to that particular page. Shared components are only displayed in this section after you add them to a page. ## Shared comp. list 1. APP LOGIC SECTION : ### 3.1.1 App Definition Attributes Link to Edit App Definition page where you can **modify your app attributes**, including its name, version, and availability options. You can turn on new Friendly URLs option. ### 3.1.2 Application Processes Run PL/SQL logic at a specific point from multiple pages (reports) of an app. You can apply conditions to ** control when** process executes. Currently there are **8 different types** of process that you can include in your app. One significant is **On Demand App Process**. It is a special type of app process which executes when called from : 1. page-level On Demand process 2. or from an Ajax call from the browser. On Demand processes are useful eg **assessing customer's outstanding balance and using that figure (value) on reports eg :** customer invoice, age analysis report, customer balances report and so on. ## Shared comp. list 2. SECURITY SECTION ### 3.1.3 Authentication Schemes (access=prijava, functionalities=prava) These schemes enable us to declaratively define security for our apps quickly and easily. **Authentication** is the process of **establishing identity of every your app user **. Most common auth. process : usrname and psw. These credentials are then evaluated either through 1. built-in APEX Auth. scheme 2. or using a custom scheme with more control. Authentication could involve use of **digital certificates** or a **secure key**, too. If credentials pass, user is allowed to access app. Once a user has been identified, APEX engine keeps track of each user by setting the value of **built-in substitution string APP_USER**. As you create your app, you must determine ** whether to include auth**. You can: 1. Choose to **not require authentication**. Oracle APEX does not check any user credentials. All pages of your app are accessible to all users eg **public informational app website**. 2. Select a built-in authentication scheme. Create an auth. method based on available preconfigured authentication schemes. Each scheme follows a standard behavior for authentication and session management. 3. APEX Accounts. These are user accounts created within and managed in Oracle APEX user repository. When you use this method, your app is authenticated against these accounts. 4. ### DB Account Credentials authentication scheme It utilizes DB schema accounts. This authscheme requires that DB user (schema) exist in local DB. When using this method, **username and password of the DB account is used to authenticate user**. Choose DB Account Credentials **if having one DB account for each named user of your app** is feasible (viable, practicable, executable, workable) and account maintenance using DB tools meets your needs. 5. HTTP Header Variable. It supports the use of header variables to identify a user and to create an Application Express user session. Use this authentication scheme if your company employs a centralized web authentication solution like Oracle Access Manager, which provides single sign-on across apps and technologies. 6. LDAP Directory Verification. You can configure any authentication scheme that uses a login page to use Lightweight Directory Access Protocol (LDAP) to verify the username and password submitted on the login page. App Builder includes wizards and pages that explain how to configure this option. These wizards assume that an LDAP directory accessible to your application for this purpose already exists and that it can respond to a SIMPLE_BIND_S call for credentials verification. 7. Application Server Single Sign-On Server. This one delegates authentication to the Oracle AS Single Sign-On (SSO) Server. To use this authentication scheme, your site must have been registered as a partner application with the SSO server. 8. Create custom authentication scheme. Using this method you can have complete control over the authentication interface. To implement this approach you must provide a PL/SQL function the Application Express engine executes before processing each page request. The Boolean return value of this function determines whether the Application Express engine processes the page normally or displays a failure page. This is the best approach for apps when any of the following is true: 1. Database authentication or other methods are not adequate 2. You want to develop your **own login form** and associated methods 3. You want to control security aspects of session management 4. You want to record or audit activity at the user or session level 5. You want to enforce session activity or expiry limits 6. Your **app consists of multiple apps that operate seamlessly (eg, more than one app ID)** ### 3.1.4 Authorization Schemes To control users access to specific components of your app. An auth. scheme can be specified for an entire app, page, or specific page components such as a region, button, or item. For instance, you can apply an auth. scheme to determine which menu options a user can see, or whether he is allowed to create a new order (using Create button). ## Shared comp. list 3. OTHER COMPONENTS ### 3.1.5 LOVs (Lists of Values) are defined by running LOV wizard - static and dynamic Once created, LOVs are stored in LOVs repository and are utilized by page items Px\_... 1. static LOV displays and returns predefined values such as Yes and No 2. dynamic list is populated using SQL query After creating LOV you associate it to page items such as **select list, radio group, checkbox...**. LOVs at app-level can be added to any page within app, and is easy to locate and update (since all LOV definitions are stored in one location). ### 3.1.6 Plug-Ins framework - was introduced in Oracle APEX 4.0 Allows developers to create their own plug-ins to add additional functionality in a supported and declarative way. Usually, a **tool like Ajax** is used to add custom functionality. The con of this approach is to place the code in different locations such as within the database, in external JavaScript files, and so on. On the other hand, turning that code into a plug-in is more convenient to use and manage because the code resides in one object. With the help of open source jQuery components you can create plug-ins without generating huge amount of code manually. Plug-ins are shared component objects that allow you to extend the functionality of item types, region types, dynamic actions, and process types. The plug-in architecture includes a declarative development environment that lets you create custom versions of these built-in objects. For example, you can create your **own star rating item** that allows your user to provide feedback using a one-to-five star graphic. This new item type can then be used across all your apps. The main part of a plug-in consists of PL/SQL code and can be supplemented with JavaScript and CSS code. A plug-in consists of one or more PL/SQL functions. These functions can either reside in the database (in a package or a set of functions) or be included within the plug-in. NOTE: Plug-in OTN page (https://www.oracle.com/tools/technologies/apex-plug-ins.html) has several different plug-ins developed by APEX community. ### 3.1.7 Shortcuts to avoid repetitive coding of HTML or PL/SQL functions You can use a shortcut to define a page control such as a button, HTML text, or a PL/SQL procedure. Once defined, you can invoke a shortcut using specific syntax unique to the location in which the shortcut is used. Shortcuts can be referenced many times, thus reducing code redundancy. When you create a shortcut, you must specify the type of shortcut you want to create. Oracle APEX supports the following shortcut types: 1. PL/SQL Function Body 2. HTML Text 3. HTML Text with Escaped Special Characters 4. Image 5. Text with JavaScript Escaped Single Quotes 6. Message 7. Message with JavaScript Escaped Special Quotes ## Shared comp. list 4. NAVIGATION ### 3.1.8 Lists - collections of links For each list entry, you specify display text, a target URL, and other attributes to control when and how the list entry displays. Once created, you can add a list to any number of pages within an app by creating a region and specifying the region type as List. You control the display of the list and the appearance of all list entries by linking list to a template. Lists are of two types: **Static Lists** - When you create a static list you define a list entry label and a target (either a page or a URL). You can add list entries when you create the list (from scratch), by copying existing entries or by adding the list entries. You can control when list entries display by defining display conditions. **Dynamic Lists** - are based on a SQL query or a PL/SQL function executed at runtime. ### 3.1.9 Navigation Menu You might have seen a horizontal bar at the top of a website. The options provided on this bar help you navigate to different pages within that site. app Express provides you with a similar component called Navigation Menu. It is an effective way to navigate users between pages of an app. A navigation menu is basically a list with hierarchical entries. When you create an app, the Create app Wizard automatically creates a navigation menu for you and populates it with one or more list entries. Types of navigation menus include Side Me **Navig. Top Menu, or Mega Menu** By default, the navigation menu is displayed as a left sidebar. Users can expand or collapse the Side Navigation Menu by clicking on the menu icon from the header. This navigation menu renders the navigation items using a tree component that enables users to expand or collapse sub items. A Top Navigation Menu displays at the top of the app. You can change how and where a navigation menu displays by editing the app User Interface Details. The Top Navigation Mega Menu template renders your app navigation in a pop-up panel that can be opened or closed from the header menu button. Users can expand or collapse a Mega Menu by clicking on the menu icon from the header. Mega menus are especially useful when you want to display all navigation items at once to your user. ### 3.1.10 Breadcrumb A breadcrumb (A) is a hierarchical list of links rendered using a template. For example, you can display breadcrumbs as a list of links or as a breadcrumb path. A breadcrumb trail indicates where you are within the app from a hierarchical perspective. In addition, you can click a specific breadcrumb link to instantly view the page. For example, in the screen shot below you can access the app home page by clicking its breadcrumb entry (B). You use breadcrumbs as a second level of navigation at the top of each page, complementing other navigation options such as Navigation Menu and Navigation Bar. ### 3.1.11 Navigation Bar List Just like menus, lists, and breadcrumb, a navigation bar is also created to link users to various pages within an app. Typically, a navigation bar carries links such as user id, logout, feedback, help, and so on. It appears on top-right of every app page. While creating a navigation bar, you can specify an image name, label, display sequence, and target location. ## Shared comp. list 5. USER INTERFACE ### 3.1.12 User Interface Attributes The app user interface determines default characteristics of app and optimizes the display for the target environment. This is place where you define your app logo. ### 3.1.13 Themes and Templates Instead of telling App Builder how to design and style your pages using HTML, CSS, and JavaScript code that you may not be familiar with, you only apply theme and templates you want to use and the Oracle APEX engine does the rest of the job for you. A theme is a named collection of templates that defines the look and feel of app user interface. Each theme contains templates for every type of app component and page control, including individual pages, regions,reports, lists, labels, menus, buttons, and list of values. APEX engine constructs the appearance of each page in a app using Templates . Templates define how pages, page controls, and page components display. Templates control the look and feel of the pages in your app using snippets of HTML, CSS, JavaScript and image icons. As you create your app, you specify templates for pages, regions, reports, lists, labels, menus, buttons, and pop-up lists of values. Groups of templates are organized into named collections called themes. App Builder also allows you to access themes and template mechanism so you can create new ones according to your own requirements or amend (improve) existing ones. Oracle APEX ships with an extensive theme repository. Administrators can add themes to the theme repository, as follows: 1. Workspace administrators can create themes that are available to all developers within the workspace. Such themes are called workspace themes. 2. Instance administrators can create public themes by adding them to the Oracle APEX Administration Services. Once added, these public themes are available to all developers across all workspaces in an instance. 3. Apps you create with the Create app Wizard use Universal Theme. Universal Theme - 42 features a responsive design, versatile UI components and enables developers to create web apps without extensive knowledge of HTML, CSS, or JavaScript. Responsive design enables you to design web pages so that the layout fits the available space regardless of the device on which page displays (eg desktop computer, laptop computer, tablet, or smartphone). ## Shared comp. list 6. FILES ### 3.1.14 Static App and Workspace resource Files (img, CSS, JS) Use these two links to upload, edit, and delete static files including images, custom style sheets, JavaScript files. Static App file can be referenced from a specific app only, whereas **workspace file can be accessed by any app in workspace**. Here we use Static app Files option to **upload your app logo**. ## Shared comp. list 7. DATA SOURCES ## Shared comp. list 8. REPORTS ### 3.1.15 Report Queries A report query is a printable document, which can be integrated with an app using buttons, list items, branches, or any other navigational components that allow for using URLs as targets. A report query is based on a standard SQL query. It can be downloaded as a PDF document, a Word document (RTF based), an Excel Spreadsheet (HTML based), or as an HTML file. The layout of a report query is customizable using RTF templates. ### 3.1.16 Report Layouts Use Report Layouts in conjunction with a report region or report query to render data in a printer-friendly format, such as PDF, Word, or Excel. A report layout can be designed using the Template Builder Word plug-in and uploaded as a file of type RTF or XSL-FO. Report regions use a generic XSL-FO layout, which is customizable. ## Shared comp. list 9. GLOBALIZATION ### 3.1.17 Globalization Attributes If you want to develop apps that can run concurrently in different languages, then app Express is the right platform for this. In the Globalization interface, you can specify options such as the app Primary Language, Date/Time format, and some other options related to app globalization. ### 3.1.18 Translate app A single Oracle DB and APEX instance can support an app in multiple languages. Translating an app involves multiple steps. To translate an app developed in App Builder, you must : 1. map the primary and target language 2. seed and export text to a translation file 3. translate the text 4. apply the translation file 5. publish the translated app. <br /><br /><br /><br /><a name="sampleIG"></a>[Top](#top).....[Back](#gosampleIG) ### App Gallery "Sample Database Application# Is finished this tutorial. Is an application that highlights common design concepts. It includes dedicated pages for customers, products, and orders as well as demonstrates the use of reports, charts, calendar, map, and tree. ## 5.6 IG : Learn IG - install "Sample Interactive Grids" app Interactive Grid is a page component, which is used to display data in row/column matrix. In appearance, it looks similar to an Interactive Report (used in the next chapter) and delivers **all features of Interactive Report**, but it also allows you to manipulate data by **clicking on a cell and editing its value (like Clipper Dbedit !)**, which is not available in Interactive Reports. In many ways this grid looks and acts like an Interactive Report. Here are some new features and differences: 1. Rows are fixed height and columns have a specific width that can be adjusted by dragging the border between column headers (G) or with Ctrl+Left/Right keys when the column header has keyboard focus. 2. Columns can be reordered with drag and drop (dragging the handle (E) at the start of a column heading) or with Shift+Left/Right keys when the column header has keyboard focus. 3. Columns can be sorted using the buttons (F) in the column heading or by using Alt+Up/Down key combination. Use the Shift key to add additional sort columns. 4. Columns can be frozen using the Freeze button (D) in the column heading pop-up menu. For example, to freeze the customers? name column (on Page 2), click the Name column heading. A pop-up menu will appear with four options: Hide (A), Control Break (B), Aggregate (C), and Freeze (D). Select Freeze. Drag the border between the Name and Address columns (F) toward right to expand the Name column. 5. By default the toolbar and column headings stick to the top of the page and the footer sticks to the bottom when scrolling. 6. By default pagination uses a "Load More" button.The grid is keyboard navigable with a focused cell and current selected row (single selection by default). 7. Toolbar includes a Reset button by default, which restores all the report settings to their defaults. ### IG : Install Sample Interactive Grids app https://apex.oracle.com/pls/apex/f?p=4000:1:708714070734932::NO:RP:FB_FLOW_ID,F4000_P1_FLOW,P0_FLOWPAGE,RECENT_PAGES:19693,19693,19693 https://apex.oracle.com/pls/apex/possys/r/19693/home (+ ?session=104411212612767) Install sample application to get required tables. 1. App Gallery menu -> **Sample Apps**.Figure 5-10 2. Click icon **Sample Interactive Grids app** - functionality of **new APEX Interactive Grid**. Declarative features : 1. Reporting capabilities 2. Pagination options 3. Editing capabilities 4. Advanced techniques 3. On App Details page, **click Install App button** Minimum Version APEX 20.1, Oracle DB **11.2.0.4 (newer than XE 11.2.0.2.0 !!) ** Released 10-MAR-2020 4. On Install App wizard screen, accept the default Authentication scheme (APEX Accounts) and click Next. 5. On the next wizard screen, click Install App button. After a while, you will see the message Application installed. 6. SQL Workshop main menu -> **Click Object Browser** and see **two required tables** (EBA_DEMO_IG_EMP and EBA_DEMO_IG_PEOPLE) in the left pane under Tables category. ### 5.6.1 IG : Column Groups in IG (Interactive Grid) Groups are used to associate columns together in the grid and Single Row View. Groups are added by expanding the Attributes node within Rendering tree, and right-clicking on Column Groups. Let's try this feature by executing the following steps: 1. Create a new page in your Sales app by clicking the Create Page button. Select the Report option in the first wizard screen, followed by the Interactive Grid option on the next screen. 2. Enter 100 for Page Number, Column Groups for Page Name, set Page Mode to Normal, Breadcrumb to Breadcrumb, Parent Entry to No Parent Entry, Entry Name to Column Groups, and click Next. 3. Select the default Navigation Preference Do not associate this page with a navigation menu entry, because this page is not associated with our sales app. Click Next. 4. On Report Source screen, keep default Off value of Editing Enabled, set Source Type to SQL Query, and enter the following SQL Statement in Enter a SQL SELECT Statement text area. ``` SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno, onleave, notes, flex4 as tags FROM EBA_DEMO_IG_EMP ``` 5. Click Create button to complete the page creation process. 6. In Page Designer, under Column Groups region (in the Rendering tree), right-click the Attributes node, and select Create Column Group (A) from the context menu. In the Properties pane, set the Heading attribute for this new group to **Identity** (cols emp name till dep). 7. Repeat step 6 to create **two more groups**. Enter **Compensation** (cols salary, commission) and **Notes** for their headings. The three column groups should look like (B). 8. Under the Columns Group region, expand the Columns node. Click the **EMPNO column and set its Type to Hidden**. 9. Set appropriate column headings, as shown in Figure 5-11. 10. Use the following table to associate each column with a group created in steps 6 & 7. To establish this association, click any column (ENAME, for example), scroll down to the Layout section, and set the Group property as follows: Column Group Property 1. ENAME Identity 1. JOB Identity 2. MGR Identity 3. HIREDATE Identity 2. SAL Compensation 1. COMM Compensation **DEPTNO Identity** 3. ONLEAVE Notes 1. NOTES Notes 2. TAGS Notes 11. Save your work and run the page. Column group headings can be used to reorder columns just like column headings. Play around with column reordering (using drag and drop - see E in Figure 5-9) to see how group headings are split and joined. ### 5.6.2 IG : Editing Data in IG (Interactive Grid) Interactive Grid allows you to manipulate data by clicking on a cell. When you add an Interactive Grid to a page, you specify (on Report Source wizard screen) whether it is editable?see step 4 in the previous section. If you initially turn this attribute off, you can always reverse it to make the Interactive Grid editable. Here are some points to know about editing: 1. Normally the grid is in navigation mode where arrow keys move from cell to cell. To enter edit mode, press the Edit button (A). 2. Alternatively, double-click a cell or press either the Enter key or F2 key in a cell. 3. To exit edit mode, press the Edit button (A) again or press the Escape key in a cell. 4. Use the Delete key on your keyboard to delete the selected rows. 5. Use the Insert key to add a row. 6. Second column (B) is a menu. It allows you to perform actions on the selected row such as Delete or Duplicate. Use the Revert Changes option from this menu to revert a record marked for deletion. 7. Editing is also supported in Single Row View. All edits are stored locally until you press the Save button (C). If you try to leave the page while there are unsaved changes you will be notified. 8. Any action that causes refreshing the data such as changing a filter or sorting will warn if there are unsaved changes. Pagination does not affect changes. Execute following steps to enable editing in the Interactive Grid you added to Page 100 in the previous section. 1. Click the Attributes node (A) under the Column Group region and turn on the Enabled attribute (B). Make sure all three operations (C) are also enabled. Figure 5-14 2. Scroll down to the Toolbar section to ensure that the Show property is turned on and the two toolbar buttons (Reset and Save) are also enabled. Reset removes any customizations, such as filters, column width, ordering, and so forth, and reloads the report definition from the server. Save will only save changes made to this interactive grid, without needing to save the whole page. The save button will be displayed only when the interactive grid is editable and the end user has the authorization to add, update, or delete records.3. After making these changes, save and run the page. Notice that the row selector (D) and the Selection Actions menu (B) columns (in Figure 5-13) are added automatically. A process named Save Interactive Grid Data is also added to the Processing tab with an Interactive Grid - Automatic Row Processing (DML) type process to perform DML processing for you without writing any SQL code. This process is added by default when an Interactive Grid is made editable. Play around with the interactive grid by adding, modifying, and deleting rows. ### 5.6.3 IG : Changing Column Type By default, the type of a column in an Interactive Grid is inherited from the base table. For example, the names of employees are displayed in a Text Field column type, while their salaries are shown in Number Field column type. In this exercise, you will change the default types of some columns to some other types, as follows: A. The Job column will be presented as a Radio Group to select one from a list of distinct jobs B. The value for the Manager column will be selected from a pop-up LOVC. The Hire Date will use a Date Picker that opens on focus D. Display Yes/No in On Leave column E. The Tags column will use a Shuttle type to select multiple values 1. With Page 100 being displayed in the Page Designer, expand the Columns node and click the JOB column. Set its Type attribute to Radio Group. When you select the radio group type, you are asked to associate a list of values to populate the item. For the List of Values Type attribute, select SQL Query and enter ``` SELECT DISTINCT job a, job b FROM EBA_DEMO_IG_EMP ``` in SQL Query box. Also turn off set Display Extra Values and Display Null Values properties ? see section 5.4.2 for details. The SQL Query fetches distinct job IDs from the table and shows them in the JOB column using the radio group type. 2. Next, click the MGR column and change its Type to Popup LOV. Then, select SQL Query for List of Values Type and enter the following statement in SQL Query box. ``` SELECT ENAME as d, EMPNO as r FROM EBA_DEMO_IG_EMP WHERE JOB = 'MANAGER' or JOB = 'PRESIDENT' order by 1 ``` 3. Click the HIREDATE column. The Type attribute of this column is already set to Date Picker and this is what we want. The only attribute of this column that needs to be changed is Show (under Settings). Change it from on icon click to On focus to display the date picker when the focus is on this column. 4. Click the ONLEAVE column and set its Type to Switch. This will display either On or Off state for this column. 5. Finally, click the TAGS column. Change its Type from Textarea to Shuttle. Set List of Values Type to Static Values and enter static values (by clicking Display1, Display2 text next to the Static Values property) as shown in the following screenshot. Recall that you created a Static LOV through Shared Components interface inChapter 3 - Section 3.4.1. There you specified a pair of static Display and Return values. Here, you didn?t use the Return value, because the Return value is optional. If a Return value is not included, the return value equals the display value. Click the OK button to close the Static Values screen. Figure 5-16 6. Save and run the page. Click different cells under the JOB column and press F2 to see values in a radio group (A). Similarly, press F2 in the Manager column. This will display a drop down list (B) in the selected cell carrying names of president and managers. Double click the column prior to the Hire Date column, and press the Tab key. The cursor?s focus will move on to the Hire Date column and immediately the Date Picker window (C) will pop up. Keep pressing the Tab key to access the On Leave column, which will show a Yes and No switch (D). Access the Tags column, which should come up with a shuttle (E) carrying the five values defined in step 5. Using the arrow key in the shuttle, move all these values to the right pane and click the cross icon to close the shuttle. Click the Save button to write your changes to the database. ### 5.6.4 IG : Protecting Rows in Interactive Grid In this example, you will see how to protect rows in an Interactive Grid. For this purpose, you need to add a column named CTRL to implement a simple rule that Managers and Presidents cannot be edited or deleted. This column is then selected in the Allowed Row Operations Column property in the Attributes node. 1. With Page 100 being displayed in the Page Designer, click the Column Groups region and amend the SELECT statement as follows (the amendment is shown in bold): SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno,onleave,notes, flex4 as tags, **case when JOB = 'MANAGER' or JOB = 'PRESIDENT' then ''** **else 'UD' end as CTRL** FROM EBA_DEMO_IG_EMP 2. After amending the SQL query you will see the CTRL column under the Columns node. Click this column and set its Type to Hidden. Also turn on the Query Only property (under Source). For explanation, see Chapter 7 section 7.4.2. 3. Click the Attributes node under the Column Groups region and set Allowed Row Operations Column (in the Edit section) to the CTRL column.4. Save the page and run it. Click the Edit button. Rows that cannot be edited or deleted are grayed out (A) in the edit mode. NOTE: If you encounter the error Interactive Grid 'Column Groups' doesn't have a primary key column defined which is required for editing or in a master detail relationship, then click the EMPNO column in the Page Designer, and **turn on the Primary Key property** in the Source section. Save and run the page. ### 5.6.5 IG : Scroll Paging Another exciting feature of Interactive Grids is scroll paging (also known as infinite scrolling or virtual paging). It is enabled by setting Pagination attribute to Scroll. After enabling this attribute, the region appears to carry the entire result set but rows are rendered on demand as you scroll. When you scroll down in the Interactive Grid, the model fetches data from the server as it is needed by the view. You can even drag the scroll bar handle all the way to the bottom and then scroll up. You need a database table with lots of records to assess this feature. In this exercise, you will use EBA_DEMO_IG_PEOPLE table, which carries over 4000 records. 1. Create a new page using the instructions mentioned earlier in Section 5.6.1. Set Page Number to 111, set Page Name to Scroll Paging, and enter the following SELECT statement. Rest of the page properties will remain the same. SELECT name, country, rating FROM EBA_DEMO_IG_PEOPLE 2. In the Page Designer, click the Attributes node under the Scroll Paging region. Set Type under the Pagination section to Scroll and turn on the Show Total Row Count. 3. Save and run the page and scroll down using your mouse wheel to test this amazing feature. You will see total number of records at the bottom of the Interactive Grid. ### 5.6.6 IG : Master Detail. And Detail. And Detail... Interactive Grid makes it **effortless to create master-detail relationships** and go any number of levels deep and across. You can create all types of master-detail-detail screens with ease. In this section, I?ll demonstrate this feature. 1. From the SQL Workshop menu, select SQL Scripts and click the Upload button. In the Upload Script screen, click the Choose File button. In the Open dialog box, select master_detail_detail.sql file from Chapter 5 folder in the book?s source code and click Upload. In the SQL Scripts interface click the Run button appearing in the last column. On the Run Script screen, click the Run Now button. The script will execute to create four tables (MD_continent, MD_country, MD_city, and MD_population) along with relevant data to demonstrate the master detail detail feature. You can view these tables from the SQL Workshop > Object Browser interface. 2. Create a new page by clicking the Create Page button in the App Builder interface. This time, select the first Blank Page option and click Next. Set Page Number to 112, Name to Master Detail Detail, Page Mode to Normal, and click Next. On the Navigation Menu screen, select the first Navigation Preference to not associate this page with any sales app navigation menu entry. On the final wizard screen, click Finish. 3. In the Page Designer, right-click the Regions node on the Rendering tab and select Create Region. Set the following properties for the new region. This region will display data from the MD_continent table. **Property Value** 1. Title Continents 2. Type (under Identification) Interactive Grid 3. Type (under Source) SQL Query 4. SQL Query SELECT * FROM MD_continent After entering the SQL query, click anywhere outside the query box. Expand the Columns node under this region. Click the CONTINENT_ID column. Set its Type to Hidden and turn on the Primary Key property (under Source). You must define a primary key column for an interactive grid region, which is required to establish a master detail relationship. 4. Create another region under the Continents region by right-clicking the main Regions node. This region will act as the detail for the Continents region. At run-time when you select a continent, this region will display a list of countries in the selected continent. Set the following properties for this new region. **Property Value** 1. Title Countries 2. Type (under Identification) Interactive Grid 3. Type (under Source) SQL Query 4. SQL Query SELECT * FROM MD_country Expand the Columns node under the Countries region. Click the COUNTRY_ID column. Set its Type to Hidden and turn on the Primary Key property (under Source). You set the Primary Key property to Yes, because this region will act as a master for the Cities region created in the next step. Now, associate this detail region to its master (Continents). Click the Countries region and set the Master Region property (under Master Detail) to Continents. This should be set when this region is the detail region in a master-detail relationship with another region on the page. For the master-detail relationship to work correctly, you must also select the column(s) in the detail region, which are foreign keys to the master region, by setting the Master Column property. Click the CONTINENT_ID column (a foreign key) in the Countries region. Set its Type property to Hidden and Master Column (under Master Detail) to CONTINENT_ID, which references the same column in the master region. 5. Create another region and place it under the Countries region. This region will show a list of cities when you select a country from its master region. Set the following properties for this region: **Property Value** 1. Title Cities 2. Type (under Identification) Interactive Grid 3. Type (under Source) SQL Query 4. SQL Query SELECT * FROM MD_cityMaster Region Countries Expand the Columns node under the Cities region. Click the CITY_ID column. Set its Type to Hidden and turn on the Primary Key property (under Source). Click the COUNTRY_ID column in this region. Set the Type of this column to Hidden and Master Column to COUNTRY_ID to point to the same column in the Countries region. 6. Create the last region to display population of a city. **Property Value** 1. Title Population 2. Type (under Identification) Interactive Grid 3. Type (under Source) SQL Query 4. SQL Query SELECT * FROM MD_population 5. Master Region Cities Expand the Columns node under the Population region. Click the POPULATION_ID column. Set its Type to Hidden. Since this is the last region, you do not need to specify this column as a primary key. However, you have to set a couple of properties for the CITY_ID column in this region to associate it with its master. Click the CITY_ID column, set its Type property to Hidden and Master Column to CITY_ID. That?s it! Save and run the page. Click the row representing Europe (A) in the first region. As you click this row, the second region will display countries in the Europe continent. Click Germany (B) in the second region. This will refresh the third region with a list of cities in Germany. Click the Berlin city (C) to see its population (D) in the forth region.Figure 5-18 ### Summary of 5.6 IG : Techniques in this chapter: 1. Declaratively created **report and form pages and linked them** together 2. Placed **form input items using 12 columns grid layout** 3. Changed default **type of an item and used LOV** 4. Created **validations** to prevent customer record deletion with existing orders and to check customers credit limits. 5. Used a dynamic action to **automatically refresh page** 6. Used various features of **new Interactive Grid** 7. Learned how to **change types of columns** 8. Got hands-on exposure to **Master Detail Detail feature**. <br /><br /><br /><br /><br /> <a name="DBobjects"></a>[Top](#top).....[Back](#goDBobjects) drop table DEMO_ORDER_ITEMS; drop table DEMO_ORDERS; drop table DEMO_ORDERS_ERR$; drop table DEMO_STATES; drop table DEMO_CUSTOMERS; drop table DEMO_CUSTOMERS_ERR$; drop table DEMO_PRODUCT_INFO; ### drop sequence drop sequence DEMO_ORDER_ITEMS_SEQ; drop sequence DEMO_ORDERS_SEQ; drop sequence DEMO_STATES_SEQ; drop sequence DEMO_CUSTOMERS_SEQ_SEQ; drop sequence DEMO_PRODUCT_INFO_SEQ; ### prompt 1. DEMO_ CUSTOMERS ``` --update DEMO_CUSTOMERS set CUST_STREET_ADDRESS2 ='aaaa bbbbb' where CUSTOMER_ID=10 ; --SELECT CUST_STREET_ADDRESS2, CUSTOMER_ID from DEMO_CUSTOMERS order by CUST_LAST_NAME desc ; CREATE table "DEMO_CUSTOMERS" ( "CUSTOMER_ID" NUMBER NOT NULL, "CUST_FIRST_NAME" VARCHAR2(20) NOT NULL, "CUST_LAST_NAME" VARCHAR2(20) NOT NULL, "CUST_STREET_ADDRESS1" VARCHAR2(60), "CUST_STREET_ADDRESS2" VARCHAR2(60), "CUST_CITY" VARCHAR2(30), "CUST_STATE" VARCHAR2(2), "CUST_POSTAL_CODE" VARCHAR2(10), "CUST_EMAIL" VARCHAR2(30), "PHONE_NUMBER1" VARCHAR2(25), "PHONE_NUMBER2" VARCHAR2(25), "URL" VARCHAR2(100), "CREDIT_LIMIT" VARCHAR2(2), "TAGS" VARCHAR2(4000), constraint "DEMO_CUSTOMERS_PK" primary key ("CUSTOMER_ID") ) / -- CONSTRAINT "DEMO_CUST_CREDIT_LIMIT_MAX" CHECK (credit_limit <= 5000) ENABLE, --CONSTRAINT "DEMO_CUSTOMERS_PK" PRIMARY KEY ("CUSTOMER_ID") USING INDEX ENABLE, --CONSTRAINT "DEMO_CUSTOMERS_UK" UNIQUE ("CUST_FIRST_NAME", "CUST_LAST_NAME") USING INDEX ENABLE alter table "DEMO_CUSTOMERS" modify ( "CREDIT_LIMIT" NUMBER(9,2) ) / CREATE sequence "DEMO_CUSTOMERS_SEQ" / CREATE trigger "BI_DEMO_CUSTOMERS" before insert on "DEMO_CUSTOMERS" for each row begin if :NEW."CUSTOMER_ID" is null then select "DEMO_CUSTOMERS_SEQ".nextval into :NEW."CUSTOMER_ID" from sys.dual; end if; end; / ``` ### prompt 2. DEMO_ PRODUCT_ INFO ``` --update DEMO_PRODUCT_INFO set CATEGORY ='aaaa' where PRODUCT_ID=8 ; --SELECT PRODUCT_NAME, CATEGORY, PRODUCT_ID from DEMO_PRODUCT_INFO order by PRODUCT_NAME ; CREATE table "DEMO_PRODUCT_INFO" ( "PRODUCT_ID" NUMBER NOT NULL, "PRODUCT_NAME" VARCHAR2(50), "PRODUCT_DESCRIPTION" VARCHAR2(2000), "CATEGORY" VARCHAR2(30), "PRODUCT_AVAIL" VARCHAR2(1), "LIST_PRICE" NUMBER(8,2), "PRODUCT_IMAGE" BLOB, "MIMETYPE" VARCHAR2(255), "FILENAME" VARCHAR2(400), "IMAGE_LAST_UPDATE" TIMESTAMP(6) WITH LOCAL TIME ZONE, "TAGS" VARCHAR2(4000), constraint "DEMO_PRODUCT_INFO_PK" primary key ("PRODUCT_ID") ) / --alter table "DEMO_PRODUCT_INFO" add column TAGS VARCHAR2(4000) ; CREATE sequence "DEMO_PRODUCT_INFO_SEQ" / CREATE trigger "BI_DEMO_PRODUCT_INFO" before insert on "DEMO_PRODUCT_INFO" for each row begin if :NEW."PRODUCT_ID" is null then select "DEMO_PRODUCT_INFO_SEQ".nextval into :NEW."PRODUCT_ID" from sys.dual; end if; end; / ``` ### prompt 3. DEMO_ STATES (no PK) ``` CREATE table "DEMO_STATES" ( --"STATE_ID" VARCHAR2(2), "ST" VARCHAR2(30), "STATE_NAME" VARCHAR2(30) ) / ``` ### prompt 4. DEMO_ ORDERS update DEMO_ORDERS set ORDER_TIMESTAMP = ORDER_TIMESTAMP + 3600 * 48 ``` Formatting of the TIMESTAMP datatype with fractional seconds: SELECT TO_CHAR(ORDER_TIMESTAMP,'DD.MM.YYYY HH24:MI:SS.FF3') ORDER_TIMESTAMP, ORDER_ID from DEMO_ORDERS order by ORDER_ID desc ; prompt ORDER_TIMESTAMP=30.08.2020 20:18:21:000 ORDER_ID=10 update DEMO_ORDERS set ORDER_TIMESTAMP = TO_TIMESTAMP('01.09.2020 11:10:55.888','DD.MM.RRRR HH24:MI:SS.FF3') where ORDER_ID=10 ; SELECT TO_CHAR(ORDER_TIMESTAMP,'DD.MM.YYYY HH24:MI:SS.FF3') ORDER_TIMESTAMP, ORDER_ID from DEMO_ORDERS order by ORDER_ID desc ; rem Commit statement not applicable. All statements are **automatically committed**. CREATE table "DEMO_ORDERS" ( "ORDER_ID" NUMBER NOT NULL, "CUSTOMER_ID" NUMBER NOT NULL, "ORDER_TOTAL" NUMBER(8,2), "ORDER_TIMESTAMP" TIMESTAMP(6) WITH LOCAL TIME ZONE, "USER_NAME" VARCHAR2(100), "TAGS" VARCHAR2(4000), constraint "DEMO_ORDERS_PK" primary key ("ORDER_ID") ) / CREATE sequence "DEMO_ORDERS_SEQ" / CREATE trigger "BI_DEMO_ORDERS" before insert on "DEMO_ORDERS" for each row begin if :NEW."ORDER_ID" is null then select "DEMO_ORDERS_SEQ".nextval into :NEW."ORDER_ID" from sys.dual; end if; end; / --ALTER TABLE "DEMO_ORDERS" DROP CONSTRAINT "DEMO_ORDERS_FK" ALTER TABLE "DEMO_ORDERS" ADD CONSTRAINT "DEMO_ORDERS_FK" FOREIGN KEY ("CUSTOMER_ID") REFERENCES "DEMO_CUSTOMERS" ("CUSTOMER_ID") / --delete DEMO_ORDERS ``` ### prompt 5. DEMO_ ORDER_ ITEMS ``` CREATE table "DEMO_ORDER_ITEMS" ( "ORDER_ITEM_ID" NUMBER NOT NULL, "ORDER_ID" NUMBER NOT NULL, "PRODUCT_ID" NUMBER NOT NULL, "UNIT_PRICE" NUMBER(8,2) NOT NULL, "QUANTITY" NUMBER(8,0) NOT NULL, constraint "DEMO_ORDER_ITEMS_PK" primary key ("ORDER_ITEM_ID") ) / CREATE sequence "DEMO_ORDER_ITEMS_SEQ" / CREATE trigger "BI_DEMO_ORDER_ITEMS" before insert on "DEMO_ORDER_ITEMS" for each row begin if :NEW."ORDER_ITEM_ID" is null then select "DEMO_ORDER_ITEMS_SEQ".nextval into :NEW."ORDER_ITEM_ID" from sys.dual; end if; end; / ALTER TABLE "DEMO_ORDER_ITEMS" ADD CONSTRAINT "DEMO_ORDER_ITEMS_FK" FOREIGN KEY ("ORDER_ID") REFERENCES "DEMO_ORDERS" ("ORDER_ID") ON DELETE CASCADE / ALTER TABLE "DEMO_ORDER_ITEMS" ADD CONSTRAINT "DEMO_ORDER_ITEMS_PRODUCT_ID_FK" FOREIGN KEY ("PRODUCT_ID") REFERENCES "DEMO_PRODUCT_INFO" ("PRODUCT_ID") / ``` <br /><br /><br /><a name="DBobjectsData"></a>[Top](#top).....[Back](#goDBobjectsData) ### tbl01 DEMO_CUSTOMERS 1. Click the SQL Workshop menu (A). 2. Select the Object Browser option (B) from the menu, which is used to review and maintain database objects (such as, tables, sequences, views, functions, triggers, and so on). 3. In Object Browser page, select the **Tables option** (C) from select list. This action will show a list of existing tables in the left pane, if there are any. 4. Click Create menu select list (D) , and select Table (E) from the menu list to create a new table. This will invoke a wizard named Create Table 5. DEMO_CUSTOMERS for table name (A), CUSTOMER_ID in the first Column Name (B), NUMBER (C) Type, Not Null (D) CUST_FIRST_NAME, CUST_LAST_NAME, CUST_STREET_ADDRESS1, CUST_STREET_ADDRESS2, CUST_CITY, CUST_STATE, CUST_POSTAL_CODE, CUST_EMAIL, PHONE_NUMBER1, PHONE_NUMBER2, URL, CREDIT_LIMIT, TAGS 6. Scale column specify the number of characters each column will hold 7. Primary Key -> select Populated from a new sequence (A) -> Accept DEMO_CUSTOMERS_PK (B) for the Primary Key Constraint Name -> select CUSTOMER_ID (C) -> default Sequence Name or enter any other 8. Skipp Foreign Key and Constraints wizard screens. On the final Confirm screen, click the Create Table button. SQL button shows auto-generated SQL see above. ``` "Column Name","Data Type","Nullable","Default","Primary Key" "CUSTOMER_ID","NUMBER","No"," ","1" "CUST_FIRST_NAME","VARCHAR2(20)","No"," "," " "CUST_LAST_NAME","VARCHAR2(20)","No"," "," " "CUST_STREET_ADDRESS1","VARCHAR2(60)","Yes"," "," " "CUST_STREET_ADDRESS2","VARCHAR2(60)","Yes"," "," " "CUST_CITY","VARCHAR2(30)","Yes"," "," " "CUST_STATE","VARCHAR2(2)","Yes"," "," " "CUST_POSTAL_CODE","VARCHAR2(10)","Yes"," "," " "CUST_EMAIL","VARCHAR2(30)","Yes"," "," " "PHONE_NUMBER1","VARCHAR2(25)","Yes"," "," " "PHONE_NUMBER2","VARCHAR2(25)","Yes"," "," " "URL","VARCHAR2(100)","Yes"," "," " "CREDIT_LIMIT","VARCHAR2(2)","Yes"," "," " "TAGS","VARCHAR2(4000)","Yes"," "," " -- data : see oracle_apex_....csv files CUSTOMER_ID,CUST_FIRST_NAME,CUST_LAST_NAME,CUST_STREET_ADDRESS1,CUST_STREET_ADDRESS2,CUST_CITY,CUST_STATE,CUST_POSTAL_CODE,CUST_EMAIL,PHONE_NUMBER1,PHONE_NUMBER2,URL,CREDIT_LIMIT,TAGS 1,John,Dulles,45020 Aviation Drive, ,Sterling,VA,20166,techies81@gmail.com,703-555-2143,703-555-8967,http://www.johndulles.com,1000, 2,William,Hartsfield,6000 North Terminal Parkway, ,Atlanta,GA,30320, ,404-555-3285, , ,1000,REPEAT CUSTOMER 3,Edward,Logan,1 Harborside Drive, ,East Boston,MA,2128, ,617-555-3295, , ,1000,REPEAT CUSTOMER 4,Frank,OHare,10000 West OHare, ,Chicago,IL,60666, ,773-555-7693, , ,1000, 5,Fiorello,LaGuardia,Hangar Center,Third Floor,Flushing,NY,11371, ,212-555-3923, , ,1000, 6,Albert,Lambert,10701 Lambert International Blvd., ,St. Louis,MO,63145,techies81@gmail.com,314-555-4022, , ,1000, 7,Eugene,Bradley,Schoephoester Road, ,Windsor Locks,CT,6096,techies81@gmail.com,860-555-1835, , ,1000,REPEAT CUSTOMER ``` ### tbl02 DEMO_PRODUCT_INFO Contains **BLOB** (Binary Large Objects) type (B), which is an Oracle data type that can hold up to 4 GB of data. BLOBs are handy for storing digitized information, such as images, audio, and video. This type can also be used to store document files like PDF, MS Word, MS Excel, MS PowerPoint and CSV. We are also using a **TIMESTAMP** type (C) to store the date when a product image is updated. Select the Populated from a new sequence Skip the Foreign Key and Constraints wizard screens. ``` PRODUCT_ID,PRODUCT_NAME,PRODUCT_DESCRIPTION,CATEGORY,PRODUCT_AVAIL,LIST_PRICE,PRODUCT_IMAGE,MIMETYPE,FILENAME,IMAGE_LAST_UPDATE 1,Air Max 2090,"Bring the past into the future with the Nike Air Max 2090, a bold look inspired by the DNA of the iconic Air Max 90.",Men,Y,1500,,image/png,1_AirMax2090.png,21-JUN-20 06.45.19.434901 AM 2,LeBron Soldier 13 Red,"LeBron works hard in the offseason, getting stronger and fine-tuning his already devastating skills. ",Men,Y,200,,image/png,2_LeBron Soldier 13 Red.png,21-JUN-20 06.45.19.733931 AM 3,LeBron Soldier 13 White,"LeBron works hard in the offseason, getting stronger and fine-tuning his already devastating skills. ",Men,Y,150,,image/png,3_LeBron Soldier 13 White.png,21-JUN-20 06.45.19.738065 AM 4,Air Max 720,"The Nike Air Max 720 goes bigger than ever before with Nike?s tallest Air unit yet, which offers more air underfoot for unimaginable, all-day comfort.",Women,Y,60,,image/png,4_Air Max 720.png,21-JUN-20 06.45.19.741109 AM 5,Air Max 270,"Nike's first lifestyle Air Max takes a leap forward with the softest, smoothest, most resilient foam yet in the Nike Air Max 270 React.",Women,Y,80,,image/png,5_Air Max 270.png,21-JUN-20 06.45.19.743820 AM 6,Air Jordan 6,Inspired by the original AJ6 - released the year MJ won his first professional championship - the Air Jordan 6 Retro maintains the iconic look with updated materials.,Women,Y,120,,image/png,6_Air Jordan 6.png,21-JUN-20 06.45.19.746745 AM 7,LeBron 17 BG,The LeBron 17 harnesses LeBrons strength and speed with containment and support for all-court domination.,Women,Y,30,,image/png,7_LeBron 17 BG.png,21-JUN-20 06.45.19.749888 AM 8,Air Max 270 Gradient,"By pulling inspiration from two icons the Air Max 180 and Air Max 93, the Nike Air Max 270 has the tallest Air unit to date.",Men,Y,125,,image/png,8_Air Max 270 Gradient.png,21-JUN-20 06.45.19.752623 AM 9,Air Max 180 Trainer,"Hi-Tech meets high impact in these durable, performance-based Nike training shoes.",Men,Y,110,,image/png,9_Air Max 180 Trainer.png,21-JUN-20 06.45.19.755284 AM 10,Jr Phantom Vision,"Wenn du auf der Suche nach Multinockenschuhen für Kinder bist, ist der kicker-Onlineshop genau das Richtige - 10112892",Kids,Y,50,,image/png,10_Jr Phantom Vision.png,21-JUN-20 06.45.19.757715 AM ``` ### tbl03 DEMO_STATES no PK (51 row) Skip the Foreign Key and Constraints wizard screens. ``` STATE_ID,STATE_NAME AK,ALASKA AL,ALABAMA AR,ARKANSAS AZ,ARIZONA CA,CALIFORNIA CO,COLORADO CT,CONNECTICUT DC,DISTRICT OF COLUMBIA DE,DELAWARE FL,FLORIDA GA,GEORGIA HI,HAWAII IA,IOWA ID,IDAHO IL,ILLINOIS IN,INDIANA KS,KANSAS KY,KENTUCKY LA,LOUISIANA MA,MASSACHUSETTS MD,MARYLAND ME,MAINE MI,MICHIGAN MN,MINNESOTA MO,MISSOURI MS,MISSISSIPPI MT,MONTANA NC,NORTH CAROLINA ND,NORTH DAKOTA NE,NEBRASKA NH,NEW HAMPSHIRE NJ,NEW JERSEY NM,NEW MEXICO NV,NEVADA NY,NEW YORK OH,OHIO OK,OKLAHOMA OR,OREGON PA,PENNSYLVANIA RI,RHODE ISLAND SC,SOUTH CAROLINA SD,SOUTH DAKOTA TN,TENNESSEE TX,TEXAS UT,UTAH VA,VIRGINIA VT,VERMONT WA,WASHINGTON WI,WISCONSIN WV,WEST VIRGINIA WY,WYOMING ``` ### tbl04 DEMO_ORDERS Select Populated from a new sequence. Foreign Key wizard screen : Create a relationship between DEMO_CUSTOMERS and DEMO_ORDERS table. Default **Disallow Delete** option (B) will block deletion of rows from the customers table when they are utilized in the orders master table. Skip Constraints wizard screen. ``` ORDER_ID,CUSTOMER_ID,ORDER_TOTAL,ORDER_TIMESTAMP,USER_NAME,TAGS 1,7,1890,17-APR-20 06.45.19.000000 AM,DEMO, 2,1,2380,01-MAY-20 06.45.19.000000 AM,DEMO,LARGE ORDER 3,2,1640,12-MAY-20 06.45.19.000000 AM,DEMO, 4,5,1090,14-MAY-20 06.45.19.000000 AM,DEMO, 5,6,950,24-MAY-20 06.45.19.000000 AM,DEMO, 6,3,1515,29-MAY-20 06.45.19.000000 AM,DEMO, 7,3,905,03-JUN-20 06.45.19.000000 AM,DEMO, 8,4,1060,11-JUN-20 06.45.19.000000 AM,DEMO, 9,2,730,17-JUN-20 06.45.19.000000 AM,DEMO, 10,7,870,20-JUN-20 06.45.19.000000 AM,DEMO, 192,7,180,21-JUN-20 07.03.03.717283 AM,DEMO, 191,1,800,21-JUN-20 06.52.48.105288 AM,DEMO, 211,7,100,21-JUN-20 06.57.10.978243 AM,DEMO, 212,6,210,21-JUN-20 06.59.13.144771 AM,DEMO, 213,6,500,21-JUN-20 07.00.17.533966 AM,DEMO, 251,7,155,02-DEC-20 06.29.39.463839 AM,DEMO, 231,7,1421,06-JUL-20 09.17.31.833485 AM,DEMO, ``` ### tbl05 DEMO_ORDER_ITEMS Has two foreign key references : ORDER_ID and PRODUCT_ID. FK to DEMO_ORDERS : For this relationship you selected the Cascade Delete option (A), which simultaneously removes both parent and child records from the two tables when you delete an order. DEMO_ORDER_ITEMS_PRODUCT_ID_FK : Select Disallow Delete for delete option. Skip Constraint wizard screen. ``` "ORDER_ITEM_ID","ORDER_ID","PRODUCT_ID","UNIT_PRICE","QUANTITY" "500","1","1","50","10" "501","1","2","80","8" "502","1","3","150","5" "503","2","1","50","3" "504","2","2","80","3" "505","2","3","150","3" "506","2","4","60","3" "507","2","5","80","3" "508","2","6","120","2" "509","2","7","30","2" "510","2","8","125","4" "511","2","9","110","2" "512","2","10","50","2" "513","3","4","60","4" "514","3","5","80","4" "515","3","6","120","4" "516","3","8","125","4" "517","3","10","50","2" "518","4","6","120","2" "519","4","7","30","6" "520","4","8","125","2" "521","4","9","110","2" "522","4","10","50","4" "523","5","1","50","3" "524","5","2","80","2" "525","5","3","150","2" "526","5","4","60","3" "527","5","5","80","2" "528","6","3","150","3" "529","6","6","120","3" "530","6","8","125","3" "531","6","9","110","3" "532","7","1","50","2" "533","7","2","80","2" "534","7","4","60","2" "535","7","5","80","2" "536","7","7","30","3" "537","7","8","125","1" "538","7","10","50","3" "539","8","2","80","2" "540","8","3","150","3" "541","8","6","120","1" "542","8","9","110","3" "543","9","4","60","4" "544","9","5","80","3" "545","9","8","125","2" "546","10","1","50","5" "547","10","2","80","4" "548","10","3","150","2" "561","192","7","30","6" "620","231","8","125","10" "560","191","2","80","10" "549","211","10","50","2" "550","212","7","30","7" "551","213","1","50","10" "640","251","7","30","1" "641","251","8","125","1" "580","231","8","111","1" "581","231","7","30","2" ``` <br /><br /><br /> ## Why would I want to build a Single Page Application in APEX? https://blog.foex.at/an-introduction-to-single-page-application-development-in-oracle-apex/ APEX has many unique characteristics that you won?t find in any other framework. 6 characteristics sets it apart from every other development framework : 1. it runs within the Oracle DB, it's at the same level of your data **negating need for a middle tier** (Java need not apply). It's perfect for data centric apps. You have full access to all DB capability, and **as of 18c **Oracle DB packs a very long comprehensive set of features. 2. it's **meta data driven**. Using SQL you can query everything that is designed on your page, or in your app, and you can do this **at the point of page rendering** or in every **AJAX callback**. You can even generate apps/pages/regions etc. using the same API's the APEX builder uses to create your apps. The power and solution capability this gives you as a developer is not widely publicised and in our opinion is really underrated. 3. is serverside generation, you can **programatically output HTML, CSS and Javascript on the fly**. This can be **on page render or for AJAX callbacks**. The benefits of server generated Javascript is not widely publicised either. Again it can reduce your client side foot print drastically as well as reducing client side coding complexity. 4. we can build visual appealing applications really fast with APEX, and they are **super easy to deploy and maintain**.Thanks to the **universal theme and Theme Roller** you can achieve a modern look and feel whilst adhering to corporate colour conventions. APEX has an extensive and mature **PLSQL API**, and also built-in REST support thanks to **ORDS (Oracle REST Data Services)**. 5. low code design makes it easy for beginners to become productive, whilst it provides full control for experts. 6. licensing cost, if you don't have a data foot print above 12GB you can use 18c XE, ORDS, and APEX for free. You can also deploy this on **cloud providers** that can charge as little as **$5 a month** for hosting. So for people not using Oracle yet there is no entry barrier for adopting APEX. You could even use **REST to access data in remote databases if your data requirement exceeds 12G**. There are **solutions to keeping costs to a minimum for small businesses**. Lastly there's also **productivity apps** that come with it like **Quick SQL which is a markdown editor** that can quickly build your data model and also generate a dummy dataset. You can also quickly **build prototypes** using APEX, comparable in time to using a wireframe tool. The difference being you have a functional application to preview, making the choice to use APEX that much easier. | | **SPA Framework** | MPA Framework | | -- | :------------------------------------- | :---------------------: | | 1. | ? Client Side Rendering | Serverside Rendering | | 2. | ? Partial Page Loading | Full Page Loading | | 3. | ? Lazy Loading | | | 4. | ? Lazy Rendering | | | 5. | ? AJAX Centric | | | 6. | ? - | Page Submits | Currently the majority of APEX plugin developers are using it for single functionality use cases like **nested reporting, multiple file upload, new LOV items...** but you can take this a step further and plug-in an existing SPA Javascript framework and provide a **reusable declarative set of regions, items, processes, and dynamic actions that are designed to work together to form a single page application design approach** to building your application. This is what is FOEX Plugin Framework for Oracle APEX. <br /><br /><br /> # Help region ``` for c1 in ( select page_title, help_text from apex_application_pages where page_id = :P10061_PAGE_ID and application_id = :APP_ID ) loop if c1.help_text is null then sys.htp.p('No help is available for this page.'); else if substr(c1.help_text, 1, 3) != '<p>' then sys.htp.p('<p>'); end if; sys.htp.p(apex_application.do_substitutions(c1.help_text)); if substr(trim(c1.help_text), -4) != '</p>' then sys.htp.p('</p>'); end if; end if; end loop; ``` <br /> ___ <a name="md2html"></a>[Top](#top) >### MD to HTML converters on inet 1. **https://www.tutorialspoint.com/online_markdown_editor.php** or https://markdowntohtml.com/ 2. or https://www.browserling.com/tools/markdown-to-html (many converters) 3. or files convert : https://products.aspose.app/pdf/conversion/md-to-html to many formats 4. Links not working : http://demo.showdownjs.com/ (no HTML source) NOT WORKING : https://daringfireball.net/projects/markdown/dingus or https://pandoc.org/try/ >https://www.w3schools.com/html/html_symbols.asp >https://www.degraeve.com/reference/specialcharacters.php [Top](#top).....[Apexws_cloud](#Apexws_cloud).....[App. builder](#app_builder).....[Page](#page).....[Environm](#environm) .....[URL](#url).....[Sales](#sales).....[SHARED C.](#shared)......[Rep.List](#rep_list).....[Ord.WizList](#ord_wiz_list).....[Top. Navig](#top_navig).....[LOVs](#lov)....[IMGs](#img) .....[Home p.](#home).....[Buttons](#buttons).....[PgStyles](#pgstyles).....[Cust](#cust).....[Prod](#prod).....[Order](#order).....[Graph. & Mobile](#gra_mob).....[Adv. Rep](#advrep).....[Authoriz](#authoriz).....[Search Style Cal.](#searchstylecal).....[ Deploy](#deploy)