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
MarkL.ax269MarkL.ax269 

Can custom components get input from the user and return to the page?

I'm trying to build a page that is a multi-purpose search tool.  The user makes a selection from a selectList (Account Search, Opportunity Search, etc.) which causes the appropriate component to render on the page.  The component contains input fields so the user can type in search terms, click a Search button and then a third table component is displayed below with the search results.  Sort of like the Advanced search combined with a List View.

My problem is, I can't figure out how to get a handle on the input text from the user, within the custom component.  Apparently the custom components are instantiated separately from the main page and if I use the same controller, I get a new instance of the class.  So I tried creating a new search object, instantiated from the main page, and then passed it to the component, using the input fields as the search object class variables.  Again, the page has no idea that values on the search object have changed.  It looks like once something is passed into a component, the link to the page is broken, and we have a new instance of "something."  Are components completely passive?

In the example below, the inputFields render with the initial values '1234' fine.  Then changing the value to '5678' and clicking an Update commandButton rerenders the fields, back to the original '1234'.  So the searchObj isn't maintained between the component and the page.  I've tried with simple text, custom classes, and last with a Product2.  Any ideas?

Code:
Page:
<apex:page id="thePage" standardController="Variable_Master__c" extensions="variableManagementController">
    <c:productSearch id="psearch" searchObj="{!searchObj}"/>
</apex:page>

Component:
<apex:component >
<apex:attribute name="searchObj" description="Object to contain search terms." type="Product2"/>
 <apex:form id="search">
  <apex:pageBlockSection title="Search" columns="1" collapsible="false" showHeader="false">
   <apex:pageBlockSectionItem >
    <apex:outputLabel for="prodName" value="Product Name"/>
    <apex:inputText id="prodName" value="{!searchObj.Name}"/>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
    <apex:outputLabel for="prodCode" value="Product Code"/>
    <apex:inputField id="prodCode" value="{!searchObj.ProductCode}"/>
   </apex:pageBlockSectionItem>
  </apex:pageBlockSection>
 </apex:form>
</apex:component>

Controller:
public class variableManagementController {
    public Product2 searchObj { get; set; }
    public variableManagementController(ApexPages.StandardController controller) {
     this.sc = controller;
     this.searchObj = new Product2(Name='Test',ProductCode='1234');
    }
}

 

mtbclimbermtbclimber
This can be tricky but should be doable. Best way to explain is with a working example which I tried to create here but I think you aren't including everything here. Where is the "Update" button you referred to? Please include a complete example of what you are trying to accomplish and the fewer custom objects/fields the better ;-)
MarkL.ax269MarkL.ax269
True, reality is a bit more complicated and maybe I over-simplified it.  :)  Here's a better example using standard objects.  Note the only one I'm trying here is "orders" (opportunity line items) and there are leftovers from trying different things here (objects, input text), but I'll need to get all three working.  In my list controllers, it's the "like" I need to get working - right now it's got hard-coded values for testing, but they should be populated with variables from the search component, and then displayed with the display component.

Code:
Page:
<apex:page id="thePage" title="Client Management" tabStyle="Opportunity" standardController="Opportunity" extensions="searchController">
 <apex:sectionHeader title="Clients" subtitle="Home"/>
  <apex:pageBlock title="Search">
   <apex:form id="selectForm">
    <apex:pageBlockSection title="Search" columns="1" collapsible="false" showHeader="false">
     <apex:pageBlockSectionItem >
      <apex:outputLabel for="selectset" value="Select Items to Manage"/>
      <apex:selectList id="selectset" value="{!searchType}" size="1">
       <apex:selectOption itemValue="" itemLabel="- None -"/>
       <apex:selectOption itemValue="addresses" itemLabel="Addresses"/>
       <apex:selectOption itemValue="campaigns" itemLabel="Orders"/>
       <apex:selectOption itemValue="orders" itemLabel="Campaigns"/>
       <apex:actionSupport event="onchange" rerender="searchPanel"/>
      </apex:selectList>
     </apex:pageBlockSectionItem>
    </apex:pageBlockSection>
   </apex:form>
   <apex:outputPanel id="searchPanel">
    <c:addressSearch id="asearch" searchType="{!searchType}" rendered="{!IF(searchType='addresses', 'true', 'false')}"/>
    <c:orderSearch id="osearch" searchObj="{!searchObj}" searchType="{!searchType}" searchName="{!searchName}" searchCode="{!searchCode}" rendered="{!IF(searchType='orders', 'true', 'false')}"/>
    <c:campaignSearch id="csearch" searchType="{!searchType}" rendered="{!IF(searchType='accountvars', 'true', 'false')}"/>
    <apex:form id="bottombuttons">
     <apex:pageBlockSection title="searchbuttons" columns="1" collapsible="false" showHeader="false" rendered="{!IF(searchType='', 'false', 'true')}">
      <apex:pageBlockSectionItem >
       <apex:outputLabel for="searchbutton" value=""/>
       <apex:commandButton value="Search" rerender="searchPanel"/>
      </apex:pageBlockSectionItem>
     </apex:pageBlockSection>
    </apex:form>
    <apex:outputText id="debug" value="Code: {!searchObj.ProductCode}"/>
   </apex:outputPanel>
  </apex:pageBlock>
 <apex:outputPanel id="resultPanel">
  <c:selectRecords id="sList" showProduct="true" showAccount="true" productList="{!itemSelections}" accountList="{!itemSelections}"/>
 </apex:outputPanel>
