0

Resubmitting to make this clearer. I have a parent object Claims_Client_Risk_Assessment__c (CCRA) that calls a Visualforce component page using the object CCRA_LOB_NonStdAuto__c (LOB_NonStdAuto.) I'm having an issue when setting the Master Detail field on the component's supporting object from the parent done in the SaveTestInsert() method. I think there is a fundamental issue I'm missing. When I just save the CCRA parent object via stdController.save() the CCRA.id remains null. If I add upcert CCRA; before the save the CCRA.id is exposed and I am able to pass this CCRA.id and CCRA.Name to the component object.

Is there an alternative way to pass the parent id to a component? Short code snippets and Visualforce component below.

Parent Visualforce call to add component:

<apex:tab label="NonStdAuto" name="tabLOB2" id="tabLOB2" rendered="{!IF(CONTAINS(Claims_Client_Risk_Assessment__c.Lines_of_Business__c,'NonStdAuto'),"true","false")}" > 
<apex:outputPanel >
<c:PROD_CCRA_LOB_NonStdAuto LOB_NonStdAuto="{!LOB_NonStdAuto}" /> 
</apex:outputPanel>

Parent Controller: (short version.)

public class ClaimsClientRiskAssessmentController {
//Properties

   //Parent and components
   public Claims_Client_Risk_Assessment__c CCRA { get; set; }
   public CCRA_LOB_NonStdAuto__c LOB_NonStdAuto { get; set; }  

   //Protected Members
    private final ApexPages.StandardController stdController;

