Hacking the APEX error page - Part 2!
Do you want to have highlighting for the tabular form column cells which have an error? Then you should read the rest of the posting!I have enhanced the original Hacking the APEX error page code (the original posting has been updated) and created a new package ApexLib_Error which can be used to "raise" errors in a process or validation process when you process your tabular form values. The advantage of this package is that it allows you to provide the column and row number when you raise an error.
When the error message is displayed above the tabular form region, all the column cells which are related to an error are highlighted.
Check out the updated Enhanced Tabular Form with column cell highlighting example.
This new package enhances the existing Plug & play tabular form handling solution. You have different possibilities to use the new package. It has methods which can be used in validation process of type Function Returning Error Text and PL/SQL error. If you use it in a process you always have to use the raise* interface.
Let's do some examples:
Create a page validation with the following settings
- 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
- Error Display Location: On Error Page (it always has to be on error page!)
- Validation:
BEGIN
ApexLib_Error.addError
( pError => '%label has to be between %0 and %1'
, pColumnName => 'SALARY'
, pRow => 1
, p0 => 1000
, p1 => 5000
);
ApexLib_Error.addError
( pError => 'SALARY_NOT_MATCHING'
, pFieldId => 'f03'
, pRow => 5
, p0 => 1000
, p1 => 5000
);
RETURN ApexLib_Error.getErrorStack;
END;
What does this code do?
It puts to errors onto an error stack, the first call identifies the column by the name (works only for updateable tabular forms) and the error text is hard coded, but with placeholders.
The second call uses a defined text message (Shared Components/Text Message) and identifies the column with the fxx syntax (in the case if you know to which HTML form item the column is mapped to). At the end of the validation process the error stack is returned to APEX. If no error is on the stack, nothing is returned. So this statement should always be the last statement in your validation process!
Let's do another example!
Create a page validation or process with the following settings
- Identify the validation level: Page level validation
- Select a validation method: PL/SQL
- Select the type of PL/SQL validation you wish to create: PL/SQL Error
- Error Display Location: On Error Page (it always has to be on error page!)
- Validation:
BEGIN
ApexLib_Error.addError
( pError => '%label has to be between %0 and %1'
, pColumnName => 'SALARY'
, pRow => 1
, p0 => 1000
, p1 => 5000
);
ApexLib_Error.addError
( pError => 'SALARY_NOT_MATCHING'
, pFieldId => 'f03'
, pRow => 5
, p0 => 1000
, p1 => 5000
);
ApexLib_Error.raiseErrorStack;
END;
Same as the above example, the difference is at the end of the code. Instead of returning the error stack we raise it with an RAISE_APPLICATION_ERROR so that APEX can capture it. This method of adding errors to the stack, allows you that you can also have multiple errors.
Another example
Same as above, but this time with the following code:
BEGIN
ApexLib_Error.raiseError
( pError => '%label has to be between %0 and %1'
, pColumnName => 'SALARY'
, pRow => 1
, p0 => 1000
, p1 => 5000
);
END;
This will immediately abort processing and the error is returned to APEX.
For a real world example check out the Plug & play tabular form handling posting.
The code has been tested with Firefox 2.0 and IE 7.0.
Where do I get the source code?
I have started a new SourceForge project, get the source code there.
Have questions? Don't hesitate to write me a note!
Update
Fixed an issue with Internet Explorer.
Labels: ApexLib, error, tabular form







