Nesting Generic Collection Binder

Occasionally, you will have a need to have a form element of one binder being bound to another data source. Sitefinity client binders support nesting of GenericCollectionBinder inside of other binders and in this article we will demonstrate how to nest a bound SELECT element, bound RADIO list and bound CHECKBOX list.

Before We start, though, let us take a look at the following screenshots to visualize the task that we wish to accomplish.

Preparing the FormBinder - binder in which GenericCollectionBinder will be nested

The process of nesting a GenericCollectionBinder inside of another binder is very simple. In this example we will be nesting GenericCollectionBinder inside of a FormBinder. You should start with defining a FormBinder like in this sample:

<div id="storeForm" runat="server"
</div>
<sitefinity:FormBinder ID="formBinder" runat="server"  
            ServiceUrl="~/Sitefinity/Services/Commerce/Stores.svc"
            TargetId="storeForm"
            OnClientBinderInitialized="FormBinderInitialized"
            OnClientItemDataBound="FormItemDataBound"
            DataKeyNames="Id"
            DataMembers="Name, Description, ManagerName"
            <Containers>
                <sitefinity:BinderContainer runat="server"
                    <fieldset>
                        <legend>Store info:</legend>
                        <label for="Name">Store name:</label>
                        <br />
                        <input id="Name" type="text" value="{{Name}}" />
                        <br />
                        <label for="Description">Store description:</label>
                        <br />
                        <textarea id="Description" rows="5">{{Description}}</textarea>
                        <br />
                        <label for="ManagerName">Manager name:</label>
                        <br />
                        <select id="ManagerName" class="optionList"></select>
                        <br />
                        <input type="button" value="Save" sys:onclick="SaveStore();" />
                        or 
                        <a sys:href="#" sys:onclick="CancelStore();">Cancel</a>
                    </fieldset>
                </sitefinity:BinderContainer>
            </Containers>
</sitefinity:FormBinder>

In place where you want to nest a GenericCollectionBinder you should:
  • put SELECT element if you want to nest a SELECT box or
  • put DIV element if you want to nest a RADIO button list or CHECKBOX list
  • The id of the element ought to be the same as the name of the DataMember that will be set through this nested binder. The class of the element should be set to:
  • optionList if you are nesting a SELECT box
  • radioList if you are nesting RADIO button list or
  • checkboxList if you are nesting CHECKBOX list
Finally subscribe to the OnClientItemDataBound event of the FormBinder; in this event we will nest the GenericCollectionBinder.

Setting up GenericCollectionBinder - binder that we will nest

As we have mentioned when explaining the Preparation of FormBinder, it was neccessary that we subscribe to the OnClientItemDataBound event. In the handler for this event we will have following code:

