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
cc_crmcc_crm 

Passing parent id to child record in VisualForce page

I'm attempting to create my first VF page. It is a line-item entry form that will allow a user to enter multiple child records (Lit_Order_Detail__c) before clicking save. Right now, I'm opening the VF page from a custom button on the parent (Lit_Order__c). However, when the page opens, the lookup field for the parent is not populated - so the user has to click the lookup to select the parent from Lit_Order__c. Is there a way to pass the parent id of the previous page to the new child records on the VF page?

 

My Visualforce page:

 

 

<apex:page standardController="Lit_Order_Detail__c" extensions="OrderEntry"> <apex:form > <apex:pageBlock title="Sales Literature Orders Quick Entry" > <apex:pageBlockButtons > <apex:commandButton value="Save" action="{!save}" rerender="error" /> </apex:pageBlockButtons> <apex:pageBlockTable value="{!ords}" var="a" id="table"> <apex:column headerValue="Order ID"> <apex:inputField value="{!a.Lit_Order__c}"/> </apex:column> <apex:column headerValue="Order Detail ID"> <apex:inputField value="{!a.Name}"/> </apex:column> <apex:column headerValue="Request"> <apex:inputField value="{!a.Literature_Request__c}"/> </apex:column> <apex:column headerValue="Quantity"> <apex:inputField value="{!a.Quantity__c}"/> </apex:column> </apex:pageBlockTable> <apex:pageblockButtons location="bottom"> <div style="text-align:right;margin-right:30px;font-weight:bold;"> <apex:commandLink value="Add Row" action="{!addRow}" rerender="table,error" immediate="true" /> &nbsp;|&nbsp;&nbsp; <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="table,error" immediate="true" /> </div> </apex:pageblockButtons> </apex:pageBlock> </apex:form> </apex:page>

 

 

 

 

My Apex class:

 

 

public class OrderEntry { public List<Lit_Order_Detail__c> ords {get; set;} public OrderEntry(ApexPages.StandardController myController) { ords = new List<Lit_Order_Detail__c>(); ords.add(New Lit_Order_Detail__c());} public void addrow() { ords.add(new Lit_Order_Detail__c());} public void removerow(){ Integer i = ords.size(); ords.remove(i-1);} public PageReference save() { insert ords; PageReference home = new PageReference('/home/home.jsp'); home.setRedirect(true); return home; }}

 

Thank you!

 

 

Best Answer chosen by Admin (Salesforce Developers) 
JimRaeJimRae

Sorry about that, missed that part.  I would say you don't even need to display the id of the parent, since the user won't be interested in seeing a 15 digit string anyway.

 

What you will need to do is to set it when you create the child object records in the custom controller.

 

 

<apex:page standardController="Lit_Order__c" extensions="OrderEntry"> <apex:form > <apex:pageBlock title="Sales Literature Orders Quick Entry" > <apex:pageBlockButtons > <apex:commandButton value="Save" action="{!save}" rerender="error" /> </apex:pageBlockButtons> <apex:pageBlockTable value="{!ords}" var="a" id="table"> <apex:column headerValue="Order Detail ID"> <apex:inputField value="{!a.Name}"/> </apex:column> <apex:column headerValue="Request"> <apex:inputField value="{!a.Literature_Request__c}"/> </apex:column> <apex:column headerValue="Quantity"> <apex:inputField value="{!a.Quantity__c}"/> </apex:column> </apex:pageBlockTable> <apex:pageblockButtons location="bottom"> <div style="text-align:right;margin-right:30px;font-weight:bold;"> <apex:commandLink value="Add Row" action="{!addRow}" rerender="table,error" immediate="true" /> &nbsp;|&nbsp;&nbsp; <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="table,error" immediate="true" /> </div> </apex:pageblockButtons> </apex:pageBlock> </apex:form> </apex:page>

 

 

public class OrderEntry { public List<Lit_Order_Detail__c> ords {get; set;} private final Lit_Order__c parOrd; public OrderEntry(ApexPages.StandardController myController) { parOrd=(Lit_Order__c)myController.getrecord(); ords = new List<Lit_Order_Detail__c>(); Lit_Order_Detail__c LitOrd = new Lit_Order_Detail__c(); LitOrd.Lit_Order__c = parOrd.id; ords.add(LitOrd);} public void addrow() { Lit_Order_Detail__c LitOrd = new Lit_Order_Detail__c(); LitOrd.Lit_Order__c = parOrd.id; ords.add(LitOrd);} public void removerow(){ Integer i = ords.size(); ords.remove(i-1);} public PageReference save() { insert ords; PageReference home = new PageReference('/home/home.jsp'); home.setRedirect(true); return home; }}

 Hopefully, this will get you close.

 

 

 

