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
Denise CrosbyDenise Crosby 

apex commandlink action not working

I am using some simple code to execute an EditAccount method after an apex commandLink is clicked. But, I can't get the method to execute and cannot find a good solution after searching existing questions. Is there something wrong that I'm doing? Thanks

Visualforce page:
<apex:page controller="IMS_CP_Projects_controller1">
    <html>

    <body>
        <apex:form>
            <apex:outputPanel id="editaccounts">

                <table id="dataTable">
                    <thead>
                        <tr>
                            <th>Account Name</th>
                            <th>id</th>
                            <th>Edit</th>
                        </tr>
                    </thead>
                    <tbody>

                        <apex:repeat value="{!Accounts}" var="A">
                            <tr>
                                <td data-label="Name">{!A.Name}</td>
                                <td data-label="id">{!A.id}</td>
                                <td data-label="Edit">
                                    <apex:commandLink action="{!EditAccount}" value="Edit" id="editcmd">
                                        <apex:param assignTo="{!editid}" value="{!A.id}" name="editid" /> {!A.id}
                                    </apex:commandLink>
                                </td>
                            </tr>
                        </apex:repeat>
                    </tbody>
                </table>

            </apex:outputPanel>
        </apex:form>
    </body>

    </html>
</apex:page>

Custom Controller:
public class IMS_CP_Projects_controller1 {

	public string editid { get; set; }

	public transient List<Account> Accounts { get; set; }

	public IMS_CP_Projects_controller1() {
		Accounts = [SELECT id, name	FROM account LIMIT 20];
	}
  
	public void EditAccount() {
		System.debug('-------- Edit Account --------');
	}
	}

Thanks so much for helping.
Best Answer chosen by Denise Crosby
Alain CabonAlain Cabon
Hi Denise,

It is one of the trap of the Salesforce VFP that needs a workaround and some tricks.
 
<apex:page controller="IMS_CP_Projects_controller1">
    <html>        
        <body>
            <apex:form>
                <apex:outputPanel id="editaccounts">                 
                    <table id="dataTable">
                        <thead>
                            <tr>
                                <th>Account Name</th>
                                <th>id</th>
                                <th>Edit</th>
                            </tr>
                        </thead>
                        <tbody>                            
                            <apex:repeat value="{!Accounts}" var="A">
                                <tr>
                                    <td data-label="Name">{!A.Name}</td>
                                    <td data-label="id">{!A.id}</td>
                                    <td data-label="Edit">
                                      <apex:actionRegion>
                                        <apex:commandLink action="{!EditAccount}" value="Edit" id="editcmd" reRender="myPanel">
                                            <apex:param assignTo="{!editid}" value="{!A.id}" name="editid" /> {!A.id}
                                        </apex:commandLink>
                                      </apex:actionRegion>
                                    </td>
                                </tr>
                            </apex:repeat>
                        </tbody>
                    </table>
                    <apex:panelGroup id="myPanel"></apex:panelGroup>
                </apex:outputPanel>
            </apex:form>
        </body>        
    </html>
</apex:page>
 
public class IMS_CP_Projects_controller1 {

	public string editid { get; set; }

	public transient List<Account> Accounts { get; set; }

	public IMS_CP_Projects_controller1() {
		Accounts = [SELECT id, name	FROM account LIMIT 20];
	}
  
	public PageReference EditAccount() {
		System.debug('-------- Edit Account --------' + editid );
        return new PageReference('/' + editid );
	}
}

Best regards
Alain

All Answers

Alain CabonAlain Cabon
Hi Denise,

It is one of the trap of the Salesforce VFP that needs a workaround and some tricks.
 
<apex:page controller="IMS_CP_Projects_controller1">
    <html>        
        <body>
            <apex:form>
                <apex:outputPanel id="editaccounts">                 
                    <table id="dataTable">
                        <thead>
                            <tr>
                                <th>Account Name</th>
                                <th>id</th>
                                <th>Edit</th>
                            </tr>
                        </thead>
                        <tbody>                            
                            <apex:repeat value="{!Accounts}" var="A">
                                <tr>
                                    <td data-label="Name">{!A.Name}</td>
                                    <td data-label="id">{!A.id}</td>
                                    <td data-label="Edit">
                                      <apex:actionRegion>
                                        <apex:commandLink action="{!EditAccount}" value="Edit" id="editcmd" reRender="myPanel">
                                            <apex:param assignTo="{!editid}" value="{!A.id}" name="editid" /> {!A.id}
                                        </apex:commandLink>
                                      </apex:actionRegion>
                                    </td>
                                </tr>
                            </apex:repeat>
                        </tbody>
                    </table>
                    <apex:panelGroup id="myPanel"></apex:panelGroup>
                </apex:outputPanel>
            </apex:form>
        </body>        
    </html>
</apex:page>
 
public class IMS_CP_Projects_controller1 {

	public string editid { get; set; }

	public transient List<Account> Accounts { get; set; }

	public IMS_CP_Projects_controller1() {
		Accounts = [SELECT id, name	FROM account LIMIT 20];
	}
  
	public PageReference EditAccount() {
		System.debug('-------- Edit Account --------' + editid );
        return new PageReference('/' + editid );
	}
}

Best regards
Alain
This was selected as the best answer
Alain CabonAlain Cabon
It is one of the traps of the Salesforce VFP that needs a workaround and some tricks

Why do you need a rerender while you change completely the navigation finally? That is the trap (old bug)
 
Steven NsubugaSteven Nsubuga
@Alain Cabon, this is very enlightening, thank you!!!
I wish I could like your response two or more times.
Just 1 minor edit to the apex class, in case the intention of the commandlink was to open the record in edit mode then 
return new PageReference('/' + editid + '/e');
is more appropriate.
Alain CabonAlain Cabon
@Steven Thank you and congratulations for your excellent score now (All star) (it is a good training here but very difficult and time consuming).  

Denise used nothing in fact for the redirection in her question and I used a very basic redirection indeed.
You have posted an excellent suggestion with the '/e' for the edition directly.  

Best regards
Alain
Denise CrosbyDenise Crosby
Alain and Steven,
Thank you for these great suggestions. I will try them tonight. My page is not redirecting to any other page to do the edit. It is using booleans to render different apex outputpanels depending on what link/method you are on within the same page. I don't think it's a great design, but I've inherited it.
Thanks again. Will post again when I know it works.
Denise
Denise CrosbyDenise Crosby
Alain, I just have to say you are the best!
Denise CrosbyDenise Crosby
Hi Alain,
One followup question. Is it absolutely necessary to return a pageReference? I want to return null so I can stay on the same page. There are many booleans set for rendering different apex outputpanels on the page so I don't want to go to a new page. Sorry if this is a real basic question.
 
public void EditProject() {
		System.debug('-------- Edit Project --------' + editid);
		renderSubmitEditProjects = true;
		renderEditProjectsTable = false;
		renderEditCurrentProject = true;
		renderProjectSummarySection = false;
		renderProjectInputSection = true;

		CurrentProject = new MProject__c();
                    
        CurrentProject = [SELECT id, name 
				FROM MProject__c where id =: editid];  
		System.debug(CurrentProject);
	
		return null;
	}
Alain CabonAlain Cabon
Hi Denise,

