Part1: The rough working prototype
Done miss to use the Beta Demo on dev org

Dear awesome readers,

This post is a continuation to a series of posts. If you missed, the previous post can be found at https://salesforcemann.wordpress.com/2016/11/11/pet-project-create-parent-and-child-records-from-visualforce-page-for-any-salesforce-object-part-0/

In this post, I will publish some screenshots and the code to a working prototype. The code has all the comments to understand the workings.
I have also used some basic Bootstrap CSS to the VF help me make the look and feel a bit fancier than the SF default.

You are free to use this code and do not hesitate to get back in touch if necessary.

Some screenshots for the code in action:

The controller:

public with sharing class pnc_v3 {

    public Map<String, Schema.SObjectType> gd_map_full;
    public Map<String, Schema.SObjectType> gd;
    public Map<String, Schema.SObjectType> child_describe;

    public sobject object_1{get;set;}   //sobject for parent
    public List<sobject> object_2{get;set;} //sobject for child

    public String display_parent{get;set;} // these are used to render the tabs
    public String display_child{get;set;}
    public Integer noOfChildren{get;set;} //number of children
    public String showParentSave{get;set;}
    public String showChildSave{get;set;}
    public String parentURL{get;set;}
    public List<String> childURL{get;set;}
    public String whichTab{get;set;}

    public List<String> parent_field{get;set;} // parent fields to display
    public List<String> child_field{get;set;}

    public String parent_sl{get;set;}  //selectlist
    public List<selectOption> parent_so{get;set;} //selectoption
    public String child_sl{get;set;}  //selectlist
    public List<selectOption> child_so{get;set;} //selectoption    

    public pnc_v3() {
        display_parent = 'false';
        display_child = 'false';
        showParentSave = 'true';
        showChildSave = 'true';
        whichTab = 'tab1';

        //display sucess message if it is a redirect
        system.debug('ApexPages.currentPage().getParameters().get ='+ApexPages.currentPage().getParameters().get('message'));
        if(ApexPages.currentPage().getParameters().get('message') != null) {
            ApexPAges.addMessage(new ApexPages.message(ApexPages.Severity.CONFIRM,ApexPages.currentPage().getParameters().get('message')));
        }
        if(ApexPages.currentPage().getParameters().get('error') != null) {
            ApexPAges.addMessage(new ApexPages.message(ApexPages.Severity.FATAL,ApexPages.currentPage().getParameters().get('error')));
        }

        renderParent_so();
    }
    public void renderParent_so() {  

        system.debug('entering renderParent_so');
        parent_so = new List<selectOption>(); //populate with object names
        parent_so.add(new SelectOption('None','None'));

        gd_map_full = Schema.getGlobalDescribe(); //get all object tokens

        gd = new Map<String, Schema.SObjectType>();
        for( String gd_string : gd_map_full.keyset()) { //add to gd only those objects that are creatable by user
            if(gd_map_full.get(gd_string).getDescribe().isCreateable()
              && gd_map_full.get(gd_string).getDescribe().isAccessible()
              && gd_map_full.get(gd_string).getDescribe().isQueryable()
              ) {
                gd.put(gd_string, gd_map_full.get(gd_string));
            }
        }		

        List<String> gd_key_lst = new List<String> (); 

        for (SObjectType s1: gd.values()) {
            gd_key_lst.add(s1.getDescribe().getName());
        }

        gd_key_lst.sort();
        for (String s1:gd_key_lst) {
            parent_so.add(new SelectOption(s1,s1));
        }
    }

    public void renderChild_so() {

        if(object_1.getSObjectType() != null) {
            child_so = new List<selectOption>();
            child_so.add(new SelectOption('None','None'));
            //system.debug('** inside renderchild = '+gd.get(parent_sl.toLowerCase()).getDescribe().getChildRelationships());
            child_describe = new Map<String, Schema.SObjectType>();
            for(ChildRelationship cr : gd.get(parent_sl.toLowerCase()).getDescribe().getChildRelationships()) {
                if (cr.getChildSObject().getDescribe().isCreateable()
                    && cr.getChildSObject().getDescribe().isAccessible()
                    && cr.getChildSObject().getDescribe().isQueryable()
                   ) {
                        child_so.add(new selectOption(cr.getChildSObject().getDescribe().getName(), cr.getChildSObject().getDescribe().getName()));
                        child_describe.put(cr.getChildSObject().getDescribe().getName(),cr.getChildSObject());
                   }

            }

        }

    }

    public void renderChildform() {
        if (child_sl != 'None') {
            //populate and display tab for child
			noOfChildren = 0;
            display_child = 'true';
            whichTab = 'tab2';

            system.debug('null testing child_sl= ' + child_sl);
            String s2 = child_sl.toLowerCase();
            system.debug('null testing s2= ' + s2);

			object_2 = new List<sObject>();
            object_2.add(child_describe.get(child_sl).newSobject());
            if(object_2[object_2.size()-1].getSObjectType().getDescribe().fields.getMap().containsKey('ownerID')) {
                object_2[object_2.size()-1].put('ownerId',system.UserInfo.getUserId());
            }

            for (String s3 : gd.get(s2).getDescribe().fields.getMap().keyset()) {
                for (SObjectType referenceTo : gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().getReferenceTo()) {
                    if (object_1.getSObjectType().getDescribe().getName() == referenceTo.getDescribe().getName()
                       && s3 != 'MasterRecordId' //special ID used in case of account. Dont populate it
                       ) {
                        //system.debug('### found parent ID field, populate it now');
                        //for (sobject so: object_2) {
                        object_2[object_2.size()-1].put(s3,object_1.get('Id'));
                        //system.debug('so = '+so);
                        //}
                    }
                }

            }

            system.debug('null testing s2=' + s2);
            child_field = new List<String>();
            system.debug('null is it? '+gd.get(s2).getDescribe().fields.getMap().keyset());
            for (String s3 :gd.get(s2).getDescribe().fields.getMap().keyset()) {
                //system.debug('renderChild() s3 = '+s3);
                if(gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isAccessible()
                  //&& gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isUpdateable() //commenting out since not showing master lookup field
                  && !gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isCalculated()
                  && gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isCreateable()

                  ) {
                      system.debug('field = '+s3+' '+gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isAccessible()+
                                  ' '+gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isUpdateable()+
                                   ' '+gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isCalculated()+
                                   ' '+gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isCreateable()
                                  );
                    child_field.add(s3); 

                }
            }
            //add_noOfChildren();
            noOfChildren = noOfChildren + 1;
        } else {
            display_child = 'false';
            noOfChildren = 0;
        }
    }

    public void add_noOfChildren() {
        noOfChildren = noOfChildren + 1;
        object_2.add(child_describe.get(child_sl).newSobject());
        if(object_2[object_2.size()-1].getSObjectType().getDescribe().fields.getMap().containsKey('ownerID')) {
            object_2[object_2.size()-1].put('ownerId',system.UserInfo.getUserId());
        }
        //noOfChildren.add(noOfChildren.size()+1);
    }

    public void remove_noOfChildren() {
        noOfChildren = noOfChildren - 1;
        object_2.remove(object_2.size()-1);
        //object_2.add(child_describe.get(child_sl).newSobject());
        //noOfChildren.add(noOfChildren.size()+1);
    }    

    public void renderParentform() {
        if (parent_sl != 'None') {
            display_parent = 'true';
            display_child = 'false';
            //noOfChildren.clear();
            noOfChildren = 0;

            system.debug('parent_sl='+parent_sl);
            String s2 = parent_sl.toLowerCase();

            object_1 = gd.get(s2).newSobject(); //create sobject for the selected object
            if(gd.get(s2).getDescribe().fields.getMap().containsKey('ownerID')) {
                object_1.put('ownerId',system.UserInfo.getUserId());
            }

            //get all fields for that object
            system.debug(gd.get(s2).getDescribe().fields.getMap().keyset());

            parent_field = new List<String>();
            for (String s3 :gd.get(s2).getDescribe().fields.getMap().keyset()) {

                if(gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isAccessible()
                  //&& gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isUpdateable()
                  && !gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isCalculated()
                  && gd.get(s2).getDescribe().fields.getMap().get(s3).getDescribe().isCreateable()

                  ) {

                    parent_field.add(s3); 

                }
            }
            renderChild_so();
        } else {
            child_so.clear();
            display_child = 'false';
            display_parent = 'false';
            noOfChildren = 0;
        }
        //populate and display tab for parent

    }

    public pageReference reset() {
        pageReference pr =  ApexPages.currentPage();
        system.debug('pr= '+pr);
        pr.setRedirect(true);
        return pr;

    }

    public void saveParent() {
        pageReference pr =  ApexPages.currentPage();
        if (parent_sl != 'None') {

            try {
                if (object_1.getSObjectType() != null) {
                    Database.upsert(object_1);
                    ApexPAges.addMessage(new ApexPages.message(ApexPages.Severity.CONFIRM,'Parent saved'));
                    parentURL = system.Url.getSalesforceBaseUrl().toExternalForm() + '/' + object_1.get('Id');
                    showParentSave = 'false';
                }
            }
            catch(DmlException e) {
                System.debug('The following exception has occurred: ' + e.getMessage());
                ApexPAges.addMessage(new ApexPages.message(ApexPages.Severity.FATAL,'Parent not saved. The following exception has occurred: ' + e.getMessage()));
                //pr.getParameters().put('error','Records not created, kindly contact support');
            }
        }

    }
    public void saveChild() {
        pageReference pr =  ApexPages.currentPage();
        if (parent_sl != 'None') {

            try {
                if (object_2.size() !=0) {
                    Database.insert(object_2);
                    ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.CONFIRM,'Child(ren) saved'));
                    childURL = new List<String>();
                    for (sobject object_2_c : object_2) {
                        system.debug('adding child url to list '+object_2_c.get('Id'));
                        childURL.add(system.Url.getSalesforceBaseUrl().toExternalForm() + '/' + object_2_c.get('Id'));
                    }

                    showChildSave = 'false';
                }

            }
            catch(DmlException e) {
                System.debug('The following exception has occurred: ' + e.getMessage());
                ApexPAges.addMessage(new ApexPages.message(ApexPages.Severity.FATAL,'Child(ren) not saved. The following exception has occurred: ' + e.getMessage()));
                //pr.getParameters().put('error','Records not created, kindly contact support');
            }

        }
    }
}

