1

I have a requirement where I have to display fields on visualforce page and then whatever user enters into those fields, fetch them and create a record out of it. I am able to do that one time but I want to display an actionLink at the bottom of the page that says "Add an additional record". When user clicks that link/button, it displays those fields again and then again another record gets created in apex class out of those values. Again the actionLink appears asking user if they want to create another record. This should keep on going. Any idea how can I make this work? I guess apex:repeat might be used but I am not sure how can I make it work in my case.

Here is my visualforce code:

  <div id="Arrest" style="display:none;" class="slds-box slds-m-bottom_xx-small">

                    <apex:outputLabel style="color:red;" value="* " />
                    <apex:outputtext style="border:1px;" value="What exactly happened in your own words?"/>
                    <br></br>
                    <apex:inputTextarea style="width:40%;" value="{!What_Happened}"/>


                    <br></br>
                    <br></br>
                    <apex:outputLabel style="color:red;" value="* " />
                    <apex:outputtext style="border:1px;" value="When did this happen?"/>
                    <br></br>
                    <apex:inputTextarea style="width:40%;" value="{!Happened_When}"/> 


                    <br></br>
                    <br></br>
                    <apex:outputLabel style="color:red;" value="* " />
                    <apex:outputtext style="border:1px;" value="Where did this happen?"/>
                    <br></br>
                    <apex:inputTextarea style="width:40%;" value="{!Happened_Where}"/> 



                    <br></br>
                    <br></br>
                    <apex:outputtext style="border:1px;" value="Do you realize that underage drinking is against the Policy?"/>
                    <br></br>
                    <apex:selectList value="{!RealizeAgainstPolicyId}" style="width:40%;" size="1"> 

                       <apex:selectOptions value="{!RealizeAgainstPolicy}"/>  

                    </apex:selectList> 



                    <apex:commandButton id="Save" styleClass="slds-button slds-button--neutral btn-lg" value="Save" action="{!saveAndContinue}"/>    




                 </div>

 <apex:commandLink onclick="send()" value="Add another record" id="Addanother"/>

Here is my apex class:

public String What_Happened{get;set;}
public String Happened_When{get;set;}
public String Happened_Where{get;set;}
public String Thought_Process_At_the_Time{get;set;}
public String RealizeAgainstPolicyId { get;set; }
 public List<SelectOption> RealizeAgainstPolicy{

  get

    {

        //Alcohol_Involved = new List<SelectOption>();
        List<Selectoption> AgainstThePolicy = new List<selectoption>();
        AgainstThePolicy.add(new selectOption('', '--None--'));
        AgainstThePolicy.add(new selectoption('Y', 'Yes'));
        AgainstThePolicy.add(new selectoption('N', 'No'));

        return AgainstThePolicy; 

     }

   set {}


  }



public pagereference saveAndContinue() {





      try {




               // Add a contact to this account.

               Application__c application = new Application__c (

                     .........

                     What_Happened__c=What_Happened,

                     Happened_When__c=Happened_When,

                     Happened_Where__c=Happened_Where,

                     Thought_Process_At_the_Time__c= Thought_Process_At_the_Time,



                     Realize_Against_Policy__c= RealizeAgainstPolicyId,







                      );


               insert application;

           } catch(DmlException e) {

                  System.debug('An unexpected error has occurred: ' + e.getMessage());

              }        

      ...................
      ...................
      ...................



      }
  • Do you need all the items to be displayed on the same page, and saved together? Or is the "Save & New" behavior fitting for your use case (save the first record then reset the page to add a second)? – battery.cord Aug 6 '18 at 15:00
  • @battery.cord whatever is easier. – Student Aug 6 '18 at 16:58
  • Follow up question - is there any reason why you have you values for Realize_Against_Policy__c as a SelectList, instead of an apex:inputField? – battery.cord Aug 6 '18 at 17:31
  • yes because I am temporarily creating a picklist field with some values to display on the page rather than displaying the actual field that exists in Salesforce. Similarly, all other fields are temporary. Once the user enters values in those fields, then I grab the data, copy them into salesforce fields and create a record out of it in apex class. (Refer Saveandcontinue method in apex class) – Student Aug 6 '18 at 17:36
  • So before user provides the information on the visualforce page, there is no application record created in Salesforce. My task is to allow user to create as many records as user wants by clicking "Add additional record" and since I don't have any record in Salesforce already, I am displaying my own created temporary fields on visualforce page so that user could enter the information there and then I could create a record out of it. I hope this makes sense to you. – Student Aug 6 '18 at 17:43
1

So, you could keep your fields as individual variables, and then create a record in the save method, but you don't really gain a lot by doing this (in this case). A good use case for non apex:inputField inputs would be if you needed to create a custom list, based on some case (such as a user list, or a list of related accounts/records). Instead, I'd recommend using a single variable, of the type of your record, and binding its fields directly to the inputs.

