function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
DroDro 

Can't use rerender and onclick together on commandlink/commandbutton?

I've got a visualforce page that displays a list of child items with links that allow them to be deleted.  I'm trying to refresh the list upon deletion with AJAX, but have run into a stumbling block.  It appears that if I use an onclick attribute and rerender attribute together on the commandlink doing the deletion, it doesn't work.  I'm using the onclick attribute to popup a confirmation box and the rerender to attempt the AJAX refresh.  If I drop the onclick, it works as expected (with no confirmation).  If I drop the rerender, if works as expected (with a full page refresh).  If I use both, it pops up the confirmation box, but then doesn't even call the controller (nothing shows up in the system log).

 

It appears to exhibit the same behavior if I substitute a commandbutton for the commandlink.

 

I've reproduced this with the simple code here (though the real code is returning a list of actual SObjects)...

 

Page:

 

 

<apex:page controller="TestController">
<apex:pageMessages />

  <apex:form >
    <apex:pageBlock title="Test" id="ListBlock">
        <apex:pageBlockTable value="{!Records}" var="i">
            <apex:column headerValue="Action">
                    <apex:commandLink action="{!delrec}" immediate="true"  onclick="return confirm('Are you sure?')" 
                        rerender="ListBlock" >Del
                        <apex:param name="delid" value="{!i}"/>
                    </apex:commandLink>
            </apex:column>
            <apex:column headerValue="ID"  > 
                    <apex:outputtext value="{!i}" />
            </apex:column>        
        </apex:pageBlockTable> 
       </apex:pageBlock> 
  </apex:form>
</apex:page>

 Controller:

 

public with sharing class TestController {
    Map<string,Integer> x;
	
    public TestController() {
    	x = new Map<string,Integer>();
    	x.put('1',1);
    	x.put('2',2);
    	x.put('3',3);
    }

    public List<Integer> getRecords() {
        return x.values();
    }

    public PageReference delRec() {
    	x.remove(ApexPages.currentPage().getParameters().get('delid'));   
        return null;
    }
}

 

Any ideas? 

 

Thanks!

 

   - Dov

 

 

Best Answer chosen by Admin (Salesforce Developers) 
Imran MohammedImran Mohammed

 

Try this

 

<apex:page controller="TestController">

    <head>

        <script type='text/javascript'>

function confirmMessage(recId)

       {

confirm('Are you sure');

document.getElementById('{!$Component.formID.delRecID}').value = recId;

delRecAction();

}

</script>

    </head>

<apex:pageMessages />

 

  <apex:form id="formID">

 

    <apex:actionFunction name="delRecAction" action="{!delrec}" rerender="ListBlock"/>

    <apex:inputHidden value="{!delRecVal}" id="delRecID"></apex:inputHidden>

 

    <apex:pageBlock title="Test" id="ListBlock">

        <apex:pageBlockTable value="{!Records}" var="i">

            <apex:column headerValue="Action">

                    <apex:commandLink onclick="return confirmMessage('{!i}')" rerender="ListBlock" >Del

                        <apex:param name="delid" value="{!i}"/>

                    </apex:commandLink>

            </apex:column>

            <apex:column headerValue="ID"  > 

                    <apex:outputtext value="{!i}" />

            </apex:column>        

        </apex:pageBlockTable> 

       </apex:pageBlock> 

  </apex:form>

</apex:page>

 

In Apex class , add variable delRecVal

 

public with sharing class TestController {

    Map<string,Integer> x;

public String delRecVal {get; set;}

 

    public TestController() {

        delRecVal = null;

     x = new Map<string,Integer>();

     x.put('1',1);

     x.put('2',2);

     x.put('3',3);

    }

 

    public List<Integer> getRecords() {

        return x.values();

    }

 

    public PageReference delRec() {

     x.remove(delRecVal);   

        return null;

    }

}

 

If you face any issues let me know.

All Answers

Imran MohammedImran Mohammed

 

Try this

 

<apex:page controller="TestController">

    <head>

        <script type='text/javascript'>

function confirmMessage(recId)

       {

confirm('Are you sure');

document.getElementById('{!$Component.formID.delRecID}').value = recId;

delRecAction();

}

</script>

    </head>

<apex:pageMessages />

 

  <apex:form id="formID">

 

    <apex:actionFunction name="delRecAction" action="{!delrec}" rerender="ListBlock"/>

    <apex:inputHidden value="{!delRecVal}" id="delRecID"></apex:inputHidden>

 

    <apex:pageBlock title="Test" id="ListBlock">

        <apex:pageBlockTable value="{!Records}" var="i">

            <apex:column headerValue="Action">

                    <apex:commandLink onclick="return confirmMessage('{!i}')" rerender="ListBlock" >Del

                        <apex:param name="delid" value="{!i}"/>

                    </apex:commandLink>

            </apex:column>

            <apex:column headerValue="ID"  > 

                    <apex:outputtext value="{!i}" />

            </apex:column>        

        </apex:pageBlockTable> 

       </apex:pageBlock> 

  </apex:form>

</apex:page>

 

In Apex class , add variable delRecVal

 

public with sharing class TestController {

    Map<string,Integer> x;

public String delRecVal {get; set;}

 

    public TestController() {

        delRecVal = null;

     x = new Map<string,Integer>();

     x.put('1',1);

     x.put('2',2);

     x.put('3',3);

    }

 

    public List<Integer> getRecords() {

        return x.values();

    }

 

    public PageReference delRec() {

     x.remove(delRecVal);   

        return null;

    }

}

 

If you face any issues let me know.

This was selected as the best answer
DroDro

That worked great.  Thanks! 

 

I just had to tweak the javascript a little so that "cancel" worked:

 

function confirmMessage(recId) {
   if (confirm('Are you sure')) {
      document.getElementById('{!$Component.formID.delRecID}').value = recId;
      delRecAction();
   }
}

 

 

Is there some reason the original code doesn't work?  Is it a bug or some nuance that I'm missing?

 

In any case, thanks for the help!

 

   - Dov

 

 

jwetzlerjwetzler

Yeah there's a nuance here that's not obvious.  Actions that fire off AJAX commands have to do so via javascript calls.  When you add events like onclick to insert your own javascript, that stuff gets prepended before the AJAX call.  So if you've got a confirm statement with a return in it, you're really returning from your javascript statement before it gets to submit anything.

 

The solution is only doing the return if someone clicks cancel, so: 

  <apex:commandButton onclick="if (!confirm('are you sure?')) return;" rerender="theForm"/>

<apex:commandButton onclick="if (!confirm('are you sure?')) return;" rerender="theForm"/>

 

DroDro

That simple change worked great and avoids the somewhat messier javascript needed otherwise.  Thanks!

 

   -Dov