The VF page:

<apex:page controller="pnc_v3" showHeader="false" title="Parent and Child creator" standardStylesheets="true">
    <head>
        <!-- Latest compiled and minified CSS -->
        				<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>

        <!-- jQuery library -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
        
        <!-- Latest compiled JavaScript -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
    </head>
    <script>
    	j$ = jQuery.noConflict();

    
                function funcparentfieldtable() {
  														j$( ".parentfieldtable table" ).each(function() {
          												j$(this).addClass( "table table-hover table-condensed" );
        											});
                }
                                                 ;

    </script>

    <apex:form styleclass="container form-group" >
    <apex:pageBlock title="Parent and child object creator" >
        <!--apex:pageBlockSection title="pbsection"-->

            <apex:outputPanel id="id_output_panel">
                <apex:Messages html-class="alert alert-info"/>

                <apex:actionRegion >

                    <apex:pageBlockSection columns="1">

                        <apex:selectList styleClass="form-control" value="{!parent_sl}" size="1" label="Parent object" title="Parent object." id="id_parent_sl" disabled="{!IF(showParentSave = 'false','true','false')}">
                            <apex:selectOptions value="{!parent_so}"/>
                            <apex:actionSupport event="onchange" action="{!renderParentform}" reRender="id_output_panel" oncomplete="funcparentfieldtable();"/>

                        </apex:selectList>

                        <apex:selectList styleClass="form-control" value="{!child_sl}" size="1" label="Child object" title="Child object." id="id_child_sl" disabled="{!IF(showChildSave = 'true',IF(showParentSave = 'false','false',true),'true')}">
                            <apex:selectOptions value="{!child_so}"/>
                            <apex:actionSupport event="onchange" action="{!renderChildform}" reRender="id_output_panel" />
                        </apex:selectList>

                    </apex:pageBlockSection>

                    <apex:pageBlockSection columns="1">
                        <apex:outputText rendered="{!showParentSave}"><code>Link to parent record after creation will appear here</code></apex:outputText>
                        <apex:outputLink value="{!parentURL}" rendered="{!IF(showParentSave = 'false','true','false')}"><code>Open parent record &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {!parentURL}</code></apex:outputLink>
                        <apex:outputText rendered="{!showChildSave}"><code>Link to child record(s) after creation will appear here</code></apex:outputText>
                        <apex:variable value="{!1}" var="nthChild"/>
                        <apex:repeat value="{!childURL}" var="URL">
                            <apex:outputLink value="{!URL}" rendered="{!IF(showChildSave = 'false','true','false')}"><code>Open child record {!nthChild} &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {!URL}</code></apex:outputLink>
                            <apex:variable value="{!nthChild + 1}" var="nthChild"/>
                        </apex:repeat>
                    </apex:pageBlockSection>
