This is a migrated thread and some comments may be shown as answers.

Accessing controls inside TemplateColumns client-side?

1 Answer 245 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Adam
Top achievements
Rank 1
Adam asked on 23 Sep 2011, 08:18 PM
I have two GridTemplateColumn's inside a RadGrid that is created dynamically in the code behind (there are actually several Grids, all with different datasources, that live inside the child items of a 2-level deep RadPanelBar!). It's a fairly simple senario:

1st column is a "N/A" column that only contains a RadioButton control.
2nd column is a "Date" column that contains a RadioButton and a RadDatePicker.

The desired behavior is for the RadDatePicker to be disabled when the "N/A" button is pressed, and enabled when the "Date" button is pressed. Unfortunately there's no 'onChanged' event for RadioButtons, so it has to be handled by 'onClick' handlers.

Here are template classes for the two columns:

private class RadioButtonDateColumnTemplate : ITemplate
{
    protected RadioButton rButton;
    protected RadDatePicker datePicker;
    private string colname;
    public RadioButtonDateColumnTemplate(string cName)
    {
        colname = cName;
    }
    public void InstantiateIn(System.Web.UI.Control container)
    {
        rButton = new RadioButton();
        rButton.GroupName = "ScaleButtons";
        rButton.ID = "dateButton";
        rButton.DataBinding += new EventHandler(rButton_DataBinding);               
         
        datePicker = new RadDatePicker();
        datePicker.ID = "DatePicker";
        datePicker.DataBinding += new EventHandler(datePicker_DataBinding);
        datePicker.Load += new EventHandler(datePicker_Load);
 
        container.Controls.Add(rButton);
        container.Controls.Add(datePicker);
    }
 
    void datePicker_Load(object sender, EventArgs e)
    {
        rButton.Attributes.Add("onClick", string.Format("DateButtonClicked('{0}')", datePicker.ClientID));
    }
 
    void datePicker_DataBinding(object sender, EventArgs e)
    {
        RadDatePicker dPick = (RadDatePicker)sender;
        GridDataItem container = (GridDataItem)dPick.NamingContainer;
 
        string date = ((DataRowView)container.DataItem)[colname].ToString();
        DateTime dateTime;
 
        if (date == string.Empty)
            dPick.SelectedDate = null;
        else
        {
            DateTime.TryParse(date, out dateTime);
            dPick.SelectedDate = dateTime;
        }
    }
 
    void rButton_DataBinding(object sender, EventArgs e)
    {
        RadioButton rBut = (RadioButton)sender;
        GridDataItem container = (GridDataItem)rBut.NamingContainer;
 
        bool naChecked;
        bool.TryParse(((DataRowView)container.DataItem)["na"].ToString(), out naChecked);
        rButton.Checked = !naChecked;
        datePicker.Enabled = !naChecked;
    }
}


private class RadioButtonColumnTemplate : ITemplate
{
    protected RadioButton rButton;
    private string colname;
    public RadioButtonColumnTemplate(string cName)
    {
        colname = cName;
    }
    public void InstantiateIn(System.Web.UI.Control container)
    {
        rButton = new RadioButton();
        rButton.GroupName = "ScaleButtons";
        rButton.DataBinding += new EventHandler(rButton_DataBinding);
        if (colname == "na")
        {
            rButton.ID = "naButton";
            rButton.Load += new EventHandler(rButton_Load);
        }
 
        container.Controls.Add(rButton);
    }
 
    void rButton_Load(object sender, EventArgs e)
    {
        GridDataItem gridRow = (GridDataItem)rButton.Parent.NamingContainer;
        string gridID = gridRow.OwnerGridID;
        int rowIndex = gridRow.DataSetIndex;
 
        rButton.Attributes.Add("onClick", string.Format("NaButtonClicked('{0}',{1},'Date')", gridID, rowIndex));
    }
 
    void rButton_DataBinding(object sender, EventArgs e)
    {
        RadioButton rBut = (RadioButton)sender;
        GridDataItem container = (GridDataItem)rBut.NamingContainer;
 
        bool check;
        bool.TryParse(((DataRowView)container.DataItem)[colname].ToString(), out check);
        rButton.Checked = check;
    }
}

The RadGrids are created inside a dynamically built RadPanelBar with root and child items (the RadGrids are inside the child items, 1 per child):