All Answers

JimRaeJimRae

I would suggest using the controller of the parent object as the stanard controller, then you can get the id automatically without passing it as a parameter.

 

 

<apex:page standardController="Lit_Order__c" extensions="OrderEntry"> <apex:form > <apex:pageBlock title="Sales Literature Orders Quick Entry" > <apex:pageBlockButtons > <apex:commandButton value="Save" action="{!save}" rerender="error" /> </apex:pageBlockButtons> <apex:pageBlockTable value="{!ords}" var="a" id="table"> <apex:column headerValue="Order ID"> <apex:inputField value="{!Lit_Order__c.id}"/> </apex:column> <apex:column headerValue="Order Detail ID"> <apex:inputField value="{!a.Name}"/> </apex:column> <apex:column headerValue="Request"> <apex:inputField value="{!a.Literature_Request__c}"/> </apex:column> <apex:column headerValue="Quantity"> <apex:inputField value="{!a.Quantity__c}"/> </apex:column> </apex:pageBlockTable> <apex:pageblockButtons location="bottom"> <div style="text-align:right;margin-right:30px;font-weight:bold;"> <apex:commandLink value="Add Row" action="{!addRow}" rerender="table,error" immediate="true" /> &nbsp;|&nbsp;&nbsp; <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="table,error" immediate="true" /> </div> </apex:pageblockButtons> </apex:pageBlock> </apex:form> </apex:page>

 

 if you need the parent in the controller (doesn't appear you do), you can use the getrecord call to pull it in.   this would be good if you were doing any validation, or if you wanted to present some specific filtered data related to the parent.

 

 

public class OrderEntry { public List<Lit_Order_Detail__c> ords {get; set;} private final Lit_Order__c parOrd; public OrderEntry(ApexPages.StandardController myController) { parOrd=(Lit_Order__c)myController.getrecord(); ords = new List<Lit_Order_Detail__c>(); ords.add(New Lit_Order_Detail__c());} public void addrow() { ords.add(new Lit_Order_Detail__c());} public void removerow(){ Integer i = ords.size(); ords.remove(i-1);} public PageReference save() { insert ords; PageReference home = new PageReference('/home/home.jsp'); home.setRedirect(true); return home; }}

 

 

 

 

cc_crmcc_crm

Thank you for your help. It's much closer, but I still have a problem: I get an error on save because the Lit_Order__c field is missing on the child records. Is there something else I need to do to actually set the value on the child records?

 

Thanks in advance - I realize that I'm probably asking pretty basic questions.

 

Partial VF page code (full code in previous posts):

 

<apex:pageBlockTable value="{!ords}" var="a" id="table"> <apex:column headerValue="Order ID"> <apex:inputField value="{!Lit_Order__c.id}"/> </apex:column> <apex:column headerValue="Order Detail ID"> <apex:inputField value="{!a.Name}"/> </apex:column> <apex:column headerValue="Request"> <apex:inputField value="{!a.Literature_Request__c}"/> </apex:column> <apex:column headerValue="Quantity"> <apex:inputField value="{!a.Quantity__c}"/> </apex:column> </apex:pageBlockTable>

 

JimRaeJimRae

Sorry about that, missed that part.  I would say you don't even need to display the id of the parent, since the user won't be interested in seeing a 15 digit string anyway.

 

What you will need to do is to set it when you create the child object records in the custom controller.

 

 

<apex:page standardController="Lit_Order__c" extensions="OrderEntry"> <apex:form > <apex:pageBlock title="Sales Literature Orders Quick Entry" > <apex:pageBlockButtons > <apex:commandButton value="Save" action="{!save}" rerender="error" /> </apex:pageBlockButtons> <apex:pageBlockTable value="{!ords}" var="a" id="table"> <apex:column headerValue="Order Detail ID"> <apex:inputField value="{!a.Name}"/> </apex:column> <apex:column headerValue="Request"> <apex:inputField value="{!a.Literature_Request__c}"/> </apex:column> <apex:column headerValue="Quantity"> <apex:inputField value="{!a.Quantity__c}"/> </apex:column> </apex:pageBlockTable> <apex:pageblockButtons location="bottom"> <div style="text-align:right;margin-right:30px;font-weight:bold;"> <apex:commandLink value="Add Row" action="{!addRow}" rerender="table,error" immediate="true" /> &nbsp;|&nbsp;&nbsp; <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="table,error" immediate="true" /> </div> </apex:pageblockButtons> </apex:pageBlock> </apex:form> </apex:page>

 

 

public class OrderEntry { public List<Lit_Order_Detail__c> ords {get; set;} private final Lit_Order__c parOrd; public OrderEntry(ApexPages.StandardController myController) { parOrd=(Lit_Order__c)myController.getrecord(); ords = new List<Lit_Order_Detail__c>(); Lit_Order_Detail__c LitOrd = new Lit_Order_Detail__c(); LitOrd.Lit_Order__c = parOrd.id; ords.add(LitOrd);} public void addrow() { Lit_Order_Detail__c LitOrd = new Lit_Order_Detail__c(); LitOrd.Lit_Order__c = parOrd.id; ords.add(LitOrd);} public void removerow(){ Integer i = ords.size(); ords.remove(i-1);} public PageReference save() { insert ords; PageReference home = new PageReference('/home/home.jsp'); home.setRedirect(true); return home; }}

 Hopefully, this will get you close.

 

 

 

This was selected as the best answer
JAW99JAW99

JIMRAE thanks for this, I adopted it to my own custom objects and was able to mod. One issue - on save, it brings me to the Home, not back to the record I wanted to add child records to.

Can you assist? thanks. To my beginner eyes it looks like the last section with return home in there but rewriting it is still challenge for me.

Message Edited by JAW99 on 11-04-2009 01:07 PM
JAW99JAW99
Also, am having trouble re wirting the apex for task. the What field doesn't want to take the custom object id. thanks again!
JimRaeJimRae

JAW99 wrote:

JIMRAE thanks for this, I adopted it to my own custom objects and was able to mod. One issue - on save, it brings me to the Home, not back to the record I wanted to add child records to.

Can you assist? thanks. To my beginner eyes it looks like the last section with return home in there but rewriting it is still challenge for me.

Message Edited by JAW99 on 11-04-2009 01:07 PM

To get have the return bring you to the parent record, you modify your page reference to point back to the parent record id.

For the original example, it would look like this:

 

public class OrderEntry { public List<Lit_Order_Detail__c> ords {get; set;} private final Lit_Order__c parOrd; public OrderEntry(ApexPages.StandardController myController) { parOrd=(Lit_Order__c)myController.getrecord(); ords = new List<Lit_Order_Detail__c>(); Lit_Order_Detail__c LitOrd = new Lit_Order_Detail__c(); LitOrd.Lit_Order__c = parOrd.id; ords.add(LitOrd);} public void addrow() { Lit_Order_Detail__c LitOrd = new Lit_Order_Detail__c(); LitOrd.Lit_Order__c = parOrd.id; ords.add(LitOrd);} public void removerow(){ Integer i = ords.size(); ords.remove(i-1);} public PageReference save() { insert ords; //PageReference home = new PageReference('/home/home.jsp'); //home.setRedirect(true); //return home; }} PageReference parrec = new PageReference('/'+parOrd.id); parrec.setRedirect(true); return parrec; }}

 

 

 

JimRaeJimRae

JAW99 wrote:
Also, am having trouble re wirting the apex for task. the What field doesn't want to take the custom object id. thanks again!

You mean the whatid field, correct?  Could you post your code?

JAW99JAW99

Thanks for the help on the page return!

I figured out the issue on the VF pages for what ID and WhoID for tasks so am just cleaning up the appearance.

 

Is there a way I can have the row of entry fields have multiple rows?Since I want to make the page foradding multiple tasks the description/comments field is in display and it would be great to be able make it nice and wide, below the other shorter fields like subject, contact.

JimRaeJimRae

I am not sure if you could do that or not.  One issue would be the column headers.  The 2 iterators for records are the datatable and the pageblocktable, and they both use a one record per row model.  You might  be able to do it with custom styling, but I am not sure what you would do.


JAW99JAW99

OK, thanks, you've been very helpful.

For now I am shaping the comments input with an inputTextarea that will just be narrower and longer down the page than usual.

JAW99JAW99

Ah, one more question:

could i seta field value in the new task? I'd like for their status to be completed by default so they move into the history. ideally the status field won't even appear on the entry page. Will try a stab at it myself but am not quite sure where to begin... searching boards pulls up a lot of other topics

JAW99JAW99
also just noticed during testting that the add another row action clears out text entered in the description box. picklist choices and the subject free text are not lost in this reload...
JimRaeJimRae

Regarding setting the status of the new tasks, that shouldn't be a problem.  Actually, you should be able to set it when you construct the new Task in the controller.

 

 

public void addrow() { ords.add(new Task(Status='Completed'));}

 For your refresh question, hard to tell. I would expect the behavior to be that the rows would get cleared out on the rerender (which happens when you add a new row).  I would recommend training the users to add all of the rows they need first, then enter the data.  Or, if that doesn't meet your design requirements you would need to modify your controller to capture the values in place before the new row is added and then populate them out again, I don't have any samples for this.

 

 

 

JAW99JAW99

Thanks, I got the status passed ok.

Yeah, dunno about the clear out of comments. I hope that is something users will adapt to soon enough.

 

JAW99JAW99

I am trying to change the page to have 3 rows of tasks by default instead of the "add row" feature b/c of the way adding a row clears out subject and description text but the controller is working funny.

any attempt to use a look up on the lower rows just feeds the info into the first row. Any suggestions would be appreciated. thanks.

ForstaForsta

Does anyone have a test class for this? I have been able to adapt the code to support multiple line enter for a new custom Opportunity Competitors object (junction object between Opportunity and new Competitors object ) but I can't seem to get the necessary coverage and keep getting an error in my test class - System.QueryException: List has no rows for assignment to SObject. I am very new to apex and would appreciate any guidance. Thanks in advance.

 

Page

<apex:page extensions="OCMultiAdd2Ext" tabStyle="Opportunity" standardController="Opportunity">
    <apex:form >
      <apex:sectionheader title="Opportunity Competitors" subtitle="{!Opportunity.Name}" />
            <apex:pageBlock >
        <p>
          Add one or more Competitors for this Opportunity. You can find competitors by using the Competitor lookup
           or by typing a name in the Competitor field. Only available <a href="https://cs1.salesforce.com/a0S" target="_blank">
           Competitors</a> can be selected. Click Add Row to enter multiple records or Remove Row to delete rows.  
       </p>
       <p>
        Click Save to add all entered Competitors to the Opportunity. Click Cancel to return to the Opportunity 
        record without saving. All data entered will be lost if you click Cancel.
       </p>
        <br />
        <apex:pageMessages />
        
            <apex:pageBlockButtons location="bottom">
                <apex:commandButton value="Save" action="{!save}" />
                <apex:commandButton value="Cancel" action="{!cancel}" />
            </apex:pageBlockButtons>
        
             <apex:pageblocktable value="{!OppComp}" var="OC" Title="Opportunity Competitors" id="table">
                      
         <!-- prevent users changing the Opportunity -->
         <apex:column headervalue="Oppportunity" rendered="false">
            <apex:inputfield value="{!OC.Opportunity__c}" style="width:250px;" />
        </apex:column>
         
         <apex:column headervalue="Competitor" >
           <apex:inputfield value="{!OC.Competitor__c}" style="width:290px;" />
        </apex:column>
    
        <apex:column headervalue="Existing Installation?" >
             <apex:inputfield value="{!OC.Existing_Installation__c}" />
        </apex:column>

        <apex:column headervalue="Notes">
             <apex:inputfield value="{!OC.Notes__c}" style="width:820px;height:30px;" />
        </apex:column>
            </apex:pageBlockTable>
                      
              <div style="text-align:right;margin-right:10px;font-weight:bold;">       
                     <apex:commandLink value="Add Row" action="{!addRow}" rerender="table,error" immediate="true" /> &nbsp;|&nbsp;
                    <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="table,error" immediate="true" />   
        </div>
            
        </apex:pageBlock>
    </apex:form>
</apex:page>

 

 

 

Extension

public class OCMultiAdd2Ext{

    public List<Opportunity_Competitors__c> oppComp {get; set;}
    private final Opportunity opp;
    public OCMultiAdd2Ext(ApexPages.StandardController cstmController) {
        Opp=(Opportunity)cstmController.getrecord();
        oppComp = new List<Opportunity_Competitors__c>();
        Opportunity_Competitors__c OpptyComp = new Opportunity_Competitors__c();
        OpptyComp.Opportunity__c = opp.id;
        oppComp.add(OpptyComp);
        } 
    
    public void addrow(){
        Opportunity_Competitors__c OpptyComp = new Opportunity_Competitors__c();
        OpptyComp.Opportunity__c = opp.id;
        oppComp.add(OpptyComp);}
    
     public void removerow(){
        Integer i = oppComp.size();
        OppComp.remove(i-1);}
    
    public PageReference save(){
        
   //error handling //   
   try{
      insert OppComp;
    }
      catch(Exception e){
           ApexPages.addMessages(e);
       return null;
    }
      
     
    // redirect the user back to the Opportunity record //        
        PageReference opprec = new PageReference('/'+opp.id);
        opprec.setRedirect(true);
        return opprec;
    }
}

 

Test

@isTest
private class testOCMultiAdd2Ext{
      
       static testMethod void testOpportunityCloseExtOpp() {
          
       //Create an account //
        Account acc = new Account(name='test Account One1');
        acc.Type='Prospect';
        insert acc;
        
         // Create Products 
         Product2 testprod1 = new Product2 (name='test product one1');
         testprod1.productcode = 'test pd code1one';
         insert testprod1;
         
         // Get Pricebook
         Pricebook2 testpb = [select id from Pricebook2 where IsStandard = true];   

        // Add to pricebook
         PricebookEntry testpbe1 = new PricebookEntry ();
         testpbe1.pricebook2id = testpb.id;
         testpbe1.product2id = testprod1.id;
         testpbe1.IsActive = True;
         testpbe1.UnitPrice = 250;
         testpbe1.UseStandardPrice = false;
         insert testpbe1;
 
         //Create an Opp //
        Opportunity Opp = new Opportunity(name='test Oppty One1');
        opp.name='test opp';
        opp.AccountId=acc.Id;
        opp.closeDate=date.today();
        opp.StageName='Qualification';
        opp.Business_Type__c='New Logo';
        opp.Compiler__c='Unknown';
        opp.LOC__c='5M+';
        opp.Platform__c='Linux';
        opp.Purprose_of_Coverity_Evaluation_Pain_Poi__c='Reduce Cost';
        opp.Buying_Budgeting_process__c='Approved';
        opp.LeadSource='Sales';
        opp.Lead_Type__c='Sales Research';
        insert opp;          
 
        // Add to Opp 
        OpportunityLineItem oli1 = new OpportunityLineItem();
        oli1.Quantity = 1000;
        oli1.TotalPrice = 10;
        oli1.PricebookEntryId = testpbe1.id;
        oli1.OpportunityId = opp.id;    
        oli1.Term_M__c = 24;
        oli1.Fulfill_As__c = 'Unlocked';
        insert oli1;
 
        Competitor__c comp = new Competitor__c(Name='Competitor',Website__c='http://www.competitor.com');
        insert comp;
    
        List<Competitor__c> Comptr = [SELECT id from Competitor__c WHERE Id = :comp.id];
        List<Opportunity> oppList = [SELECT id from Opportunity WHERE Id = :opp.id];
    
        Opportunity_Competitors__c oppComp = new Opportunity_Competitors__c(Opportunity__c=opp.Id,Competitor__c=comp.Id,Notes__c='Price is a problem');
        insert oppComp;
        
        Test.startTest();
        PageReference pageRef = Page.OCMultiAdd2;
        Test.setCurrentPageReference(pageRef);
        
        /* Standard controller for the Opportunity */
        ApexPages.StandardController stdCon = new ApexPages.StandardController(opp);
        
        /*Construct the controller extension with the standard controller arg */
        OCMultiAdd2Ext Ext = new OCMultiAdd2Ext(stdCon);
        OpportunityCloseExt con = new OpportunityCloseExt(stdCon);
        PageReference oppPage = con.save();
        System.assert(oppPage != null);                  
        Test.stopTest();
        }
          
          
      
}

 

MoosecoutureMoosecouture

I would much rather just know how to test the already existing data that is out there.  No need to take this topic off in a new direction.  I can custom fit it to my standard.  Later.  Does anybody have a Testing Class for this as I am unsure how to test List Items.