Plug & play tabular form handling
I still remember the time when I was an APEX newbie and I really got confused with tabular forms (updateable reports). They behaved very different from what I knew about "normal" page items. So what where the issues which confused me?
That's a long list and that's why I did some programming on the weekend to get a solution for the above short comings, so that newbies and experienced APEX developers don't have to care anymore.
To make a long story short, I have created a package which you just call once in your application and which takes care of the above problems. It allows you to
But first try it by yourself, I have set up a tabular form with the default APEX handling for tabular forms. Follow the instructions and play around with it.
Standard Tabular Form example
After you have done that, check out my
Enhanced Tabular Form example.
How to integrate it into your application?
Follow the steps in my How to integrate posting.
In the case if you don't want that one of your report regions is processed by the library, add $APEXLIB_IGNORE_VALIDATION$ in the region comment to skip the processing.
That's the basic integration which does the required column and format mask check. If you want to access your column in your own validation code, follow the example to see how to do that.
Example
As you can see in the code, you don't have to care about date convertion, you are only processing the changed records. The code is still understandable when you look at the code 5 days later, aren't names more meaningful than just references
to APEX_Application.g_f01? ;-)
You have different getter functions to access your columns. ApexLib_TabForm.V, -NV and -DV have the same purpose as the existing APEX functions which you can use for items. Check out the package specification of the ApexLib_TabForm package, all the functions are documented.
BTW, if you are not satisfied with the error message the validateColumns procedure is raising for required and format mask check. You can define your own error text by creating a message (Shared Components/Text Messages). The name has to be APEXLIB_TABFORM_COLUMN_REQUIRED (Format: Column "%0" is required.) or APEXLIB_TABFORM_INVALID_FORMAT (Format: Column value of "%0" doesn't match to the format "%1".) The row prefix can be define with APEXLIB_TABFORM_ROW_PREFIX (Format: Row %0: ).
Impact on your existing application
Nothing really changes except that you have better error messages in your tabular form, so it's no problem to use it also for your existing application.
Update
Known restrictions
Problems?
Enable debugging, it will show you what the library is doing and which columns are mapped to which array. Look for ApexLib_TabForm in the output.
What's next?
I have now a question. Where do you install the packages? Are you allowed to install them into the FLOWS schema? Because that would make the condition checking a breeze. If there is a big demand to just install the packages into the application schema, I have to re-code the condition/authorization checking, because it's not accessable from the application schema.
Do you have other ideas and troubles with tabular form handling which you want to automate? Feedback very welcome!
- It isn't possible to create any validations on the columns of the report, like I can do it for page items.
- You have to use the APEX_Application.g_fxx arrays instead of using bind variables as for page items.
- To find the correct array you have to look into the generated HTML code for the correct mapping.
- If the order of the columns gets changed, your code gets screwed up, because the columns now maps to a different g_fxx array.
- If a column has a condition or authorization the g_fxx array changes again, in the case the column doesn't get rendered.
- The code isn't really readable if there are just references to g_f01, g_f02, ...
- The format mask has to be duplicated if the g_fxx is accessed and you want to get the correct data type (eg NUMBER, DATE)
- When you want to get the number of array entries you have to take care that you don't use the array for a checkbox column, because that just contains the checked values!
- You have no function to find out if the row has changed.
- When the validation of a format mask or required column fails, the error message is very internal. The user doesn't have a clue which column and which row was effected. And it stops after the first error.
That's a long list and that's why I did some programming on the weekend to get a solution for the above short comings, so that newbies and experienced APEX developers don't have to care anymore.
To make a long story short, I have created a package which you just call once in your application and which takes care of the above problems. It allows you to
- reference your columns by name without having to hassling around to which array your column is mapped.
- To get the correct number of rows to process
- Identify which row has changed
- Get your data with the correct data type (NUMBER, DATE) without having to take care about format masks.
- Add a required column check by declaration, instead of coding it.
- Get more meaningfull error message than APEX provides.
But first try it by yourself, I have set up a tabular form with the default APEX handling for tabular forms. Follow the instructions and play around with it.
Standard Tabular Form example
After you have done that, check out my
Enhanced Tabular Form example.
How to integrate it into your application?
Follow the steps in my How to integrate posting.
In the case if you don't want that one of your report regions is processed by the library, add $APEXLIB_IGNORE_VALIDATION$ in the region comment to skip the processing.
That's the basic integration which does the required column and format mask check. If you want to access your column in your own validation code, follow the example to see how to do that.
Example
- Create a new page
- Page Type: Form/Tabular Form
- Allowed Operations: Update, Insert and Delete
- Table / View Name: EMPLOYEES
- Select Columns(s): Everything except of PHONE_NUMBER, COMMISSION_PCT, MANAGER_ID and DEPARTMENT_ID
- Primary Key Column1: EMPLOYEE_ID
- Source Type: Existing trigger
- Updateable Columns: ALL
- Confirm everything on the following pages
- Open the Report Attributes of the created region.
- For the columns LAST_NAME, EMAIL, HIRE_DATE, JOB_ID go to the Column Link section and enter $APEXLIB_REQUIRED$ as Link Attributes
- For the column HIRE_DATE set the following properties
- Display As: "Date Picker"
- Date Picker Format Mask: "DD-MM-YYYY" => we use a different format mask than the database has, so that auto date convertion doesn't work!
- Element Width: 10
- For the column JOB_ID set the following properties
- Display As: Select List (query based LOV)
- LOV Query:
SELECT JOB_TITLE AS D, JOB_ID AS R FROM JOBS ORDER BY JOB_TITLE
- For the column SALARY set the following properties
- Number / Date Format: FML999G990D00
- Let's create some extra validation, so that you see how easy it is to access your columns. Create a validation for the created page
- Identify the validation level: Page level validation
- Select a validation method: PL/SQL
- Select the type of PL/SQL validation you wish to create: Function Returning Error Text
- Sequence: 10
- Validation Name: Validate Hire Date and Salary
- Error Display Location: On Error Page
- Validation:
DECLARE
vMinSalary NUMBER;
vMaxSalary NUMBER;
BEGIN
FOR ii IN 1 .. ApexLib_TabForm.getRowCount
LOOP
IF ApexLib_TabForm.hasRowChanged(ii)
THEN
IF ApexLib_TabForm.DV('HIRE_DATE', ii) > SYSDATE
THEN
ApexLib_Error.addError
( pError => 'Hire Date is in the future'
, pColumnName => 'HIRE_DATE'
, pRow => ii
);
END IF;
--
SELECT MIN_SALARY
, MAX_SALARY
INTO vMinSalary
, vMaxSalary
FROM JOBS
WHERE JOB_ID = ApexLib_TabForm.V('JOB_ID', ii)
;
IF ApexLib_TabForm.NV('SALARY', ii) NOT BETWEEN vMinSalary AND vMaxSalary
THEN
ApexLib_Error.addError
( pError => 'Salary has to be between %0 and %1'
, pColumnName => 'SALARY'
, pRow => ii
, p0 => vMinSalary
, p1 => vMaxSalary
);
END IF;
END IF;
END LOOP;
--
RETURN ApexLib_Error.getErrorStack;
END; - Error Message: Error occurred.
As you can see in the code, you don't have to care about date convertion, you are only processing the changed records. The code is still understandable when you look at the code 5 days later, aren't names more meaningful than just references
to APEX_Application.g_f01? ;-)
You have different getter functions to access your columns. ApexLib_TabForm.V, -NV and -DV have the same purpose as the existing APEX functions which you can use for items. Check out the package specification of the ApexLib_TabForm package, all the functions are documented.
BTW, if you are not satisfied with the error message the validateColumns procedure is raising for required and format mask check. You can define your own error text by creating a message (Shared Components/Text Messages). The name has to be APEXLIB_TABFORM_COLUMN_REQUIRED (Format: Column "%0" is required.) or APEXLIB_TABFORM_INVALID_FORMAT (Format: Column value of "%0" doesn't match to the format "%1".) The row prefix can be define with APEXLIB_TABFORM_ROW_PREFIX (Format: Row %0: ).
Impact on your existing application
Nothing really changes except that you have better error messages in your tabular form, so it's no problem to use it also for your existing application.
Update
- Check out the Accessing the row selector of a tabular form for an example how you can access the row selector.
- Check out Hacking the APEX error page to display the errors as inline message.
- Check out Hacking the APEX error page - Part 2 to highlight the column cells which have an error.
Known restrictions
- If you use APEX_Item or HTMLDB_Item to build your own form elements. I can't map the columns, because I don't know which index you have used.
- If a column has a condition or authorization. See below.
Problems?
Enable debugging, it will show you what the library is doing and which columns are mapped to which array. Look for ApexLib_TabForm in the output.
What's next?
I have now a question. Where do you install the packages? Are you allowed to install them into the FLOWS schema? Because that would make the condition checking a breeze. If there is a big demand to just install the packages into the application schema, I have to re-code the condition/authorization checking, because it's not accessable from the application schema.
Do you have other ideas and troubles with tabular form handling which you want to automate? Feedback very welcome!
Labels: ApexLib, tabular form







14 Comments:
Hello Patrick,
first of all THANK YOU for your work. I always hated it to look at the HTML-Code to find out the right g_fxx number! Let's say it's a dark past now! But I cannot get the whole stuff to work. I tried your complete example in
http://inside-apex.blogspot.com/2006/12/plug-play-tabular-form-handling.html
but when detecting an input error with the page validation process APEX shows me this usual ugly error page with the red stop sign but with the error message I created in the page process. (Rather than above the report area) I followed your example by creating the application process and by inserting $APEXLIB_REQUIRED$ as link attributes.
I tried it on APEX Express 2.1.
Some hint for me ?
Thanks
Andree
By
Andree, at 19 December, 2006 14:36
Hi Andree,
sorry my example page also already incorporates my APEX error page hack (http://inside-apex.blogspot.com/2006/12/hacking-apex-error-page.html).
That's why the error message is displayed above the report region.
BTW, I'm currently working on some additions to highlight the column cell which has an error. Stay tuned. :-)
Patrick
By
Patrick Wolf, at 19 December, 2006 15:12
Hello Patrick,
nice enhancement !
One minor thing:
You forgot to add the grant and synonym for APEX_LIB_ERROR in the HowtoInstall.txt.
Thanks again!
Andree
By
Andree, at 20 December, 2006 08:17
... and once again hello !
Now I have some more issues to ask for...
(1)
I have two columns to check. According to your example I coded both checks with separate calls to ApexLib_Error.addError and at the end of the validation i called RETURN ApexLib_Error.getErrorStack.
When I start the page I have in one row for any reason an (old) error condition in the first of the two columns. This error is not detected when submited AND THAT IS OK, because the row contents did not change. BUT when I change the contents of the second column of the same row (to a correct or wrong value) the (unchanged) error of the first column is detected. Seems not logical.
(2)
You force "Row xx:" in front of the error message. How can I change or suppress it ? Seems not reasonable for a german (or other language than english) application.
(3)
You force a "f0x_000y" at the end of the message. Is it a forgotten debug output or did I something wrong ?
Thank you again ! It's a really great help to use your tools !
Keep going on !
Andree
By
Andree, at 20 December, 2006 08:39
Hi Andree,
thanks a lot for letting me know! I have already fixed it and uploaded release V0.12.
So you are installing it in the FLOWS schema? No problems with your DBA? :-)
Patrick
By
Patrick Wolf, at 20 December, 2006 08:41
Ups, another comment :-)
1) I can't really detect if a single column value has changed, because APEX is just generating a checksum for the hole record. But anyway, when you write an IF and read the value of a column, how should the library know that you don't want to check this column, because it hasn't changed? :-) Or do you mean the automatic required and format mask check?
But as I said, single column change detection will not be possible as long as I'm not reading the record from the database... Costs performance...
2) All the messages the ApexLib library is raising can be translated, add under Shared Components\Text Message entries for APEXLIB_TABFORM_ROW_PREFIX, APEXLIB_TABFORM_COLUMN_REQUIRED and APEXLIB_TABFORM_INVALID_FORMAT. Details about the format and placeholders can be found in the posting.
3) You see that f0x_000y in your error message? Or only when you are running in debug mode? Or do you also see it in the inplace message? The user normally should see it as long as he is running in debug mode.
Great that you are really using it! That's the way to find bugs the fastest way.
Patrick
By
Patrick Wolf, at 20 December, 2006 08:56
Hello Patrick,
Yes, I installed it, because for the Express Edition on my own machine I AM THE DBA (Hugh!).
1) I guessed that!
2) Works !
3) Until now I did not install the "error page hack" and live with the usual page with the red sign. And there the messages are concatinated with "f0x_000y" (x and y depending on column and row) No debug mode. (APEX Task bar shows "Debug" NOT "No Debug", so it is switched off)
If you give me an email address, I send you a screenshot.
Regards
Andree
By
Andree, at 20 December, 2006 09:19
Ok, in the case if you are not using the APEX error page hack yet, it's clear for me why you see it.
But if you are not using it, your columns cell will never get highlighted! If you don't like to use the highlighting, you can call the addError with pColumnName => NULL, pRow => NULL. So that the column information isn't added to the error message.
But I will add something into the next version so that this information is always hidden.
You can find my e-mail address in the profile of the blog.
Patrick
By
Patrick Wolf, at 20 December, 2006 10:34
Hi Patrick,
(Beginner level)
I was using the Tabular Form and I found a problem. What can I do to validate this?: if I erase a value from a field and then click on the Submit button. After this an error appears "Error in mru internal routine: ORA-20001: Error in MRU: row= 1, ORA-01407: cannot update ("SUPPORT"."GK_ACCESS_TYPES"."ACCESS_TYPE_DESC") to NULL, update "SUPPORT"."GK_ACCESS_TYPES" set "ACCESS_TYPE_ID" = :b1, "ACCESS_TYPE_DESC" = :b2 where "ACCESS_TYPE_ID" = :p_pk_col
".
How can I fix this exception?
By
Fury, at 15 June, 2007 18:56
btw, in my previous comment, that error is displayed when the submit button tries to do an update into a table, but it tries to update a field with a null value... and I want to display a normal error message not that exception page
thank you
By
Fury, at 15 June, 2007 19:36
Hi Fury,
if you are using my ApexLib Framework, just use the $APEXLIB_REQUIRED$ tag to tell the framework that the column is required and it will do all necessary checks that the tabular form column contains a value.
See above for further details.
Patrick
By
Patrick Wolf, at 15 June, 2007 23:27
Hi Patrick,
First off thanks for ApexLib - I use it a lot for my Apex apps and it makes life so much easier!
I have a question around tabular form handling and validation I hope you don't mind me posting.
1. Does the ApexLib framework support tabular form handling for pages that use Apex Collections rather than based on a table.
2. Can you validate attributes in previous rows using the ApexLib framework? By this I mean that in the tabular form if, for example, there is a date column in record 1 and the value for entries in record 2 must not overlap with that date is it possible to validate?
To give you some context I am looking at how a new application can capture multiple addresses for a person and validate that the dates they lived at each of them are continuous.
As always any help and pointers that you can give me will be much appreciated.
Kind regards,
Stuart
By
StuMac, at 16 January, 2008 15:58
Hi Stuart,
1.) Yes. It doesn't matter if it's a real table or view. As long as it's a valid SQL statement which doesn't use the Apex_Item.xxx calls you are fine.
2.) Yes. When calling the ApexLib_TabForm.NV/DV/... functions, you can pass the row number of the previous row. But remember, that in the array APEX has build, only the visible rows will be included. For example, if you paginated onto page 2, the APEX arrays will just include rows from page 2! So just checking the previous record might not be enough. It's probably better to check that with SQL statements/triggers when you actually insert/update the row.
Patrick
By
Patrick Wolf, at 16 January, 2008 23:37
Hi Patrick,
thanks for your Oracle APEX work that you provide.
I try to use the APEXLib Framework because I have severe issues with tabular forms:
1. with Popup Key from LOV in connection with collections in a tabular form
2. with providing default values and length restrictions in tabular forms
Now I see that APEXLIB_TABFORM.INIT checks for the use of APEX_ITEM in the region source query.
Do I see it correctly that this implies that APEXLib does not work with tabular forms containing any list item? Or is there another way to use lists in tabular forms together with APEXLib?
thanks
Michael
By
Michael, at 03 September, 2008 15:07
Post a Comment
<< Home