function FormItemDataBound(sender, args) { 
      var target = args.FindControl('ManagerName'); 
      if (args.get_dataItem()) { 
            employeesBinder.set_selectedValue(args.get_dataItem().ManagerName); 
      
      employeesBinder.set_target(target); 
      employeesBinder.DataBind(); 
}

The ItemEventArgs object passed to us in this function eases the whole process quite a lot. Let us examine this code line by line:

  • In the first line, we are getting the target element for our nested binder, by looking for the control with the id 'ManagerName' (remember that we have placed a SELECT element with id='ManagerName' in the BinderContainer for out FormBinder). It is important to find the reference to the target in this manner, since binders automatically ensure unique IDs of the controls - meaning that the ID of the select box is not exactly 'ManagerName' - however, the FindControl function is able to resolve that id to an actual id of the control.
  • After that, we check if there is a dataItem for this item and if so, we set the selected value of our nest binder to the ManagerName property of the bound data item. In this way we ensure that when user opens the form, the proper manager name in the nested binder is always selected.
  • In the next line, we are dynamically setting the target of our nested binder to the target element for which we have acquired the reference in the first line of this function.
  • Finally, we call DataBind function on the nested binder in order to bind it.

    And that is all we need to do. Sitefinity client binders will take care of all the plumbing. At the end of this article you can find the code sample which demonstrates nesting SELECT box, CHECKBOX list and RADIO button list. Here you can see the full implementation for nesting the SELECT box:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="StoresDropDown.aspx.cs" Inherits="StoresDropDown" %>
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<%@ Register TagPrefix="sitefinity" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<head runat="server"
    <title></title
</head>
<body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView" sys:activate="*" xmlns:code="http://schemas.microsoft.com/aspnet/code"
    <form id="form1" runat="server"
 
        <asp:ScriptManager ID="scriptManager1" runat="server"
            <Scripts>
                <asp:ScriptReference Name="MicrosoftAjax.js" Path="~/Sitefinity/Scripts/MicrosoftAjax.js" />
                <asp:ScriptReference ScriptMode="Inherit" Path="~/Sitefinity/Scripts/MicrosoftAjaxTemplates.js" />
                <asp:ScriptReference ScriptMode="Inherit" Path="~/Sitefinity/Scripts/MicrosoftAjaxAdoNet.js" />
            </Scripts>
        </asp:ScriptManager>
 
        <h2>
            Stores drop down 
        </h2>
        <a href="Employees.aspx">Employees</a>  
        |  
        <strong>Stores drop down</strong>
        
        <a href="StoresCheckboxes.aspx">Stores checkboxes</a>
        
        <a href="StoresRadioButtons.aspx">Stores radiobuttons</a>
 
        <hr />
        <input id="NewStoreButton" type="button" value="New store" onclick="NewStore();" />
 
        <div id="storeForm" runat="server"
        </div>
 
        <telerik:RadGrid ID="storesGrid" runat="server" AutoGenerateColumns="false"
            <MasterTableView>
                <Columns>
                    <telerik:GridTemplateColumn UniqueName="BinderContainer0"></telerik:GridTemplateColumn>
                    <telerik:GridTemplateColumn UniqueName="BinderContainer1"></telerik:GridTemplateColumn>
                    <telerik:GridTemplateColumn UniqueName="BinderContainer2"></telerik:GridTemplateColumn>
                    <telerik:GridTemplateColumn UniqueName="BinderContainer3"></telerik:GridTemplateColumn>
                </Columns>
            </MasterTableView>
        </telerik:RadGrid>
 
        <sitefinity:FormBinder ID="formBinder" runat="server"  
            ServiceUrl="~/Sitefinity/Services/Commerce/Stores.svc"
            TargetId="storeForm"
            OnClientBinderInitialized="FormBinderInitialized"
            OnClientItemDataBound="FormItemDataBound"
            DataKeyNames="Id"
            DataMembers="Name, Description, ManagerName"
            <Containers>
                <sitefinity:BinderContainer runat="server"
                    <fieldset>
                        <legend>Store info:</legend>
                        <label for="Name">Store name:</label>
                        <br />
                        <input id="Name" type="text" value="{{Name}}" />
                        <br />
                        <label for="Description">Store description:</label>
                        <br />
                        <textarea id="Description" rows="5">{{Description}}</textarea>
                        <br />
                        <label for="ManagerName">Manager name:</label>
                        <br />
                        <select id="ManagerName" class="optionList"></select>
                        <br />
                        <input type="button" value="Save" sys:onclick="SaveStore();" />
                        or 
                        <a sys:href="#" sys:onclick="CancelStore();">Cancel</a>
                    </fieldset>
                </sitefinity:BinderContainer>
            </Containers>
        </sitefinity:FormBinder>
 
        <sitefinity:RadGridBinder ID="gridBinder" runat="server"
            ServiceUrl="~/Sitefinity/Services/Commerce/Stores.svc"
            TargetId="storesGrid"
            BindOnLoad="true"
            OnClientBinderInitialized="GridBinderInitialized"
            OnClientItemEditCommand="GridEditCommand"
            DataKeyNames="Id"
            DataMembers="Name, Description, ManagerName"
            <Containers>
                <sitefinity:BinderContainer runat="server"
                    <input type="button" value="Edit" class="editCommand" />
                </sitefinity:BinderContainer>
                <sitefinity:BinderContainer runat="server"
                    {{Name}} 
                </sitefinity:BinderContainer>          
                <sitefinity:BinderContainer runat="server"
                    {{Description}} 
                </sitefinity:BinderContainer>
                <sitefinity:BinderContainer runat="server"
                    {{ManagerName}} 
                </sitefinity:BinderContainer>
            </Containers>
        </sitefinity:RadGridBinder>
 
        <sitefinity:GenericCollectionBinder ID="employeesBinder" runat="server"
            ServiceUrl="~/Sitefinity/Services/Commerce/Employees.svc"
            OnClientBinderInitialized="EmployeesBinderInitialized"
            DataKeyNames="Id"
            DataMembers="Name"
            <Containers>
                <sitefinity:BinderContainer runat="server" RenderContainer="false" TemplateHolderTag="Select"
                    <option value="{{Name}}">{{Name}}</option>
                </sitefinity:BinderContainer>
            </Containers>     
        </sitefinity:GenericCollectionBinder>
 
        <script type="text/javascript"
 
            var formBinder; 
            var gridBinder; 
            var employeesBinder; 
 
            function FormBinderInitialized(sender, args) { 
                formBinder = sender; 
                formBinder.AddValidationRule('Name', 'required', 'Name is a required field'); 
            
 
            function GridBinderInitialized(sender, args) { 
                gridBinder = sender; 
            
 
            function EmployeesBinderInitialized(sender, args) { 
                employeesBinder = sender; 
            
 
            function NewStore() { 
                formBinder.New(); 
                formBinder.get_globalDataKeys()["Id"] = formBinder.GetEmptyGuid(); 
            
 
            function SaveStore() { 
                if (formBinder.SaveChanges()) { 
                    formBinder.ClearTarget(); 
                    gridBinder.DataBind(); 
                
            
 
            function CancelStore() { 
                formBinder.ClearTarget(); 
                return false;               
            
 
            function GridEditCommand(sender, args) { 
                formBinder.get_globalDataKeys()["Id"] = args.get_key()["Id"]; 
                formBinder.DataBind(); 
            
 
            function FormItemDataBound(sender, args) { 
                var target = args.FindControl('ManagerName'); 
                if (args.get_dataItem()) { 
                    employeesBinder.set_selectedValue(args.get_dataItem().ManagerName); 
                
                employeesBinder.set_target(target); 
                employeesBinder.DataBind(); 
            
        </script>
</body>
</html>

Next steps

+1-888-365-2779
sales@sitefinity.com

Related topics:

Feedback

How useful is this article?

Tell us more

Submit
Your message was successfully sent.

We appreciate your feedback.

Your message could not be sent.

OK