   //Constructor
    public ClaimsClientRiskAssessmentController(ApexPages.StandardController controller) {
        try {
         CCRA = new Claims_Client_Risk_Assessment__c();
         this.stdController = controller; 
         this.CCRA = (Claims_Client_Risk_Assessment__c) controller.getRecord();
         this.LOB_NonStdAuto = new CCRA_LOB_NonStdAuto__c();  //instatiate the LOB to receive parent ID                                        

         //build up LOB fields to pass to components.
         this.LOB_NonStdAuto = queryLOB_NonStdAuto(this.CCRA.Id); 

        catch (Exception ex) {
            ApexPages.addMessages(ex);
        }
    }  

//Public Methods        

//**********************************************************     
    Public Void SaveTestInsert() {
        try {
            upsert CCRA; 
            stdController.save();
            AttachLOB();
        } catch (Exception ex) {
            ApexPages.addMessages(ex);
        }
    }
//********************************************************** 

    Public void AttachLOB() {
    try {    
           LOB_NonStdAuto.Claims_Client_Risk_Assessment__c = CCRA.id;
           LOB_NonStdAuto.Name = CCRA.Name;
           Upsert LOB_NonStdAuto;
        } catch (Exception ex) {
            ApexPages.addMessages(ex);
        }    
    }

//**********************************************************
    public void getLOB_NonStdAuto() {    
        try {
            this.LOB_NonStdAuto = queryLOB_NonStdAuto(this.CCRA.Id);     
            } catch (Exception ex) {
            ApexPages.addMessages(ex);
            }        
        }

//**********************************************************************     
   // used to populate Viusalforce component with fields.

    Private CCRA_LOB_NonStdAuto__c queryLOB_NonStdAuto(Id CCRA_ID) {    
    LOB_NonStdAuto = [
        SELECT 
            Id
            ,Claims_Client_Risk_Assessment__c

        FROM 
            CCRA_LOB_NonStdAuto__c 
        WHERE 
            IsDeleted = false 
            AND 
            Claims_Client_Risk_Assessment__c = :CCRA_ID 
        ORDER BY CreatedDate DESC NULLS FIRST LIMIT 1
   ];  

        return LOB_NonStdAuto;    
    }


//**********************************************************************     
} //End Class

Visualforce Component

<apex:component >
    <!-- Attribute Definitions -->
    <apex:attribute name="NonStdAuto" type="CCRA_LOB_NonStdAuto__c" description="CCRA non standard auto LOB" required="true"/>

<!--Contoller Information variables --> 
<apex:variable var="LOB" value="{!NonStdAuto}" /> 

<apex:stylesheet value="{!URLFOR($Resource.cssresource_ClaimCCRA, 'CSSresource_ClaimsCCRA.css')}"/> 

<apex:pageMessages id="globalMessages" rendered="false"/>
<apex:messages title="data incorrectly entered." style="background-color:yellow; color: blue" /> 

<apex:form id="form1">
<apex:pageBlock id="block1" dir="" >
<apex:actionRegion immediate="true" >
<apex:outputPanel id="OutputTabPanel"> 

<apex:outputPanel Style="width:100%;" layout="block">
    <apex:pageBlockSection id="Summary" title="" columns="2" showHeader="false" >
<!-- ********* -->  
//..... content 
<!-- ********* -->
</apex:pageBlockSection>
</apex:outputPanel>

</apex:outputPanel>
</apex:actionRegion>

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

<!-- End  -->
</apex:component>

1 Answer 1

1

I just want to flag in starting off that some of your terminology is a little confusing and might lead down wrong paths. Objects don't call components, and components don't have Master-Detail relationships - only objects do. Components aren't objects, and nowhere are you passing the parent Id to the component - you're pulling it from the standard controller. (I don't mean to sound brusque, but I think your issue gets way more complex just because of simple terminology issues).

How, in fact, are you surfacing this component? It cannot be on a standard record page, since you have a required sObject attribute. Are you certain that it's receiving the Id of a parent record at all?

I think I see some of the features that contribute to your issue, though, so I hope I can be helpful by highlighting a few of them.

Constructor

         CCRA = new Claims_Client_Risk_Assessment__c();

This line does nothing, because you're initializing from the Standard Controller two lines down.

         this.stdController = controller; 
         this.CCRA = (Claims_Client_Risk_Assessment__c) controller.getRecord();
         this.LOB_NonStdAuto = new CCRA_LOB_NonStdAuto__c();  //instatiate the LOB to receive parent ID         

Same as above.

         //build up LOB fields to pass to components.
         this.LOB_NonStdAuto = queryLOB_NonStdAuto(this.CCRA.Id); 

If you call this while this.CCRA.Id is null, you'll immediately get a QueryException. Also note that your method both assigns directly to the instance variable and returns the value to be assigned here; that's unnecessary and not ideal design.

So clearly if we get to this point this.CCRA.Id is not null, right? Otherwise, we would already have an exception. But... we're hiding the exception, if any, with this construct:

        catch (Exception ex) {
            ApexPages.addMessages(ex);
        }

Why? Because your page has this shebang in it:

<apex:pageMessages id="globalMessages" rendered="false"/>

The page messages component isn't rendered, so you're never going to see any errors that occur. They just vanish, and then your code's behavior is likely to be in the realm of undefined - meaning it's unpredictable and we struggle to explain why it does what it does because its internal state is inconsistent.

Getter

    public void getLOB_NonStdAuto() {    
        try {
            this.LOB_NonStdAuto = queryLOB_NonStdAuto(this.CCRA.Id);     
            } catch (Exception ex) {
            ApexPages.addMessages(ex);
            }        
        }

You've got a get method synthesized already in your property declaration:

   public CCRA_LOB_NonStdAuto__c LOB_NonStdAuto { get; set; }  

There's no need to write one out, and in fact it's going to cause problems. Every time this method gets called, and Visualforce will call it, changes you've made to this.LOB_NonStdAuto are going to be wiped out by re-querying it from the database.

Save Method

    Public Void SaveTestInsert() {
        try {
            upsert CCRA; 

You do not need to perform DML yourself if you're also calling, as you do right below, the standard controller's save() method. I'm not sure I can explain the specific behavior you're discussing regarding where the Id value is and is not populated, but if you can remove all of this error-suppression code and add some clear System.debug() statements, I think it'll become much clearer.

            stdController.save();
            AttachLOB();
        } catch (Exception ex) {
            ApexPages.addMessages(ex);
        }
    }

Visualforce Page

<apex:attribute name="NonStdAuto" type="CCRA_LOB_NonStdAuto__c" description="CCRA non standard auto LOB" required="true"/>

<!--Contoller Information variables --> 
<apex:variable var="LOB" value="{!NonStdAuto}" /> 

Neither of these is connected to your controller. Your controller has a property called LOB_NonStdAuto, and you're not using the assignTo attribute on <apex:attribute>, so there's no connection between the values for { !NonStdAuto } in your page and this.LOB_NonStdAuto in your controller.

Since your controller either queries or instantiates its own object, it's not clear how you intend to use this passed-in value. You don't need to construct a new one if you're being supplied with a child object by whatever container is holding this component. Any input fields hooked up to fields of NonStdAuto are going to do nothing at all, because that object never has DML performed on it.

Conclusion

You're overworking this. Define your use case carefully - where is this component being used? What data is being passed into it? Are the objects it receives already persisted to the database or not? How are they being shared between the component markup and the controller? - and go from there. Consider removing all of your error handling code until you get it working, and then rebuild it.

4
  • I appreciate your comments. Ironically other criticized my previous post on this because it was more comprehensive. Go figure. And yes the terminology is probably a bit off but I'm inferring that objects are supporting either a VisualForce or VisualForce Component. That may address most of your comments. I am looking for some advice on this.
    – rickmac
    Commented Jul 3, 2018 at 18:39
  • Yeah, we are big on minimal examples, but it looks like you have some issues that are related to your overall architecture. I hope that my comments above help point towards a solution. Some refactoring may just make your problem go away.
    – David Reed
    Commented Jul 3, 2018 at 18:43
  • The original post was not terribly large so I jumped thru a hoop here. I edited the description on terminology. Rather than repost I need to clarify I am creating a new page, nothing saved yet so no ID is available. It seems that I need to upcert and save in order to get the ID to write to the component supporting object master detail field. This works but I'm looking for a cleaner way to do this.
    – rickmac
    Commented Jul 3, 2018 at 18:48
  • I am not assigning anything in the Visual Force component because I'm simply passing the objects data into it via the named attribute 'NonStdAuto' from the parent controller. There are (5) other visualForce Components that will all be passed using dedicated objects. Saves me from having to plug apex into each component's supporting object. I added the parent's Visualforce page that calls a query to pass this. Now I see where your comment is coming from .
    – rickmac
    Commented Jul 3, 2018 at 18:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .