+ Start a Discussion
SCWells72SCWells72 

Two questions about custom components: nesting and sharing controllers

Hi, I'm relatively new to the Force.com platform but am finding it very interesting.  I'm in the process of exploring a reusable integration between jqGrid and VisualForce through custom components.  I have an early version working now but I have two issues that I'd like to resolve:

 

Nested custom components

 

I can't figure out how to have two VisualForce custom components have a nesting relationship, for example, like pageBlockTable and column where the  former sets up some outer context through its value and var attributes and the latter can refer to those, presumably through a shared controller?  I know that you can give a custom component an ID and then refer to that component by ID from other components, but that seems like a cumbersome way to couple reusable components.  What I'd like to have in the end is something like:

 

<c:jqGrid id="productsTable" sObjectTypeName="Product2" pageSize="10" pageSizes="10,25,50" height="250">

    <c:jqGridColumn name="Name" width="75"/>

    <c:jqGridColumn name="ProductCode" width="75"/>

    <c:jqGridColumn name="Family" width="150"/>

</c:jqGrid>

 

But I can't figure out how to give jqGridColumn the context established by jqGrid, both in terms of its attributes and the state of its controller.  Any hints on how to do this?  

 

Shared controllers

 

I'm using JSON to provide a data model for jqGrid.  To do so I have the following artifacts (and would add another custom component if I can get a solid answer for the question above):

 

 

  • jqGrid.component - A custom component that creates the JavaScript and HTML for the jqGrid based on its attributes.
  • jqGridPagingController.cls - A controller for the jqGrid component that's responsible for its state but not anything to do with retrieving or paging through data.
  • jqGridJSONPager.page - A custom page that receives the REST request from jqGrid and returns the correct JSON for the current page.
  • jqGridJSONController.cls - A controller for the page above that actually does the heavy lifting of translating the inputs into a StandardSetController, thumbing through the results, and returning model data fit for a JSON response.
Overall I'm pretty happy with this layout, but the two controllers are shared-nothing.  I'm able to create some connection by passing the required subset of the grid component's configuration as query parameters to the JSON pager, but each time I do so it seems to set up a brand new controller context and therefore a brand new StandardSetController.  This seems VERY inefficient.  Is there any way I can have these guys either ideally share a controller or minimally retain state in jsGridJSONController across invocations?
Thanks much for any tips!

 

Best Answer chosen by Admin (Salesforce Developers) 
SCWells72SCWells72

Okay, I managed to get this going exactly the way I wanted without having to share controllers or have one component know anything about another.  Basically I have the sub-components generate JavaScript variables that build the array for the jQuery Grid and the outer component aggregates those variables and hands them to jqGrid.  The only complaint I have now is that VisualForce is generating a SPAN tag surrounding my custom components that I don't want, but if that's the worst thing I'm hitting, I'm good to go.  Thanks for all the help!!!

 

All Answers

bob_buzzardbob_buzzard

Nested custom components - the controller isn't shared between the outer and inner components in datatable et al, its done through the value and var attributes.  I wrote an example of using this on my blog at:

 

http://bobbuzzard.blogspot.com/2010/10/visualforce-conditional-list-rendering.html

 

WRT shared controllers, you can share the same controller between a page and a component, but you have to pass the controller as an attribute to the component.

SCWells72SCWells72

Thanks for the reply.  I'm still not sure how to do what I'm wanting (hoping?) to do.  In my original example showing nested custom components, what I really need to happen is for both the outer and the inner custom components to contribute to the state of a common controller, then emit the appropriate jQuery.  For example, when the following tags are used:

 

<c:jqGrid sObjectTypeName="Product2" pageSize="10" pageSizes="10,25,50" height="250">
    <c:jqGridColumn name="Name" width="75"/>
    <c:jqGridColumn name="ProductCode" width="75"/>
    <c:jqGridColumn name="Family" width="150"/>
</c:jqGrid>

I want to emit the following HTML:

 

<script type="text/javascript"> 
var grid$ = jQuery.noConflict();
grid$(function(){
jQuery("#Product2Table").jqGrid({
    url:'/apex/jqGridJSONPager?sObjectTypeName=Product2&fields=Name%2CProductCode%2CFamily',
    datatype:'json',
    colModel:[
        {name:'Name',label:'Name',index:0,width:75},
        {name:'ProductCode',label:'Product Code',index:1,width:75},
        {name:'Family',label:'Family',index:2,width:150}
    ],
    rowNum:10,
    rowList:[10,25,50],
    height:250,
    pager:'#Product2TablePager',
    caption:'Products'
});
jQuery("#Product2Table").jqGrid('navGrid', '#Product2TablePager', {edit:false, add:false, del:false});
});
</script>        
    
<table id="Product2Table"></table> 
<div id="Product2TablePager"></div>

where the 'url' and 'colModel' selectors are built off of the nested jqGridColumn component and the rest is pretty much built off of the jqGrid component.  Is this possible with VisualForce custom components?  If so, would you mind providing an explicit description of how to do so?  If so, I think I can build a REALLY nice reusable jqGrid component!

 

Thanks again!

 

bob_buzzardbob_buzzard

If you have to share the controller, then I think you'll need to instantiate the controller in your parent page and then pass that in as an attribute to the child components.  However, if you are planning to change controller values based on getters/setters being called, I'd suggest having a read of the Order of Execution section of the VisualForce Developer's Guide - basically you can't guarantee the order, nor if they will be called more than once.

SCWells72SCWells72

Okay, I managed to get this going exactly the way I wanted without having to share controllers or have one component know anything about another.  Basically I have the sub-components generate JavaScript variables that build the array for the jQuery Grid and the outer component aggregates those variables and hands them to jqGrid.  The only complaint I have now is that VisualForce is generating a SPAN tag surrounding my custom components that I don't want, but if that's the worst thing I'm hitting, I'm good to go.  Thanks for all the help!!!

 

This was selected as the best answer