Thursday, January 18, 2007

Forcing apex item buttons to do what you want

If you tried with little success to attach some javascript code to an Apex item button (not a region button, that's a piece of cake...) , it may console you to know that i have been in the same situation for some time.

I wanted to catch button clicks and display one of those classic, annoying pop up messages asking "do you really really really want to delete this stuff?"

With a normal region button it's pretty easy, although it's not so straightforward.

You need to go to the button property called optional URL redirect and pick the value URL and put something like:
javascript:confirmDelete('Press OK to delete the selected rows',
'MULTI_ROW_DELETE');

in the URL target attribute.

Unfortunately item buttons don't come with the same feature, so one starts wondering about some fancy way of hacking the system.

Luckily enough, if you opt for a template based button, there is a property called Attributes where apparently you can put your stuff.
But this is just the half of the moon.
Because the button template you are using might not include a #BUTTON_ATTRIBUTES# substitution string in its definition (as suggested in Apex on-line help), so, whatever you put there, it won't work because it will be left out.

So, to get to the other side of the moon, you need to customize the template button, or better, to make a copy of an existing one and customize the duplicate, just in case you don't want to mess up the entire application.

Here is how i did it:

first i picked the Button, Alternative 2 template (may be it doesn't exist such template in the theme you're currently using, so pick a different one) and copied it, using the built-in copy feature.
With much fantasy i renamed it to Button, Alternative 2, Custom.

Here is the template before i started hacking it:

<table class="t1ButtonAlternative2"
cellspacing="0" cellpadding="0"
border="0" summary="">
<tr>
<td class="t1L">
<a href="#LINK#">
<img src="#IMAGE_PREFIX#themes/theme_1/button_alt2_left.gif"
alt="" width="11" height="20" />
</a>
</td>
<td class="t1C">
<a href="#LINK#">#LABEL#</a>
</td>
<td class="t1R">
<a href="#LINK#">
<img src="#IMAGE_PREFIX#themes/theme_1/button_alt2_right.gif"
width="11" height="20" alt="" />
</a>
</td>
</tr>
</table>


As you see there was no trace of the #BUTTON_ATTRIBUTES# mentioned above, so i changed it as follows:

<table class="t1ButtonAlternative2"
cellspacing="0" cellpadding="0"
border="0" summary="">
<tr>
<td class="t1L">
<a href="#BUTTON_ATTRIBUTES#">
<img src="#IMAGE_PREFIX#themes/theme_1/button_alt2_left.gif"
alt="" width="11" height="20" />
</a>
</td>
<td class="t1C">
<a href="#BUTTON_ATTRIBUTES#">#LABEL#</a>
</td>
<td class="t1R">
<a href="#BUTTON_ATTRIBUTES#">
<img src="#IMAGE_PREFIX#themes/theme_1/button_alt2_right.gif"
width="11" height="20" alt="" />
</a>
</td>
</tr>
</table>


This template will work well provided you perform the following settings in the button definition:
  • Pick Template based button as Style attribute
  • Pick Button, Alternative 2 Custom (or whatever is in your case) as Template attribute
  • Put the following text in the Attributes property
    javascript:confirmDelete('message to user','request string');
  • Clear the content of the property Button Request Value
  • Set the property Button Request Source Type to Always null


Happy scripting.

8 comments:

nxg said...

I wouldn't put the #BUTTON_ATTRIBUTES# , as the name says it doesn't belong there (no need for attributes in an attribute).
I recommend to put it in like that <a href="#LINK#" #BUTTON_ATTRIBUTES#>

Now add in the attributes property: onclick="return confirmDelete('message to user','request string');"

That way you can still use the attribute property to add other attributes.

Byte64 said...

Nxg,
did you try that?

When i press the Cancel button, the page is submitted anyway.
If you look at the source code, here is how the button code looks like:

<a href="javascript:doSubmit('MULTI_ROW_DELETE');" onclick="return confirmDelete('Press OK to delete rows','MULTI_ROW_DELETE');"><img src="/i/themes/theme_1/button_alt2_left.gif" alt="" width="11" height="20" /></a>

I am not an expert of javascript, but from what i see, it seems that
Internet Explorer 7 and Firefox 2.0.0.1 are executing both the doSubmit and the onclick event or they are simply ignoring the return value in the onclick javascript code.

The reason why i came up with this workaround must be because of this weird behavior and also the fact that i could not get rid of the doSubmit (for some reason ApEx manages to add it even if you set the request to null), so i decided to omit the #LINK# substitution string having wasted enough time trying to figure out how to prevent Apex from submitting the page.

May be there is some way to make it work, i just gave up at a certain point, but feel free to post the definitive solution if you find it.

In the end i am using the template just as a workaround for this special situation, so i don't see potential problems with standard buttons, as i am using other templates in that case.

Thanks

nxg said...

I didn't try it until now, but I know what the problem is.
I misunderstood how confirmDelete does things.
The browsers don't ignore the return value it's just that confirmDelete doesn't return anything, that way it is always "true".

Instead of the - onclick="return confirmDelete('message to user','request string');" - put in a - onclick="confirmDelete('message to user','request string'); return false;" .

That way the "javascript:doSubmit('MULTI_ROW_DELETE');" is always ignored.

A cleaner solution would be that you put in - onclick="return confirm('Would you like to perform this delete action?')" .
That way it should use the "javascript:doSubmit('MULTI_ROW_DELETE');" if you click "OK", and do nothing if you click "Cancel".

This two ways should work with standard templates (well the ones that have #BUTTON_ATTRIBUTES# in it) out of the box.

I tried "Go')" onclick="return confirm('Press OK to delete rows?" as request, but unfortunately it escapes the quotes, so there is no solution that works out of the box with all templates, at least not one I know of.


Sorry for the delayed response, I almost forgot about my post here.

Byte64 said...

Nxg,
i am not sure i understand what you are suggesting here.
I looked at the source code of confirmDelete and if you don't put anything as second argument in the function call, it will use the default string "Delete".
So that introduces a problem instead of fixing one.

Concerning the final statement about the problem of the escaped quotes, i am missing the point.

As you say, if no solution works out of the box in all cases, why i should take an obscure javascript route instead of a clean custom template that does the job without a hitch?

Thanks,
Flavio

nxg said...

Only in the first it is confirmDelete, confirm (or document.confrim) is like alert a built in javascript function (confirmDelete uses confirm).

Using it like I suggest makes it easier to work with existing code (like one that already has additional attributes) or if you're not sure if you need to add some more attributes.
It's also easier to understand for someone without looking into the templates.

If you're sure you'll just need href without any other attributes then it's up to you what you use, but may be it's interesting for other users of APEX/HTMLDB.

The problem I see with using #BUTTON_ATTRIBUTES# for href is that it may confuse others or yourself someday.

Using "return confirm(something)" in onclick is in my opinion a cleaner and more readable solution
(even more than using confirmDelete, in that case, because the request given in the item's properties is still used).

My final statement with escaped quotes was just something I tried (and I just wanted to let you know) that would work out of the box no matter if the template has #BUTTON_ATTRIBUTES# in it or not, but of course it would by no means a clean solution (and it would even be more confusing for others), as it doesn't even work it's no valid solution at all.

In the end it's of course up to the developer.

Byte64 said...

Thanks for clearing this up, Nxg.

In a perfect world i'd expect Oracle Apex team to add the URL property to Button items, making them perfectly equivalent to standard buttons.

The lack of the URL property is what made this story start in the first place.

Concerning modified templates, i see where you come from. If i remove a "standard" substitution string, i'll make life very hard for someone who needs to track down a problem and is taking for granted the existence of that string in the template.

Thanks for stressing out this aspect.

Bye,
Flavio

Byte64 said...

I had to do a similar operation again today (more than one year later) and i needed to get rid of the javascript redirect that is included when you choose "URL" as optional URL redirect, because i wanted a simple link. In a similar fashion, i modified the original button template to remove completely the #LINK# substitution string and i simply put my href="..." stuff inside the button attributes property.

snake said...

thank you, thank you, thank you.

i've was frustrated half the day why my attributes weren't happening.

i also agree with nxg about the placement of the #button_attributes# substitution string. that's what i did.

but, still, i wouldn't have gotten there without finding your post thru some miracle.

yes you can!

Two great ways to help us out with a minimal effort. Click on the Google Plus +1 button above or...
We appreciate your support!

latest articles