</apex:page>

Search Component:
<apex:component >
 <apex:attribute name="searchLabel" description="Label for the search." type="String"/>
 <apex:attribute name="searchType" description="Objects to search" type="String"/>
 <apex:attribute name="searchName" description="Name of the product to search." type="String"/>
 <apex:attribute name="searchCode" description="Code of the product to search." type="String"/>
 <apex:attribute name="searchObj" description="Object to contain search terms." type="Product2"/>
 <apex:form id="search">
  <apex:pageBlockSection title="Search" columns="1" collapsible="false" showHeader="false">
   <apex:pageBlockSectionItem >
    <apex:outputLabel for="prodName" value="Product Name"/>
    <apex:inputText id="prodName" value="{!searchObj.Name}"/>
   </apex:pageBlockSectionItem>
   <apex:pageBlockSectionItem >
    <apex:outputLabel for="prodCode" value="Product Code"/>
    <apex:inputField id="prodCode" value="{!searchObj.ProductCode}"/>
   </apex:pageBlockSectionItem>
  </apex:pageBlockSection>
 </apex:form>
</apex:component>

Display Component:
<apex:component >
 <apex:attribute name="showOrder" description="Show/hide the orders." type="Boolean"/>
 <apex:attribute name="showAccount" description="Show/hide the accounts." type="Boolean"/>
 <apex:attribute name="orderList" description="List of orders." type="OpportunityLineItem[]"/>
 <apex:attribute name="accountList" description="List of accounts." type="Account[]"/>
 <apex:form id="recordSelection">
  <apex:pageBlock title="Orders" tabStyle="Opportunity" rendered="{!showOrder}">
   <apex:pageBlockTable value="{!orders}" var="o" id="olist" width="100%">
    <apex:column headerValue="Product Code" value="{!o.PricebookEntry.ProductCode}"/>
    <apex:column headerValue="Product Name" value="{!o.PricebookEntry.Name}"/>
   </apex:pageBlockTable>
  </apex:pageBlock>
  <apex:pageBlock title="Accounts" tabStyle="Account" rendered="{!showAccount}">
   <apex:pageBlockTable value="{!accounts}" var="a" id="alist" width="100%">
    <apex:column headerValue="Area ID" value="{!a.Area_ID__c}"/>
    <apex:column headerValue="Account Name" value="{!a.Name}"/>
   </apex:pageBlockTable>
  </apex:pageBlock>
 </apex:form>
</apex:component>

Controller:
public class searchController {
 
 public String searchType { get; set; }
 public String searchName { get; set; }
 public String searchCode { get; set; }
 public Product2 searchObj { get; set; }
 public list<Account> accounts;
 public list<Product2> products;
 public ApexPages.StandardController sc { get; set; }
 
 public ApexPages.StandardSetController productSC {
  get {
            if(productSC == null) {
                productSC = new ApexPages.StandardSetController(Database.getQueryLocator([select Id, Name, PricebookEntry.ProductCode from OpportunityLineItem where PricebookEntry.ProductCode like '2008V-D%' limit 10]));
            }
            return productSC;
        }
        set;
 }
 
 public ApexPages.StandardSetController accountSC {
  get {
            if(accountSC == null) {
                accountSC = new ApexPages.StandardSetController(Database.getQueryLocator([select Id, Name, Area_ID__c from Account where Area_ID__c like 'IN%' limit 10]));
            }
            return accountSC;
        }
        set;
 }

    public searchController(ApexPages.StandardController controller) {
     this.sc = controller;
     this.searchType = '';
     this.searchObj = new Product2(Name='Test',ProductCode='1234');
    }
    
    public list<OpportunityLineItem> getItemList() {
     return (list<OpportunityLineItem>)this.productSC.getRecords();
    }
    
    public list<Account> getAccounts() {
     return (list<Account>)this.accountSC.getRecords();
    }
    
}

 

MarkL.ax269MarkL.ax269
I missed a couple things in "standardizing" my code - leftovers from trying different things.  The getItemList method should be:
Code:
    public list<OpportunityLineItem> getProducts() {
     return (list<OpportunityLineItem>)this.productSC.getRecords();
    }

 and the resultPanel component should be
Code:
 <apex:outputPanel id="resultPanel">
  <c:selectRecords id="sList" showProduct="true" showAccount="true" orderList="{!products}" accountList="{!accounts}"/>
 </apex:outputPanel>

 Mark



Message Edited by MarkL on 12-08-2008 10:59 AM