What it looks like you're doing is creating a visualforce edit page for a record. You can mimic the standard "Save & New" behavior here pretty easily, and save yourself from having to worry about juggling a list of records on a page.

DemoController

public DemoController {

    public Account Record { get; set; } // our variable 

    public DemoController() {
        Record = new Account(); // initial state 
    }

    public PageReference Save() {
        insert Record;

        return new PageReference('/' + Record.Id); // redirect to saved record 
    }

    public PageReference SaveAndNew() {
        insert Record; 

        Record = new Account(); // reset record  

        return null; // reset page 
    }

}

DemoPage

<apex:page controller="DemoController">
    <apex:pageBlock>

        <apex:pageBlockButtons>
            <apex:commandButton action="{!Save}" value="Save" />
            <apex:commandButton action="{!SaveAndNew}" value="Save & New" />
        </apex:pageBlockButtons>

        <apex:pageBlockSection>
            <!-- Bound to our variables field -->
            <apex:inputField value="{!Record.Name}" />
        </apex:pageBlockSection>
    </apex:pageBlock>
</apex:page>

Conceptually, its pretty simple to have a list of records on a page, and save those records together. In practice, its a little tougher. The basic idea is to keep a list of records in your controller, and add/remove records from it based on the inputs from the page. This gets tougher due to the inputs on the page mixed with a bunch of re-rendering of those inputs. You need to set up the page just right in order to keep the data in your list, while rerendering the page to add new records. This is where having a variable for each of the records fields won't work as well (unless you use some nested maps, but at that point you might as well use an sObject or Wrapper class). Using the list of records as our repeat, we can create as many rows as we need, to create as many fields, and store as much data as we need (there is a limit, based on the page state, Id do some testing & figure out a limit for the page's record count).

Dummy_Controller

public class Dummy_Controller {

    public List<Account> Records { get; set; } // our variable 

    public Dummy_Controller() {
        Records = new List<Account>(); // initial state 
        Records.add(new Account()); // initial record 
    }

    public PageReference Save() {
        insert Records; // save all records 

        return new PageReference('/' + Records[0].Id); // redirect to saved record 
    }

    public PageReference AddNew() {
        Records.add(new Account()); // add another record 

        return null; 
    }

}

DummyPage

<apex:page controller="Dummy_Controller">
    <Apex:form>
        <apex:pageBlock>
            <apex:pageBlockButtons>
                <apex:commandButton action="{!Save}" value="Save" />
                <!-- Has to be immediate - otherwise the form tries to "submit" and triggers built in validation --> 
                <apex:commandButton action="{!AddNew}" value="Add New" immediate="true" />
            </apex:pageBlockButtons>

            <!-- Repeat for each record, create a "row" where we can put inputs --> 
            <apex:repeat var="record" value="{!Records}">
                <!-- wrap each record with an actionRegion - ensures the fields are submitted when adding new rows --> 
                <apex:actionRegion>
                    <apex:pageBlockSection>
                            <apex:inputField value="{!Record.Name}"  />
                    </apex:pageBlockSection>
                </apex:actionRegion>
            </apex:repeat>
        </apex:pageBlock>
    </Apex:form>
</apex:page>
  • Thanks for doing all this. So from what I understood it seems like you create an empty record first and then ask user to fill out the fields inside it. After it gets saved and user clicks 'Add an additional record' you create another empty record and again user enter the information for second record and it keeps on going. Correct? Also, I will try this sometime today and let you know what I found. Thanks again. – Student Aug 6 '18 at 18:32
  • I tried to implement the above code and realized that I am missing the master-record id field "student_form__c". I am inserting the records in the above code as related list to studentform object. I have already fetched the studentformid from url in apex class constructor like this Id StudentFormId = ApexPages.currentPage().getParameters().get('id'); Now I want to assign this fetched id to student_form__c field while inserting all the records. Please help. – Student Aug 7 '18 at 21:23
  • I tried doing this in apex class save method. Records.student_form__c=StudentFormId; insert Records; But it gave me the following error Error: Compile Error: Variable does not exist: student_form__c I have already double checked that I have spelled the field name right. – Student Aug 7 '18 at 21:25
  • Yeah thats a pretty sub-par error message. You're trying to set a field on a list of records, but you've written it like the list is a single instance (Record.Field = Id). You need to iterate over your records and set each instance contained in the list separately. (for(sObject record:records) { record.Field = Id; }). Just seems like a confusing message to get for a simple problem. – battery.cord Aug 8 '18 at 14:00
  • Thanks for the help. I tried iterating, populating the master-detail id field and then run insert Records command. Now it gives me error on clicking save button that the master-detail field is not writable. Is there any other way to do it? – Student Aug 8 '18 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.