+ Start a Discussion
Craig PCraig P 

RemoteAction method does NOT work when invoked from within a pageBlockTable?

I have a VF page that lists members of a campaing.  Within in each row, I want the user to be able to click on a button to log an activity.

 

I have a RemoteAction method working fine, if it is invoked from an HTML element outside of the pageBlockTable.  However, when the RemoteAction is invoked from a button in a row in the pageBlockTable, it does not work.  Am I missing somthing obvious?

 

Class w/ RemoteAction - works fine when invoked from a button outside of a pageBlockTable

global with sharing class CampaignConsoleRemoteController {

    public String contactOrLeadId{ get; set; }
    public static Contact contact { get; set; }    

    /*******************************************************************************
    *    empty constructor...
    *******************************************************************************/
    public CampaignConsoleRemoteController(CampaignConsoleController controller) {}

    /*******************************************************************************
    *    remote method to add Activity for the Campaign Member...
    *******************************************************************************/
    @RemoteAction
    global static String addActivityHistory(String contactOrLeadId) {
        Task t = new Task();
        t.subject = 'Campaign call';
        t.type = 'Call';
        t.status = 'completed';
        t.activitydate = system.today();
        t.description = 'words words words';
        t.whoId = contactOrLeadId;
        //CE:  t.whatId = account.Id;
        insert t;        
                   
        return contactOrLeadId;
    }
}

 

Visualforce page...

<apex:page controller="CampaignConsoleController" extensions="CampaignConsoleRemoteController" action="{!getData}" id="ccPage">
    <script type="text/javascript">
        /*******************************************************************
        *     addActivityToCampaignMember(contactLeadId, noteElementId)
        *******************************************************************/
        function addActivityToCampaignMember(contactLeadId) {
            // debug info...
            console.log("contactLeadId: ", contactLeadId);
    
            // invoke the remote action on the server...
            Visualforce.remoting.Manager.invokeAction(
                '{!$RemoteAction.CampaignConsoleRemoteController.addActivityHistory}',
                contactLeadId, 
                function(result, event){
                      if( event.status ) {
                          // Get DOM IDs for HTML and Visualforce elements like this
                          console.log("inside anonymous function... result Id: ", result);                          
                          console.log("result Id: ", result);
                          document.getElementById("cepInput").innerHTML = result;
                      } else if (event.type === 'exception') {
                          document.getElementById("responseErrors").innerHTML = 
                          event.message + "<br/>\n<pre>" + event.where + "</pre>";
                      } else {
                          document.getElementById("responseErrors").innerHTML = event.message;
                      }
                }, 
                {escape: true}
            );        
            
            console.log("finishing JS function...");
        }
    </script>
 
    <body id="ccBody">
        <apex:sectionHeader title="Campaign Console"></apex:sectionHeader>
        <apex:form id="ccForm" >
           <!-- display error messages... -->
           <apex:pageMessages />
           <!-- display Contacts that are Campaign Members... -->
            <apex:pageBlock title="Contacts" id="ccPageBlock">
                <apex:pageBlockTable value="{!CampaignMemberContacts}" var="cm" id="ccPageBlockTable">
                   <apex:column rendered="false">
                        <apex:inputHidden value="{!cm.Contact.Id}" Id="memberId" />
                   </apex:column>
                   <apex:column headerValue="Company Name" value="{!cm.Contact.Account.name}" />
                   <apex:column value="{!cm.Contact.name}"/>
                   <apex:column value="{!cm.Contact.phone}"/>
                   <apex:column value="{!cm.Contact.email}" />
                   <apex:column headerValue="Status">
                       <apex:inputField value="{!cm.Status}"  onchange="updateRecords();" />
                   </apex:column>
                   <apex:column headerValue="Note"  >
                       <apex:inputTextArea value="{!note}" Id="ccContactNote" />
                   </apex:column>
                   <apex:column >
                       <!-- <apex:commandButton id="btnAddNote" value="Add Note" onclick="saveRow(jQuery(this).closest('tr').prevAll('tr').length, '{!cm.Contact.Id}')" /> -->
                       <!-- <apex:commandButton id="btnAddNote" value="Log Activity" onclick="saveRow('1', '{!cm.Contact.Id}', '{!$Component.ccContactNote}')" /> -->
                       <apex:commandButton id="btnAddNote" value="Log It!" onclick="addActivityToCampaignMember('{!cm.Contact.Id}')" />
                   </apex:column>
                </apex:pageBlockTable>
            </apex:pageBlock>
        </apex:form>    
    </body>    
</apex:page>

 

bob_buzzardbob_buzzard

One issue, I think, is that you are into a race condition here - when the user clicks the button, the onclick action fires which starts the javascript remoting, but once the onclick completes (and before the JS remoting has invoked the callback) the default behaviour of the commandbutton continues, which is to post back the form.

 

To stop this, your onclick needs to return false:

 

<apex:commandButton id="btnAddNote" value="Log It!" onclick="addActivityToCampaignMember('{!cm.Contact.Id}'); return false;" />