4

I have successfully created a visualforce page (parent VF page) that injects another visualforce page (child VF page) into a jquery modal window.

The problem I am running into is passing some data from the parent VF page to the child VF page. The way I currently have it setup is using the apex:composition tag. However, I am not sure if that is the best approach. Here is the code...

Parent VF page

<apex:page controller="ChooseContactController">
JS/Stylesheets
<apex:form >
    <apex:pageBlock title="Choose a contact" mode="edit">
        <apex:pageBlockButtons >
            <input type="button" class="btn show-modal" value="New Contact"/>
            <apex:commandButton action="{!save}" value="Save" rerender="chooseContactPageMessagesWrapper"/>
        </apex:pageBlockButtons>
        <apex:outputPanel id="chooseContactPageMessagesWrapper">
            <apex:pageMessages />
        </apex:outputPanel>
        Data Display
    </apex:pageBlock>
    <apex:inputHidden value="{!primaryContactId}" id="primaryContactId" />
</apex:form>

<div id="modal-div" title="Create Contact" style="display:none;">
    <apex:composition template="CreateContact">
        <apex:define name="accountId">
            <apex:inputHidden value="{!accountId}" id="accountId" />
        </apex:define>
    </apex:composition>
</div>

In the apex:define tag, I am successfully passing the accountId to the child page...

Child VF page

<apex:page standardController="Contact" extensions="CreateContactExtensions">
<apex:form >
    <apex:pageBlock title="Create a new contact">
        <apex:outputPanel id="createContactPageMessagesWrapper">
            <apex:pageMessages />
        </apex:outputPanel>
        <apex:pageBlockButtons >
            <apex:commandButton action="{!save}" value="Save" rerender="createContactPageMessagesWrapper" />
        </apex:pageBlockButtons>
        <apex:pageBlockSection >
            <apex:inputField value="{!contact.firstName}"/><br />
            <apex:inputField value="{!contact.lastName}"/>
        </apex:pageBlockSection>
    </apex:pageBlock>
    <apex:insert name="accountId"/>
</apex:form>

When I inspect the html on the child VF page, the accountId is successfully being passed over. However, the CreateContactExtensions controller class does not recognize the accountId.

CreateContactExtensions controller

public class CreateContactExtensions 
{
    public String accountId { get; set; }
    public Contact contact { get; set; }
    ApexPages.StandardController standardController;

    public CreateContactExtensions(ApexPages.StandardController standardControllerParam) 
    {
        accountId = 'test';
        standardController = standardControllerParam;
        contact = (Contact)standardController.getRecord(); 
    }

    public String getAccountId()
    {
        return accountId;
    }

    public PageReference save() 
    {
        System.debug(accountId);
        contact.AccountId = accountId;
        standardController.save();
        return null;
    }
}

When I try to save the contact, the accountId is always set to 'test'. I am assuming that is because the child VF page extension controller class does not recognize accountId as a property.

Is there a way to get the extension controller class to recognize accountId as a property the way I have it setup? Should I be taking a different approach... maybe using apex:components? Is there a way to leverage a standard controller within a custom component?

Should I try one large custom visualforce page/controller? Although, I am not sure how viable this solution is because my child VF page is optional. To do this, I would have to move the child VF page markup into the form tag on the parent VF page. Then, when I post back to the parent VF custom controller, validation rules will run on all the properties. The contact property will need to have certain fields, i.e. last name, filled in for the validation rules to pass. Being that this piece is optional, sometimes those fields will not be filled in, the validation rules will fail, and I will never reach my method on the custom controller.

Am I simply missing something with my current architecture?

  • 1
    Custom components with their own controller can have parent controller's variables passed by defining within the custom component an apex:attribute name="myAttr" assignto="{!customcomponentControllerSetterProperty}". When you define the custom component, use name="{!accountId}" to pass the value from parent controller to component controller – cropredy May 24 '14 at 18:41
  • That sounds like a viable solution. Do you think one large custom visualforce page/controller is a better option? Or should I try to decouple it? – Mr. Ant May 25 '14 at 13:53
  • 1
    Custom components are useful when you plan on reusing the component elsewhere on the page or on other pages. That said, I use components (not necessarily with their own controllers) just to make the main VF page more understandable – cropredy May 26 '14 at 20:35
3

I would suggest the pattern of using a custom component that receives data from the parent page. As long as you are only needing the value within the component, it is a straightforward process. If, however, you are wanting to modify the value in the component and return that to the parent page, it gets more complicated.

In the simplest form (just passing the value to the component):

<apex:component controller="YourComponentControllerClass" selfClosing="true" allowDML="true">
    <apex:attribute name="accountId" description="" type="Id" assignTo="{!theAccountId}" />
    <!-- do your stuff here -->
</apex:component>


public with sharing class YourComponentControllerClass {
    public Id theAccountId {get; set;}

    public YourComponentControllerClass() {}
    // do your stuff here
}
  • Can I refresh the parent VF page from the component controller? – Mr. Ant May 27 '14 at 13:33
  • Also, can I leverage a standard controller within a custom component? My child VF page is just inserting a contact to a specific account. – Mr. Ant May 27 '14 at 13:47
  • 1
    Yes, you can rerender the parent visualforce page. It requires 2 things -- a method that returns PageReference, even if that method just returns null (same as a normal page rerender), and an attribute on your custom component titled "rerender" that takes a string. As for the standard controller within a custom component, I'm not sure about that. I have never tried it, but would be worth a shot. – Andrew Monshizadeh May 27 '14 at 14:46
  • On the parent VF page, does <c:someValue /> tag go in the apex:form tag? The reason I ask is because when I initially tried to make this all one big custom VF page, validation rules would run on the null contact object, i.e. You must enter a last name. Because the validation rules failed, the page would never post to my custom controller action method. Do custom components work in a similar manner? – Mr. Ant May 27 '14 at 18:10
  • 1
    I would argue that if you are only rerendering the page (like if you are updating the ui in response to a pick list change), then you most often will want to bypass validation rules. It is only when you want to insert/update should the page run its validation. – Andrew Monshizadeh May 30 '14 at 16: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.