2

So this is a weird one.

I have two buttons in a Table Column. They are HTML buttons with action support. When I click on the first one, it runs the second button's Method. When I comment out the second button, the first button calls the right method.

Weird, right? Thoughts? CODE BELOW

<apex:form>
  <apex:pageblock>
       <apex:pageblocktable value="{!wrapComplaintList}" var="c" id="complaintTable" >
            <apex:column >
                <apex:facet name="header">
                    Action
                </apex:facet>
                 <apex:outputpanel layout="block">

    //THIS IS BUTTON 1// <button class="dialogEventsOpener" type="button" style="cursor:pointer">
                       <apex:actionsupport action="{!retrieveEventsTable}" rerender="pbEvents" event="onclick" oncomplete="sortTable(); return false">
                                Events
                         <apex:param name="eventsParam" value="{!c.complaintOBJ.id}" assignto="{!eventsComplaintID}" />
                            </apex:actionsupport>
                        </button>

 //BUTTON 2            <button class="dialogRFIOpener" type="button" style="cursor:pointer"> 
                       <apex:actionsupport action="{!retrieveRFITable}" rerender="pbRFI" event="onclick" oncomplete="sortTable(); return false">
                             RFI
                             <apex:param name="RFIParam" value="{!c.complaintOBJ.id}" assignto="{!RFIComplaintID}" />
                            </apex:actionsupport>
                        </button> 
                 </apex:outputpanel>
                </apex:column>  

Below is the Java script.

function sortTable(){

              j$("[id$=complaintTable]")
        .tablesorter({theme: 'green' ,headerTemplate: '{content} {icon}',widthFixed:true, showProcessing: true,  widgets : ['zebra','resizable', 'uitheme','columns']
                     ,headers: {0: {sorter:false} }});

           j$("[id$=eventsTable]")

          .tablesorter({theme: 'green' , widthFixed:true, showProcessing: true, widgets : ['zebra'], headers: {0: {sorter:false}}
                       }) 

             .bind('pagerChange pagerComplete pagerInitialized pageMoved', function(e, c){
               var msg = '"</span> event triggered, ' + (e.type === 'pagerChange' ? 'going to' : 'now on') +
                   ' page <span class="typ">' + (c.page + 1) + '/' + c.totalPages + '</span>';
               j$('#display')
               .append('<li><span class="str">"' + e.type + msg + '</li>')
               .find('li:first').remove();
           })
            .tablesorterPager({container: j$(".pager"), size: 5, fixedHeight:true});


        j$("[id$=RFITable]")

          .tablesorter({theme: 'green' , widthFixed:true, showProcessing: true, widgets : ['zebra'], headers: {0: {sorter:false}}
                       }) 

             .bind('pagerChange pagerComplete pagerInitialized pageMoved', function(e, c){
               var msg = '"</span> event triggered, ' + (e.type === 'pagerChange' ? 'going to' : 'now on') +
                   ' page <span class="typ">' + (c.page + 1) + '/' + c.totalPages + '</span>';
               j$('#display')
               .append('<li><span class="str">"' + e.type + msg + '</li>')
               .find('li:first').remove();
           })
            .tablesorterPager({container: j$(".pagerRFI"), size: 5, fixedHeight:true});

        init();
    }
    </script>

2 Answers 2

1

You shouldn't try to mix arbitrary Visualforce support elements with plain HTML. The fact that it works at all is pretty surprising; normal buttons don't have all the necessary markup/parameters for the Visualforce API to correctly identify the correct action to perform.

If you need to call a function and reRender, either use apex:commandButton, or you use an apex:actionFunction, which is the supported method for reRendering from JavaScript:

<!-- Do not include this in a loop, but inside apex:form.
     Parameter will be supplied by JavaScript -->
<apex:actionFunction
    name="retrieveEventsTableJS" 
    action="{!retrieveEventsTable}" 
    rerender="pbEvents"
    oncomplete="sortTable(); return false">
    <apex:param name="eventsParam" value="" assignto="{!eventsComplaintID}" />
</apex:actionFunction>

<!-- Remember to use JSINHTMLENCODE when there's a possibility of 
     XSS injection. This code happens to be safe, because ID values 
     will never contain unsafe characters, but you should always practice
     safety -->
<button class="dialogEventsOpener" type="button" style="cursor:pointer" onclick="retrieveEventsTableJS('{!JSINHTMLENCODE(c.complaintOBJ.Id)}')" />
2
  • sfdcFox! I recognize you from lots of other answers, thanks for answering! I'll definitely try this in the AM. Thank you also for all your other answers on other issues - you've unknowingly helped me many other times :) EDIT: Side question... so generally any time I pass a parameter over, I should protect against XSS injection, just like SQL injection on text input fields?
    – RC82
    Nov 11, 2015 at 3:34
  • Visualforce elements will naturally protect against injection. You only need to worry about using merge fields with normal html. There's lot of tutorials online about when to use JSINHTMLECODE and JSENCODE.
    – sfdcfox
    Nov 11, 2015 at 4:45
0

An apex:actionSupport element adds support for an action to the element's parent Visualforce element. In your case, both apex:actionSupport elements have the same parent apex:outputPanel.

Because the button elements are children of the apex:outputPanel (div), clicks on the buttons bubble to the apex:outputPanel and the (last) action is triggered.

Wrapping each apex:actionSupport element in its own apex:outputPanel should fix the problem.

1
  • Oh wow, didn't know that - that makes sense! That's really good to know. Thanks for this, I'll try this out next time!
    – RC82
    Nov 23, 2015 at 18:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .