You need to sign in to do that
Don't have an account?
Need help creating multiple child records on one visualforce page via a related list button
Hello all,
I've been trying for awhile to create a list button that will allow the creation of multiple child records of the same parent record on one Visualforce page (rather than clicking save and new over and over). I need to pass the parent ID and assign a record type, and I'd prefer that happen without the user having to do anything other than click the button on the related list. My visualforce page works in that if I preview it, I can see each field in a column, and the "add" link is working to add new rows. However, the parent ID isn't getting passed, I can't figure out how to assign the record type ID, and the "x" link to delete a row isn't working.
I've posted on the forum about this multiple times, but have not received many replies.
This would be a huge help for the organizations I work with, and I'd be willing to pay for a few hours of someone's time to help me get the code right. Any one interested in helping me out?
Email ID: pradeepsm36@gmail.com
Below is the sample code to add multiple contacts.
Thanks
Prady01
I understood your requirement and also checked the code from your previous posts.
Use below code:
VF PAGE:
<apex:page standardController="Class_Enrollment__c" extensions="ClassEnrollmentExtensions">
<apex:form >
<apex:pageBlock >
<apex:pageBlockSection Title="Class Enrollment" columns="1" id="classId">
<apex:commandLink value="Add Class Enrollment" action="{!addClassEnrollment}" reRender="classId"/>
<apex:variable value="{!0}" var="num"/>
<apex:pageBlockTable value="{!ceRecord}" var="ce">
<apex:column headerValue="Class Enrollment Name">
<apex:inputfield value="{!ce.Name}"/>
</apex:column>
<apex:column headerValue="Notes">
<apex:inputfield value="{!ce.Notes__c}" required="false"/>
</apex:column>
<apex:column >
<apex:commandLink value="Remove" action="{!removeClassEnrollment}" reRender="classId">
<apex:param name="ceIndex" value="{!num}"/>
</apex:commandLink>
<apex:variable var="num" value="{!num+1}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
<apex:commandButton action="{!save}" value="Save"/>
<apex:commandButton action="{!cancel}" value="Cancel"/>
</apex:pageBlock>
</apex:form>
</apex:page>
CONTROLLER:
public class ClassEnrollmentExtensions {
public Session__c sessionRecord{get; set;}
public List<Class_Enrollment__c> ceRecord{get; set;}
public Integer ceIndex {get; set;}
public Id sessionId;
public ClassEnrollmentExtensions(ApexPages.StandardController controller){
sessionRecord = new Session__c();
sessionId = ApexPages.currentpage().getParameters().get('parentid');
sessionRecord = [SELECT Id, Name FROM Session__c WHERE Id = :sessionId];
ceRecord = new List<Class_Enrollment__c>();
ceRecord.add(new Class_Enrollment__c(Session__c = sessionId));
}
public void addClassEnrollment() {
ceRecord.add(new Class_Enrollment__c(Session__c = sessionId));
}
public void removeClassEnrollment() {
ceIndex = Integer.valueOf(ApexPages.currentPage().getParameters().get('ceIndex'));
ceRecord.remove(ceIndex);
}
public PageReference save() {
upsert ceRecord;
update sessionRecord;
PageReference page = new PageReference('/' + sessionId);
return page;
}
public PageReference cancel() {
PageReference page = new PageReference('/' + sessionId);
return page;
}
}
**Note:
1. Please add the fields of Class_Enrollment__c in the code as per your requirement
2. Create List button on Class_Enrollment__c having Content source as URL.
Do let me know if this helps you.
Thanks
This is super helpful, thank you!
I modified the code slightly because there were a couple of extra fields I wanted on the Visualforce page. I also renamed the Session object, because the API name on the object itself was Sessions__c, but the API name for the master-detail relationship on Class_Enrollments__c was Session__c (without the "s" at the end of Session). I realized this was causing me issues, so they are now both Session__c (object API name) and Session__c (field name on Class_Enrollments__c object).
I am running into a couple of issues:
1) I am returning this error whenever I try to preview the VF page:
System.QueryException: List has no rows for assignment to SObject
Class.ClassEnrollmentsExtensions.<init>: line 9, column 1
2) I would like to pass a specific record type ID (0120f000001QfBc) to all records created via this button. How do I do that?
Below is my amended code:
Class Enrollments VF:
<apex:page standardController="Class_Enrollments__c" extensions="ClassEnrollmentsExtensions">
<apex:form >
<apex:pageBlock >
<apex:pageBlockSection Title="Class Enrollment" columns="1" id="classId">
<apex:commandLink value="Add Class Enrollment" action="{!addClassEnrollments}" reRender="classId"/>
<apex:variable value="{!0}" var="num"/>
<apex:pageBlockTable value="{!ceRecord}" var="ce">
<apex:column headerValue="Youth Name">
<apex:inputfield value="{!ce.Youth_Name__c}"/>
</apex:column>
<apex:column headerValue="Works Wonders Record">
<apex:inputField value="{!ce.Works_Wonders_Youth_Name__c}"/>
</apex:column>
<apex:column headerValue="Attendance">
<apex:inputField value="{!ce.Attendance__c}"/>
</apex:column>
<apex:column headerValue="Participation Note">
<apex:inputfield value="{!ce.Participation_Note__c}" required="false"/>
</apex:column>
<apex:column >
<apex:commandLink value="Remove" action="{!removeClassEnrollment}" reRender="classId">
<apex:param name="ceIndex" value="{!num}"/>
</apex:commandLink>
<apex:variable var="num" value="{!num+1}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
<apex:commandButton action="{!save}" value="Save"/>
<apex:commandButton action="{!cancel}" value="Cancel"/>
</apex:pageBlock>
</apex:form>
</apex:page>
ClassEnrollmentsExtensions Controller:
public class ClassEnrollmentsExtensions {
public Session__c sessionRecord{get; set;}
public List<Class_Enrollments__c> ceRecord{get; set;}
public Integer ceIndex {get; set;}
public Id sessionId;
public ClassEnrollmentsExtensions(ApexPages.StandardController controller){
sessionRecord = new Session__c();
sessionId = ApexPages.currentpage().getParameters().get('parentid');
sessionRecord = [SELECT Id, Name FROM Session__c WHERE Id = :sessionId];
ceRecord = new List<Class_Enrollments__c>();
ceRecord.add(new Class_Enrollments__c(Session__c = sessionId));
}
public void addClassEnrollments() {
ceRecord.add(new Class_Enrollments__c(Session__c = sessionId));
}
public void removeClassEnrollment() {
ceIndex = Integer.valueOf(ApexPages.currentPage().getParameters().get('ceIndex'));
ceRecord.remove(ceIndex);
}
public PageReference save() {
upsert ceRecord;
update sessionRecord;
PageReference page = new PageReference('/' + sessionId);
return page;
}
public PageReference cancel() {
PageReference page = new PageReference('/' + sessionId);
return page;
}
}
Any help is appreciated!
You are getting error System.QueryException: List has no rows for assignment to SObject because when you are previewing your vf page, URL does not contain 'parentId' as parameter in it.
For previewing you better use: /apex/ClassEnrollmentPage?parentId=ANY_SESSION_RECORD_ID&recordTypeId=0120f000001QfBc
To pass specific record type Id (0120f000001QfBc) to all the records you need to modify your ClassEnrollmentsExtensions.cls
ClassEnrollmentsExtensions.cls
public class ClassEnrollmentExtensions {
public Session__c sessionRecord{get; set;}
public List<Class_Enrollment__c> ceRecord{get; set;}
public Integer ceIndex {get; set;}
public Id sessionId;
public Id recordTypeId;
public ClassEnrollmentExtensions(ApexPages.StandardController controller){
sessionRecord = new Session__c();
sessionId = ApexPages.currentpage().getParameters().get('parentid');
recordTypeId = ApexPages.currentpage().getParameters().get('recordtypeId');
sessionRecord = [SELECT Id, Name FROM Session__c WHERE Id = :sessionId];
ceRecord = new List<Class_Enrollment__c>();
ceRecord.add(new Class_Enrollment__c(Session__c = sessionId, RecordTypeId = recordTypeId ));
}
public void addClassEnrollment() {
ceRecord.add(new Class_Enrollment__c(Session__c = sessionId, RecordTypeId = recordTypeId ));
}
public void removeClassEnrollment() {
ceIndex = Integer.valueOf(ApexPages.currentPage().getParameters().get('ceIndex'));
ceRecord.remove(ceIndex);
}
public PageReference save() {
upsert ceRecord;
update sessionRecord;
PageReference page = new PageReference('/' + sessionId);
return page;
}
public PageReference cancel() {
PageReference page = new PageReference('/' + sessionId);
return page;
}
}
URL: /apex/ClassEnrollmentPage?parentId={!Session__c.Id}&recordtypeId=0120f000001QfBc
Please do not forget to mark this thread as SOLVED and answer as the BEST ANSWER if it helps address your issue.
Thanks
You are a lifesaver, thank you!
So, I am getting this error when trying to preview the button:
System.StringException: Invalid id: {!Class_Enrollments__c.SessionId__c}
Class.ClassEnrollmentsExtensions.<init>: line 10, column 1
However, when I do as you suggested and replace the ID with an actual ID of a session record, I can see the page. However, I am still having trouble with the "Remove" link. Because the Youth Name is a required field, I'm getting an error. Here is a demonstration:
When I don't try to add another row, the record saves beautifully!
Finally: once the Remove issue is fixed, how can I get help deploying this? I've done all of this in the sandbox, so I'd like to move it to production. Again, I'd be willing to provide compensation for someone to help walk me through how to do this for the first time!
Thank you!
As you can see, the parentID is empty :-/
Here is what I have on the URL parameter: /apex/Class_Enrollments_VF?parentId={!Class_Enrollments__c.SessionId__c}&recordtypeId=0120f000001QfBc
Here is my controller with the changes:
public class ClassEnrollmentsExtensions {
public Session__c sessionRecord{get; set;}
public List<Class_Enrollments__c> ceRecord{get; set;}
public Integer ceIndex {get; set;}
public Id sessionId;
public Id recordTypeId;
public ClassEnrollmentsExtensions(ApexPages.StandardController controller){
sessionRecord = new Session__c();
sessionId = ApexPages.currentpage().getParameters().get('parentid');
recordTypeId = ApexPages.currentpage().getParameters().get('recordtypeId');
sessionRecord = [SELECT Id, Name FROM Session__c WHERE Id = :sessionId];
ceRecord = new List<Class_Enrollments__c>();
ceRecord.add(new Class_Enrollments__c(Session__c = sessionId, RecordTypeId = recordTypeId));
}
public void addClassEnrollments() {
ceRecord.add(new Class_Enrollments__c(Session__c = sessionId, RecordTypeId = recordTypeId));
}
public void removeClassEnrollment() {
ceIndex = Integer.valueOf(ApexPages.currentPage().getParameters().get('ceIndex'));
ceRecord.remove(ceIndex);
}
public PageReference save() {
upsert ceRecord;
update sessionRecord;
PageReference page = new PageReference('/' + sessionId);
return page;
}
public PageReference cancel() {
PageReference page = new PageReference('/' + sessionId);
return page;
}
}
/apex/Class_Enrollments_VF?parentId={!Session__c.Id}&recordtypeId=0120f000001QfBc
It doesn't work if I preview from the button, but it works if I click the button on the related list.
OK sorry for all the confusion. So, can you help or direct me towards how to deploy this in production?
I appreciate your help so much!
I hope my solution is helping you to get your issues fixed.
Do you want to deploy the VF Page and its extension to the Production org or even the objects ?
Do let me know about this so that I can help you in that too.
Thanks
I want to deploy the VF page and its extension to Production! The objects are already created in Salesforce.
However, there is one additional fix I needed prior to deploying, I realized. The "Remove" link is not working. When I click that link, it tells me that the first field, "Youth Name" is required. How can I get the "Remove" link functioning properly?
I've been reading up on change sets. Is this a reasonable way to deploy the components once everything is working well?
Hi Blair,
You need to add one attribute in VF page components:
<apex:commandLink value="Add Class Enrollment" action="{!addClassEnrollments}" reRender="classId" immediate="true" />
<apex:commandLink value="Remove" action="{!removeClassEnrollment}" reRender="classId" immediate="true">
To deploy VF Page and its extension to Production Org you need to create Change Set and add those component to it. Also you need to have test class for the extension(ClassEnrollmentsExtensions.cls). I can help you in writing test class for the extension.
Thanks
Please provide me details regarding objects: Session__c and Class_Enrollment__c (Details related to fields of both the objects).
Thanks
Thank you so much! The addition worked for the VF page. What is the best way to share the details with you? Both objects have a lot of fields. Not all of the fields are used for the particular record types this button will be used with. The class enrollments object has 30 fields and the session has 45+. Is there a way to grant login access to a sandbox? Or should I do a screenshot of the fields? Let me know what works best! Sorry for the delay in responding, but I will respond to your reply by tomorrow :)
Please provide me the field names of Session__c and Class_Enrollment__c which are required and are also used in this functionality.
Thanks
Session
Record Type, RecordTypeId(0120f000001QfBhAAK)*
Session Number, Name
Master-Detail Relationship with Groups and Classes:
Group_Class__c*
Date: Start_Date__c
Date: End_Date__c
Number: Length_of_Class_es__c
Number: Number_of_Sessions_Held__c
Lookup to Accounts: Class_Location__c
Lookup to Users: Facilitator__c*
Lookup to Contacts: Youth_Leader__c
Lookup to Users: Co_Facilitator__c
Multi-Select Picklist: Works_Wonders_Module_s__c*
Checkbox: Peer_Component_Offered__c
Number: Length_of_Peer_Component_Minutes__c
Checkbox: Educational_Component_Offered__c
Number:
Length_of_Education_Component_Minutes__c
Long Text Area:
Anything_to_pay_closer_attention_to__c
Long Text Area:
Anything_you_want_to_learn_more_about__c
Long Text Area:
Any_Youth_Feedback__c
Long Text Area: Specific_Example_of_Challenge__c
Long Text Area: What_happened_you_felt_good_about__c
Long Text Area: Which_exercises__c
Class Enrollments
Class Enrollments Number, Name*
Record Type, RecordTypeId(01IG00000028DLM)
Master-Detail with Session, Session__c*
Master-Detail with Contact, Youth_Name__c*
Lookup with Works_Wonders__c: Works_Wonders_Youth_Name__c*
Picklist: Attendance__c*
Text Area: If_Youth_Did_Not_Attend_Explain_Why__c
Currency: Incentive_Paid__c
Text Area: Participation_Note__c
Checkbox: Youth_Has_Completed_This_Group__c
I'm sharing a sample test class here. You just have to add those fields which are required while creating test data.
ClassEnrollmentExtensionsTest
@isTest
public with sharing class ClassEnrollmentExtensionsTest {
@testSetup static void testDataCreation() {
Session__c session = new Session__c();
session.Session_Email__c = 'abc@gmail.com';
session.Name = 'Test Session';
//Add your Session__c object's fields here.
Database.insert(session);
}
@isTest static void testAddRemoveFunctionality(){
List<Session__c> sessions = [SELECT Id FROM Session__c];
PageReference page = Page.ClassEnrollmentPage;
page.getParameters().put('parentid', sessions[0].Id);
page.getParameters().put('recordtypeId', '0120f000001QfBc');
page.getParameters().put('ceIndex', '0');
page.setRedirect(true);
Test.setCurrentPage(page);
ClassEnrollmentExtensions classEnrollment = new ClassEnrollmentExtensions();
classEnrollment.addClassEnrollment();
classEnrollment.addClassEnrollment();
classEnrollment.removeClassEnrollment();
System.assertEquals(false, classEnrollment.ceRecord.isEmpty(), 'List has no elements in it');
}
@isTest static void testSaveCancelFunctionality(){
List<Session__c> sessions = [SELECT Id FROM Session__c];
Class_Enrollment__c classEnrollment = new Class_Enrollment__c();
classEnrollment.Session__c = sessions[0].Id;
classEnrollment.Name = 'Test CE';
classEnrollment.Notes__c = 'Test Content';
//Add your Class_Enrollment__c object's fields here.
PageReference page = Page.ClassEnrollmentPage;
page.getParameters().put('parentid', sessions[0].Id);
page.getParameters().put('recordtypeId', '0122v000001OBkJAAW');
page.getParameters().put('ceIndex', '0');
page.setRedirect(true);
Test.setCurrentPage(page);
ClassEnrollmentExtensions extension = new ClassEnrollmentExtensions();
extension.ceRecord.add(classEnrollment);
PageReference resultPage = extension.save();
PageReference returnPage = extension.cancel();
System.assertNotEquals(null, resultPage, 'Invalid Page returned');
System.assertNotEquals(null, returnPage, 'Invalid Page returned');
}
}
Also while creating test test I noticed that we are not using StandardController functionality anywhere. You need make some small changes in page and controller:
1. <apex:page controller="ClassEnrollmentExtensions">
2. public ClassEnrollmentExtensions() {
//Constructor body
}
Also you can rename the class ClassEnrollmentExtensions to ClassEnrollmentController.
Thanks
I tried to add the fields as you specified in the test class, though I imagine my formatting could be wrong...I'm not sure for lookup or master-detail relationships if I can use Name or if I need to use ID.
However, I am getting this error:
Error: Compile Error: Constructor not defined: [ClassEnrollmentController].<Constructor>() at line 17 column 53
Below is my updated test class:
@isTest
public with sharing class ClassEnrollmentControllerTest {
@testSetup static void testDataCreation() {
Session__c session = new Session__c();
session.Group_Class__c = 'Works Wonders';
session.Facilitator__c = 'Blair Burnette';
Database.insert(session);
}
@isTest static void testAddRemoveFunctionality(){
List<Session__c> sessions = [SELECT Id FROM Session__c];
PageReference page = Page.Class_Enrollments_VF;
page.getParameters().put('parentid', sessions[0].Id);
page.getParameters().put('recordtypeId', '0120f000001QfBc');
page.getParameters().put('ceIndex', '0');
page.setRedirect(true);
Test.setCurrentPage(page);
ClassEnrollmentController classEnrollment = new ClassEnrollmentController();
classEnrollment.addClassEnrollment();
classEnrollment.addClassEnrollment();
classEnrollment.removeClassEnrollment();
System.assertEquals(false, classEnrollment.ceRecord.isEmpty(), 'List has no elements in it');
}
@isTest static void testSaveCancelFunctionality(){
List<Session__c> sessions = [SELECT Id FROM Session__c];
Class_Enrollment__c classEnrollment = new Class_Enrollment__c();
classEnrollment.Session__c = sessions[0].Id;
classEnrollment.Name = 'Test CE';
classEnrollment.Notes__c = 'Test Content';
classEnrollment.Notes__c =
classEnrollment.Youth_Name__c = 'Test Test';
classEnrollment.Works_Wonders_Youth_Name__c = 'Test Test';
classEnrollment.Attendance__c = 'Attended';
PageReference page = Page.Class_Enrollments_VF;
page.getParameters().put('parentid', sessions[0].Id);
page.getParameters().put('recordtypeId', '0122v000001OBkJAAW');
page.getParameters().put('ceIndex', '0');
page.setRedirect(true);
Test.setCurrentPage(page);
ClassEnrollmentController extension = new ClassEnrollmentController();
extension.ceRecord.add(classEnrollment);
PageReference resultPage = extension.save();
PageReference returnPage = extension.cancel();
System.assertNotEquals(null, resultPage, 'Invalid Page returned');
System.assertNotEquals(null, returnPage, 'Invalid Page returned');
}
}
- While setting value for lookup or MD relationship field use ID of that object.
- Actually I mentioned earlier that you have to modify your constructor of Controller class as well:
Earlier it was:
public ClassEnrollmentsController(ApexPages.StandardController controller){
//Contructor Body
}
After modification:
public ClassEnrollmentController() {
//Contructor Body
}
Thanks
When I go to Apex Test Execution, I don't see the test class listed. However, it does show in the Test History if I click the "Run Test" button on the class itself.
I've noticed that the SaveCancel Functionality failed. I can't figure out how to see more details of the Debug log to see what failed.
Here is that piece of code:
@isTest static void testSaveCancelFunctionality(){
List<Session__c> sessions = [SELECT Id FROM Session__c];
Class_Enrollments__c classEnrollment = new Class_Enrollments__c();
classEnrollment.Session__c = sessions[0].Id;
classEnrollment.Youth_Name__c = '0033C00000C9hK1QAJ';
classEnrollment.Works_Wonders_Youth_Name__c = 'a5b3C000000ClmlQAC';
classEnrollment.Attendance__c = 'Attended';
PageReference page = Page.Class_Enrollments_VF;
page.getParameters().put('parentid', sessions[0].Id);
page.getParameters().put('recordtypeId', '0122v000001OBkJAAW');
page.getParameters().put('ceIndex', '0');
page.setRedirect(true);
Test.setCurrentPage(page);
ClassEnrollmentController extension = new ClassEnrollmentController();
extension.ceRecord.add(classEnrollment);
PageReference resultPage = extension.save();
PageReference returnPage = extension.cancel();
System.assertNotEquals(null, resultPage, 'Invalid Page returned');
System.assertNotEquals(null, returnPage, 'Invalid Page returned');
}
}
Any ideas what might be wrong? Or how do I access this information? I can't see any more details when I go to Test History or Debug logs. I am guessing maybe I have some formatting of the field names wrong, but I'm not sure. I am sorry to keep bugging you! I've never done these tests before, so I'm scrambling to learn quickly :)