You need to return a pageReference and the same page is just : return null indeed.
You can just rerender a part of your form (used above with a <apex:panelGroup> ( you can use almost all the apex tags instead of panel group).

You can use:   public pageReference  EditProject()  { return null; }
That is allowed and very common.

If you have a current code that doesn't work, you can post it and we can fix the problem.
 
Alain CabonAlain Cabon
Hi Denise,

You can rerender many panels.

<apex:commandLink action="{!EditAccount}" value="Edit" id="editcmd" reRender="myPanel1,myPanel2">
<apex:page controller="IMS_CP_Projects_controller1">
    <html>        
        <body>
            <apex:form >
                  <apex:panelGroup id="myPanel1">
                        <h1>TEST: {!selectedid} / {!editid} </h1>
                    </apex:panelGroup>
                <apex:outputPanel id="editaccounts">               
                    <table id="dataTable">
                        <thead>
                            <tr>
                                <th>Account Name</th>
                                <th>id</th>
                                <th>Edit</th>
                            </tr>
                        </thead>
                        <tbody>                            
                            <apex:repeat value="{!Accounts}" var="A">
                                <tr>
                                    <td data-label="Name">{!A.Name}</td>
                                    <td data-label="id">{!A.id}</td>
                                    <td data-label="Edit">
                                        <apex:actionRegion >
                                            <apex:commandLink action="{!EditAccount}" value="Edit" id="editcmd" reRender="myPanel1,myPanel2">
                                                <apex:param assignTo="{!editid}" value="{!A.id}" name="editid" /> {!A.id}
                                            </apex:commandLink>
                                        </apex:actionRegion>
                                    </td>
                                </tr>
                            </apex:repeat>
                        </tbody>
                    </table>
                    <apex:panelGroup id="myPanel2">
                        <h1>TEST: {!selectedid} / {!editid} </h1>
                    </apex:panelGroup>                   
                </apex:outputPanel>
            </apex:form>
        </body>        
    </html>
</apex:page>
 
public class IMS_CP_Projects_controller1 {
    
    public string editid { get; set; }    
    public string selectedid { get; set; }   
    public transient List<Account> Accounts { get; set; }
    
    public IMS_CP_Projects_controller1() {
        Accounts = [SELECT id, name	FROM account LIMIT 20];
    }
    
    public PageReference EditAccount() {
        System.debug('-------- Edit Account --------' + editid );
        selectedid = editid;
        return null;
        //return new PageReference('/' + editid );
    }
}

Tell me, Denise, if you have any new problem.

Best regards
Alain
Denise CrosbyDenise Crosby
Hi Alain,
Thanks for all your great suggestions.
No matter what I try, I cannot get the Edit button to render the page correctly, even though it is now executing the EditProject method. Let me know if I should enter this as a new question. I can mark your answer here as Best Answer. I think it's related to all the outputpanels being rendered based on boolean values, but I'm not sure. 
 
public class IMS_CP_Projects_controller2 {
	public MentorProjectDataAccessor projectAccessor = new MentorProjectDataAccessor();

	//Sections
	public boolean ProjectSection { get; set; }

	//Sub Sections
	public boolean SubHomeSection { get; set; }
	public boolean ApprovalStatusOfProjects { get; set; }
	public boolean SubmitEditProjects { get; set; }
	public boolean EditProjectsTable { get; set; }

	public Mentor_Project__c CurrentProject { get; set; }
	public string editid { get; set; }
	public transient List<Messaging.SingleEmailMessage> Mailers { get; set; }
	public boolean ProjectContinue { get; set; }
	public boolean EditCurrentProject { get; set; }
	public transient List<Mentor_Project__c> Projects { get; set; }

	public IMS_CP_Projects_controller2() {

        System.debug('Starting Controller');

		EditCurrentProject = false;
		ProjectContinue = false;

		SubHomeSection = true;
		Projects = [
				SELECT id, name, Project_Name_with_Identifier__c
				FROM Mentor_Project__c
				WHERE Center__c = 'Thomas'
				AND RecordTypeId = :Schema.SObjectType.Mentor_Project__c.getRecordTypeInfosByName().get('Application').getRecordTypeId()
				ORDER BY Name
				LIMIT 20
		];
	}

	public void BackSubHomeSection() {
		SubHomeSection = true;
		ProjectSection = true;
		SubmitEditProjects = false;
		EditProjectsTable = false;
		CurrentProject = new Mentor_Project__c();
		ProjectContinue = false;
	}

	public void RenSubmitEditProjects() {
		SubHomeSection = false;
		SubmitEditProjects = true;
	}

	public void RenEditProjectsTable() {
		System.debug('Render Edit Projects Table');
		SubHomeSection = false;
		EditProjectsTable = true;
		Projects = projectAccessor.getApplicationProjectsByCenterAndSession(null, null);
	}
    
	public PageReference EditProject() {
		System.debug('-------- Edit Project --------' + editid);
		SubmitEditProjects = true;
		EditProjectsTable = false;
		CurrentProject = new Mentor_Project__c();
		CurrentProject = [SELECT id, name, description__c, Project_Name_with_Identifier__c FROM Mentor_Project__c where id =: editid];  

		return null;
	}
}



 
public class IMS_CP_Projects_controller2 {
	public MentorProjectDataAccessor projectAccessor = new MentorProjectDataAccessor();

	//Sections
	public boolean ProjectSection { get; set; }

	//Sub Sections
	public boolean SubHomeSection { get; set; }
	public boolean ApprovalStatusOfProjects { get; set; }
	public boolean SubmitEditProjects { get; set; }
	public boolean EditProjectsTable { get; set; }

	public Mentor_Project__c CurrentProject { get; set; }
	public string editid { get; set; }
	public transient List<Messaging.SingleEmailMessage> Mailers { get; set; }
	public boolean ProjectContinue { get; set; }
	public boolean EditCurrentProject { get; set; }
	public transient List<Mentor_Project__c> Projects { get; set; }

	public IMS_CP_Projects_controller2() {

        System.debug('Starting Controller');

		EditCurrentProject = false;
		ProjectContinue = false;

		SubHomeSection = true;
		Projects = [
				SELECT id, name, Project_Name_with_Identifier__c
				FROM Mentor_Project__c
				WHERE Center__c = 'Thomas'
				AND RecordTypeId = :Schema.SObjectType.Mentor_Project__c.getRecordTypeInfosByName().get('Application').getRecordTypeId()
				ORDER BY Name
				LIMIT 20
		];
	}

	public void BackSubHomeSection() {
		SubHomeSection = true;
		ProjectSection = true;
		SubmitEditProjects = false;
		EditProjectsTable = false;
		CurrentProject = new Mentor_Project__c();
		ProjectContinue = false;
	}

	public void RenSubmitEditProjects() {
		SubHomeSection = false;
		SubmitEditProjects = true;
	}

	public void RenEditProjectsTable() {
		System.debug('Render Edit Projects Table');
		SubHomeSection = false;
		EditProjectsTable = true;
		Projects = projectAccessor.getApplicationProjectsByCenterAndSession(null, null);
	}
    
	public PageReference EditProject() {
		System.debug('-------- Edit Project --------' + editid);
		SubmitEditProjects = true;
		EditProjectsTable = false;
		CurrentProject = new Mentor_Project__c();
		CurrentProject = [SELECT id, name, description__c, Project_Name_with_Identifier__c FROM Mentor_Project__c where id =: editid];  

		return null;
	}
}

Thank you so much for helping!


 
Alain CabonAlain Cabon
Hi Denise,

You have posted the same controller twice?

The VFP is also interesting.
 
Denise CrosbyDenise Crosby
I am sorry. I must be getting blurry eyed from trying to find an error in 8000 lines of code. These are just pieces.

Here is the VFP
 
<apex:page controller="IMS_CP_Projects_controller2">
    <html>

    <body>
        <apex:form>

            <!--Sub Home Page-->
            <apex:outputPanel rendered="{!SubHomeSection}">
                <main>
                    <h1>What would you like to do?</h1>
                    <apex:commandLink styleClass="bh1" value="Edit Projects" action="{!RenEditProjectsTable}" />
                </main>
            </apex:outputPanel>

            <apex:outputPanel rendered="{!SubmitEditProjects}" id="submiteditprojectspanel">
                <main>
                    <label>Project Title:</label>
                    <p>Choose a title that describes your project.</p>
                    <apex:inputField value="{!CurrentProject.Name}" />
                    <label>Project Description
                        <span>Describe what a person will be doing on this project.</span>
                    </label>
                    <apex:inputTextarea value="{!CurrentProject.Description__c}" />
                </main>
            </apex:outputPanel>

            <!--EditProjectsTable-->
            <apex:outputPanel id="editprojects" rendered="{!EditProjectsTable}">
                <main>
                    <apex:commandlink action="{!BackSubHomeSection}" value="<< Back to Projects" />
                    <h3>My Projects</h3>
                    <table id="dataTable">
                        <thead>
                            <tr>
                                <th>Project Title</th>
                                <th>id</th>
                                <th>Edit</th>
                            </tr>
                        </thead>
                        <tbody>
                            <apex:repeat value="{!Projects}" var="P">
                                <tr>
                                    <td data-label="Project Title">{!P.Project_Name_with_Identifier__c}</td>
                                    <td data-label="id">{!P.id}</td>
                                    <td data-label="Edit">
                                        <apex:actionRegion>
                                            <apex:commandLink action="{!EditProject}" value="Edit" id="editcmd" reRender="submiteditprojectspanel">
                                                <apex:param assignTo="{!editid}" value="{!P.id}" name="editid" /> {!P.id}
                                            </apex:commandLink>
                                        </apex:actionRegion>
                                    </td>
                                </tr>
                            </apex:repeat>
                        </tbody>
                    </table>

                </main>
            </apex:outputPanel>
        </apex:form>
    </body>

    </html>
</apex:page>

 
Alain CabonAlain Cabon
Denise,  

You have got all the traps together.  <apex:outputPanel> is very capricious and doesn't respond correctly to the rerender (?).

rerender is stil interesting to be used and necessary

<apex:commandLink rerender="editprojects"
<apex:outputPanel rendered="{!SubHomeSection}">
   <main>
       <h1>What would you like to do?</h1>         
       <!-- SubHomeSection = false;	EditProjectsTable = true;  -->
<apex:commandLink styleClass="bh1" value="Edit Projects" action="{!RenEditProjectsTable}" rerender="editprojects"/>               
   </main>
</apex:outputPanel>
<apex:panelGroup id="editprojects">
<!--EditProjectsTable-->
        <apex:panelGroup id="editprojects">      
            <apex:outputPanel rendered="{!EditProjectsTable}">      
                <main>
                </main>
            </apex:outputPanel>
       </apex:panelGroup>
<apex:panelGroup id="editprojects">  responds correctly. It is a complication that seems useless but that works.
Denise CrosbyDenise Crosby
Thank you Alain. I don't have my page working exactly right yet, but I think I get the gist of it. Thanks!!!!
Alain CabonAlain Cabon
Hi Denise;

8,000 lines? it is much too big. 
And the few lines, you have posted are already tricky with many variables and combinations (+ all the things that should work but don't work).

<apex:outputPanel> is a very common component but combined with rerender and rendered, that doesn't work here for your sample (?) but all your code is correct in principle. That really is quite unnerving.

The following articles are interesting but old now and with the commandlink, that should work without a workaround ... excepted in an iteration (?).

Jeff Douglas: This post is a slight tweak of yesterday's post, Passing Parameters with a CommandLink. In theory you should just be able to switch out the CommandLink component with a CommandButton component and be golden. However, not so fast. There seem to still be a bug with the CommandButton component.
https://blog.jeffdouglas.com/2010/03/04/passing-parameters-with-a-commandbutton/
https://blog.jeffdouglas.com/2010/03/03/passing-parameters-with-a-commandlink/
He talked about the workaround with "rerender" in his blog but I don't retrieve this part.

In brief, there are bugs and when you are trapped, you are losing a lot of time (all the code is correct according the documentation but that doesn't work).

For commandbutton in a loop: it is one solution: https://developer.salesforce.com/forums/?id=9060G000000BiTJQA0

With salesforce, every four months, that could work better or badly as you know so some old articles (more than some months) can be obsolete and fixed (known issues).

Best regards
Alain
Denise CrosbyDenise Crosby
Hi Alain,
I finally got my page done and it's working great. Thanks again for your help. I couldn't have done it without you.
Alain CabonAlain Cabon
Hi Denise,

Congrats! It is one of the most dreaded problem with a VFP. I suffered a lot myself with a similar page using some commandbutton and commandlink as well as Jeff Douglas, Trailhead Developer Advocate for modules with Apex and VFP, a great expert who gave the basis for a solution on his blog. That drives all of us nuts until that works finally when all the workarounds and tricks are in place (very time consuming)..

Best regards
Alain