<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)