<div align="center">
                        <apex:commandButton styleClass="btn-danger" value="Reset" action="{!reset}" immediate="true"                                              onclick="if(!confirm('Are you sure that you want to reset?')){return false;}"/></div>
</apex:actionRegion>

                <apex:actionRegion >

                    <apex:tabPanel  switchType="client" value="{!whichTab}">
                        <apex:tab name="tab1" label="Parent" rendered="{!display_parent}" >
<div class="parentfieldtable">
                            <apex:pageBlockSection columns="4"> 

                                <apex:repeat value="{!parent_field}" var="iterator">
                                    <apex:inputfield styleclass="form-group" value="{!object_1[iterator]}" rendered="{!showParentSave}"/>
                                    <apex:outputfield styleclass="form-group" value="{!object_1[iterator]}" rendered="{!IF(showParentSave = 'false','true','false')}"/>
                                </apex:repeat>

                            </apex:pageBlockSection></div>
<div align="center">
                                <apex:commandButton styleClass="btn-primary" value="Save Parent" action="{!saveParent}" rendered="{!showParentSave}" reRender="id_output_panel"/></div>
</apex:tab>
                        <apex:tab name="tab2" label="Child" rendered="{!IF(display_child = 'true',IF(showParentSave = 'false','true','false'),'false')}" >

                            <!--apex:commandButton value="Add Child" action="{!renderChild}" rendered="{!showChildSave}" reRender="id_output_panel" immediate="true"/-->
                            <apex:commandButton styleClass="btn-success" value="Add Child" action="{!add_noOfChildren}" rendered="{!showChildSave}" reRender="id_output_panel" immediate="true"/>
                            <apex:commandButton styleClass="btn-warning" value="Remove Child" action="{!remove_noOfChildren}" rendered="{!showChildSave}" reRender="id_output_panel" immediate="true"/>
                            <apex:outputText >Current number of child(ren) on this page: {!noOfChildren}</apex:outputText>
                            <apex:variable value="{!1}" var="nthChild"/>
                            <apex:repeat value="{!object_2}" var="object_child">
                                <apex:pageBlockSection columns="2" title="Child {!child_sl} {!nthChild}">
                                    <apex:variable value="{!nthChild + 1}" var="nthChild"/>
                                    <apex:repeat value="{!child_field}" var="iterator">
                                        <apex:inputfield value="{!object_child[iterator]}" rendered="{!showChildSave}"/>
                                        <apex:outputfield value="{!object_child[iterator]}" rendered="{!IF(showChildSave = 'false','true','false')}"/>
                                    </apex:repeat>
                                </apex:pageBlockSection>
                            </apex:repeat>
<div align="center">
                                <apex:commandButton styleClass="btn-primary" value="Save Child" action="{!saveChild}" rendered="{!showChildSave}" reRender="id_output_panel"/></div>
</apex:tab>
                    </apex:tabPanel>

                </apex:actionRegion>

            </apex:outputPanel>

    </apex:pageBlock>
    </apex:form>
</apex:page>

Happy coding folks!
Mann.

Advertisements