15 Comments:
Hi,
I just wanted to say that I read the Apex Forum and blogs of people like Carl, Dmitri, Benjamin Wootton, John Scott and find them useful. I found the link to yours a short while ago, and congratulate you on your excellent posts. There are some really great bits of advice in here. Please keep up the good work.
Regards,
Jon.
By
Jon Miller, at 20 December, 2006 10:37
Hi Jon,
good to hear that you like my blog!
That really motivates me to continue blogging. Sure I see the visitor stats for my blog, but you never know if people find it useful what I'm writing.
Thanks
Patrick
By
Patrick Wolf, at 20 December, 2006 12:25
Patrick -
I would like to echo Jon's comments about the excellent code/techniques you have implemented. Every day APEX looks more and more like a "full strength" web development platform.
Has Oracle offered you a job yet?? ;)
Keep up the great work!!
Hoages
By
Anonymous, at 20 December, 2006 16:02
Hi Patrick,
thanks for your excellent work!
I've integrated your solution in my application. All things work as expected. But one thing I didn't solve yet due to my little APEX knowledge. How to prevent ApexLib validation when user just delete a row in tabular form? Test case: erase a date field in your demo form, then try to delete this row. I tryed to add condition to this validation: Request != Expression1 where Expression1 is set to MULTI_ROW_DELETE. It seems this doesn't help to overcome to overcome the problem
By
Edward, at 03 January, 2007 14:51
Hi Edward,
you are right with that check, never thought that a user modifies the data and then deletes the row :-) I have created a bug for that, so that it is ignored in the future.
About your workaround. Hmm, that should work, I just tried that I add a condition of Request != Expression1 to my Application Process which calls validateColumns. And the Expression 1 is set to MULTI_ROW_DELETE
When I delete now a row, the columns are not checked anymore.
Can you try that again?
Patrick
By
Patrick Wolf, at 03 January, 2007 15:24
Hi Patrick,
thanks for confirmation. I tried it again, it works! It seems I had had a mistake somewhere when posted you my initial question.
I would like to ask you two things also.
1) Is it possible to associate user input error with several columns? I mean to highlight them alltogether. I'll try to explain. I have a kind of denormalizaton on the base table where values in several columns are logically connected with each other. You know sometimes it may be nessesary. I check the following formula to raise error:
ROUND((ApexLib_TabForm.NV('PRICE', ii) * ApexLib_TabForm.NV('AMOUNT', ii) - ApexLib_TabForm.NV('DISCOUNT', ii)), 2) <> ApexLib_TabForm.NV('TOTAL_COST', ii)
In this case we don't actually know which column has an error value (or simply a user misprint). It would be nice to have a method to associate such 'logical errors' with several fields if it's possible with ApexLib.
By
Edward, at 10 January, 2007 02:17
Hi Edward,
I have created a feature request for this topic and will think about how to solve that.
I'm currently in the progress of implementing a new big feature, so it may take some time...
Patrick
By
Patrick Wolf, at 10 January, 2007 08:31
Thanks for your stuff on hacking the error page - very useful. I have implemented your solution and when I try to save the required field is coloured blue and the error message displayed at the top of the screen. However when I then type something into the field and press submit all that happens is that the field turns white and I have to press submit again to save. This happens in your example also. Do you know any way that I can get it to submit the page and save the data the first time I hit submit after the error is displayed?
By
Andrew, at 29 January, 2007 22:26
Hi Andrew,
I think the reason is that the browser "forgets" the button click.
When the button is clicked the focus is moved to the button and the onchange event for the item is triggered, which will remove the error text.
Removing the error text seems to disturb the browser, because it will change the visible focus and the mouse cursor isn't placed anymore over the submit button. This will lead to the situation that the browser "forgets" that the button has been pressed. Really strange!!! :-(
I don't have a solution for that problem yet. The only one would be not to remove error messages...
Anybody out there having an idea what to do!?!?
Patrick
By
Patrick Wolf, at 30 January, 2007 00:27
Patrick,
Does your Error page hacking meganism work with the Oracle Headstart CDM rulframe error message/Hil message stack errors?
Gr Hans Langenberg
By
Anonymous, at 20 February, 2008 10:12
Hi Hans,
it works with any ORA error message. If you now see your message on the separate error page of APEX, you will also see it as inline error message on your page.
Hope that answers your question.
Patrick
By
Patrick Wolf, at 20 February, 2008 15:49
You've helped me so much already Patrick fantastic framework ! cheers , but I have one request , how can I change the colour of the apexlib error message I realise it is connected to the theme used but I cannot seem to find the link
Chris
By
Anonymous, at 21 February, 2008 13:06
You have to change the CSS of the theme. Have a look at t7Message, t7Notification or something similar.
t7 is depending on your theme number.
Patrick
By
Patrick Wolf, at 22 February, 2008 01:29
Patrick,
The ruleframe messages are not just ORA-errors. The thing is ones a business rule failes a user defined error is raised (ORA-20998: Transaction Failed) telling you there is a message on the error stack, you can fetch with a piece of code like this :
declare
l_message_rectype_tbl hil_message.message_tabtype;
l_message_count number := 0;
l_raise_error boolean := false;
l_list_count number := 0;
l_severity varchar2(12);
l_tekst varchar2(1000);
begin
cg$errors.get_error_messages
( l_message_rectype_tbl
, l_message_count
, l_raise_error
);
dbms_output.put_line(to_char(l_message_count)||' messages');
if l_message_count > 0
then
for i in 1..l_message_count loop
if l_message_rectype_tbl(i).severity = 'E'
then
l_severity := 'Error';
elsif l_message_rectype_tbl(i).severity = 'W'
then
l_severity := 'Warning';
elsif l_message_rectype_tbl(i).severity = 'I'
then
l_severity := 'Information';
else
l_severity := l_message_rectype_tbl(i).severity;
end if;
l_tekst:= l_severity || ' ' || l_message_rectype_tbl(i).msg_code
|| ' ' || l_message_rectype_tbl(i).msg_text;
dbms_output.put_line(substr(l_tekst,1,250));
if length(l_tekst)>250
then
dbms_output.put_line(substr(l_tekst,251,250));
end if;
if length(l_tekst)>500
then
dbms_output.put_line(substr(l_tekst,501,250));
end if;
if length(l_tekst)>750
then
dbms_output.put_line(substr(l_tekst,751,250));
end if;
end loop;
end if;
end;
/
and these are messages we want to present to the user.
greetings,
Hans Langenberg
By
Anonymous, at 03 March, 2008 14:24
Hi Hans,
currently there is no central hook in APEX which is called when an error occurs and where it would be possible to "translate" an error message. I have also the same need and I hope that the APEX team will include such a feature in the next version.
Currently you already have to call this mapping code in the instead of trigger of the view or somewhere else and raise it again with RAISE_APPLICATION_ERROR.
Hope that helps
Patrick
By
Patrick Wolf, at 05 March, 2008 15:52
Post a Comment
<< Home