protected void CategoriesPanelBar_Init(object sender, EventArgs e)
{
    DataTable cTypes = GetCapabilityTypes(false);
    DataTable cCategories = GetCapabilityCategories();
 
    RadPanelBar rpbCapabilityCategories = (RadPanelBar)sender;
 
    foreach (DataRow typeRow in cTypes.Rows)
    {
        string typeName = typeRow["typename"].ToString();
        string typeID = typeRow["id"].ToString();
        RadPanelItem typeItem = new RadPanelItem(typeName);
        DataRow[] categoriesByType = cCategories.Select(string.Format("type = {0}", typeID));
        foreach (DataRow categoryRow in categoriesByType)
        {
            string categoryName = categoryRow["categoryname"].ToString();
            int categoryID = int.Parse(categoryRow["id"].ToString());
            RadPanelItem categoryItem = new RadPanelItem(categoryName);
            categoryItem.BackColor = System.Drawing.Color.LightBlue;
 
            RadGrid rgItems = new RadGrid();
            rgItems.AutoGenerateColumns = false;
            rgItems.AllowMultiRowEdit = true;
            rgItems.MasterTableView.EditMode = GridEditMode.InPlace;
            rgItems.PreRender += new EventHandler(rgItems_PreRender);
 
            BuildCapabilityItemsGridByCategory(rgItems, categoryID);
 
            categoryItem.Controls.Add(rgItems);
            typeItem.Items.Add(categoryItem);
        }
 
        rpbCapabilityCategories.Items.Add(typeItem);
    }
}


I create the template columns when building the RadGrid inside the BuildCapabilityItemsGridByCategory() function:

...

DataTable dtCapabilities = GetCapabilityItemsByCategoryAndSite(category, site);
 
...
 
dtCapabilities.Columns.Add("na", System.Type.GetType("System.Boolean"));
GridTemplateColumn naCol = new GridTemplateColumn();
naCol.ItemTemplate = new RadioButtonColumnTemplate("na");
naCol.HeaderText = "N/A    ";
naCol.DataField = "na";
rgItems.Columns.Insert(rgItems.Columns.Count, naCol);
 
...
 
GridTemplateColumn dateCol = new GridTemplateColumn();                       
dateCol.ItemTemplate = new RadioButtonDateColumnTemplate("date");
dateCol.HeaderText = "Date";
dateCol.DataField = "date";
dateCol.UniqueName = "Date";
rgItems.Columns.Insert(rgItems.Columns.Count, dateCol);
 
...
 
rgItems.DataSource = dtCapabilities;
rgItems.DataBind();


Now enabling the RadDatePicker was very easy - I can pass the clientID directly to the JavaScript function, so a simple js function works:

function DateButtonClicked(datePickerId) {
         var datePicker = $find(datePickerId)
         datePicker.set_enabled(true);
}

But I had a terrible time trying to get the disable to work!! At first, I tried passing the RadDatePicker clienID to the JavaScript function by getting it in the code behind (which is easier for me to write than JavaScript). I tried getting the "N/A" buttton's GridDataItem and looking for a RadDatePicker control on the same row, but some some reason the event would NEVER show up in the page's markup, even when I could see the attribute being added with what appear to be the correct clientID's for the "N/A" radio button and the RadDatePicker on the same row.

I followed some other examples to create a very round-about solution, passing the entire GridView to the JavaScript function, along with the row index and column name that holds the RadDatePicker I want to disable. Even then, I'm not sure how to access the RadDatePicker directly from its grid cell. I ended up using an ugly hack to parse the clientID out of the .innerHTML of the cell, then using the $find() method to grab it. It works, but I KNOW there has to be a better, safer way of doing this:

function NaButtonClicked(gridID, index, colName) {
   var gridView = $find(gridID);
   var masterTable = gridView.get_masterTableView();
   var cell = masterTable.getCellByColumnUniqueName(masterTable.get_dataItems()[index], colName)
   if (cell != null) {
      var datePickers = cell.getElementsByClassName('RadPicker RadPicker_Default');
      for (i = 0; i < datePickers.length; i++) {
         var idString = datePickers[i].innerHTML;
         var startString = "id=\"";
         var endString = "\"";
         var startIndex = idString.indexOf(startString) + startString.length;
         var endIndex = idString.indexOf(endString, startIndex);
         var datePickerId = idString.substring(startIndex, endIndex);
      }
   }
   var datePicker = $find(datePickerId)
   datePicker.set_enabled(false);
}


My questions are:
- is there an easier way to access the controls living in these template columns? I don't have an easy references to use, because everything is created dynamically (the RadGrid, the columns, etc)
-am I hooking up the JavaScript functions is the right spot in the code behind?

I'm worried I'm going about this in the wrong way, making things unnecessarily hard on myself, but maybe the programmatic approach I'm using is just more difficult to execute. I'm very new to ASP.NET and especially JavaScript coding, so I appreciate any help (and all the help I've already received from Pavlina!).


Thanks,
-Adam

1 Answer, 1 is accepted

Sort by
0
Pavlina
Telerik team
answered on 26 Sep 2011, 11:15 AM
Hello Adam,

Please refer to the project attached in the code library below which demonstrates how to get a reference to the DOM element of a server-side control on the client.
http://www.telerik.com/community/code-library/aspnet-ajax/grid/accessing-server-controls-in-a-grid-template-on-the-client.aspx

and see if it helps to achieve your goal.

Greetings,
Pavlina
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now
Tags
Grid
Asked by
Adam
Top achievements
Rank 1
Answers by
Pavlina
Telerik team
Share this question
or