• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 11849
  • Last Modified:

ASP.NET Interacting Client-Side With Repeater Child Controls Using JavaScript/C#

Hello,

I have a relatively simple need, but I just can't get things to work. I have a repeater control with several controls in its ItemTemplate. One of those controls is a Checkbox. Another is a Textbox. These controls are rendered client-side as HTML type "checkbox" and type "textarea", respectively.

What I would like to do is add text to the textbox whenever the checkbox is checked--and also make it read-only and grayed-out. In essense, the user will see a checkbox labeled "Skip this question"--and when checking it, the words "User did not want to answer this question" would appear in the textbox and it would immediate become read-only and grayed-out. The textbox needs to be changed to read-only so that the user cannot have the checkbox checked and then go enter text into the textbox (the back end would not know what the intent of the user if the checkbox is checked AND there is custom text in the textbox!). When the user unchecks the checkbox, the textbox text should be cleared, and write-enabled, and "whitened" again.

The problem I have is getting the JavaScript function to interact with the textbox. I tried numerous strategies, from getElementById and the forms collection, but nothing worked for me... To give a summary of my work so far, here is what I know (I'm just not sure how to do it syntactically):

1) I need an onclick() attribute defined for the checkbox that will call a client-side JavaScript function and pass to it the index of the checkbox.
2) The client-side function needs to locate the corresponding textbox (textarea) control and change its readonly and value (text?) properties, depending on whether the checkbox is being checked or is being unchecked.

The textarea controls are being rendered as such:
<textarea name="dlstResponses:_ctl0:txtAnswer" id="dlstResponses__ctl0_txtAnswer" class="textbox" style="height:100px;width:322px;"></textarea>
<textarea name="dlstResponses:_ctl1:txtAnswer" id="dlstResponses__ctl1_txtAnswer" class="textbox" style="height:100px;width:322px;"></textarea>
<textarea name="dlstResponses:_ctl2:txtAnswer" id="dlstResponses__ctl2_txtAnswer" class="textbox" style="height:100px;width:322px;"></textarea>
etc.

The checkbox controls are being rendered as such:
<input id="dlstResponses__ctl0_chkNoAnswer" type="checkbox" name="dlstResponses:_ctl0:chkNoAnswer" onclick="setTexboxVals(0)" />
<input id="dlstResponses__ctl1_chkNoAnswer" type="checkbox" name="dlstResponses:_ctl1:chkNoAnswer" onclick="setTexboxVals(1)" />
<input id="dlstResponses__ctl2_chkNoAnswer" type="checkbox" name="dlstResponses:_ctl2:chkNoAnswer" onclick="setTexboxVals(2)" />
etc.

setTexboxVals() is my current JavaScript function.

*** BELOW DOES NOT WORK ***
*** I KNOW THE SYNTAX IS WRONG; I'M SHOWING PSEUDOCODE ONLY ***

What I need is a JavaScript function that does something like this:

function setTextboxVals(val)
{
       if (checkbox being checked)
                {
      document.getElementById("dlstEssays__ctl" + val + "_txtAnswer").setAttribute("readonly","true");
      document.getElementById("dlstEssays__ctl" + val + "_txtAnswer").setAttribute("backcolor","gray");
      document.getElementById("dlstEssays__ctl" + val + "_txtAnswer").setAttribute("value","User did not want to answer this question");
                }
      else
               {
      document.getElementById("dlstEssays__ctl" + val + "_txtAnswer").setAttribute("readonly","false");
      document.getElementById("dlstEssays__ctl" + val + "_txtAnswer").setAttribute("backcolor","white");
      document.getElementById("dlstEssays__ctl" + val + "_txtAnswer").setAttribute("value","");
                }
      return false;
}

Note that I need to know if the checkbox is being checked or unchecked, and I also need to know how to set the textbox's readonly, backcolor, and value (text) properties.

Any help would be most appreciated.
0
Jon500
Asked:
Jon500
  • 4
  • 4
  • 3
1 Solution
 
b1xml2Commented:
it's not so simple. I talk about the theory before i show you what you need to do to make it work.
1. If you recall that the DataGrid has the edit mode where at any one time, only one row is available for editing (by default), that is for very good reasons, as if we expose editable controls throughout every row, we will have to loop through the DataGrid and repopulate the persisted data thereby refreshing the persisted data before rebinding the DataGrid to it.
2. Then there is the client approach and the server approach. If you are looking for simplicity, you use the client code. If you want consistency you'd use the server approach.

I would strongly urge the server approach unless you have very strong reasons against this.
0
 
raterusCommented:
As long as you can access the checkbox and textbox from codebehind in the ItemCreated or ItemDataBound events of the datagrid, you can use their .ClientID property to correctly reference them as the client would see them.  No reason to be writing all the namingcontainer gobbleygook in your example.  Basically, whan I'd do is this.  Create a global JS function that accepts the client ID's of both the checkbox and textbox.  For each row in ItemCreated, attach an onclick handler to the checkbox to call this function, with both ID's set.  Should work pretty smoothly if done properly, and I don't see any reason not to do it on the clientside.
0
 
Jon500Author Commented:
b1xml2:
I'm using a repeater control--not a datagrid.

I absolutely must do this client-side. Imagine how ineffective it would be to round-trip after each checkbox click? If the texbox is not grayed-out upon clicking the checkbox, then the user can enter text into the text box as well as have the checkbox checked. As I mentioned, this is not desirable.

raterus:
I see what you're saying, but whether I hard-code the client id's or populate them server-side into the JS code, I still don't have the syntax down. If you do this sort of thing frequently with success, I'd love to see an example.

To reiterate: I am stuck on getting the JavaScript (JS) code to work. I understand server-side code well, and can populate what streams to the client very effectively. I am weak, however, on DOM and JS.

I raised the points to 350. I need someone who can use my pseudocode (JS, at the very least) and provide a working example.
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
b1xml2Commented:
aspx
===
<%@ Page language="c#" Codebehind="Repeater.aspx.cs" AutoEventWireup="false" Inherits="b1xml2.ExpertsExchange.CSharp.April.Repeater" %>
<%@ Import Namespace="System.Data"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > 

<html>
  <head>
    <title>Repeater</title>
    <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
    <meta name="CODE_LANGUAGE" Content="C#">
    <meta name=vs_defaultClientScript content="JavaScript">
    <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
    <style>
    <!--
    table { border-left:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;}
    td {border-top:1px solid #000000;font-family:Verdana;font-size:10pt;}
    input, a {font-family:Verdana;font-size:10pt;}
   
    // -->
    </style>
  </head>
  <body MS_POSITIONING="FlowLayout">
      
    <form id="Form1" method="post" runat="server">
   
<asp:Repeater ID="ExampleRepeater" Runat="server">
<HeaderTemplate>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tr>
      <td>ReadOnly</td>
      <td>Comments</td>
      <td>&nbsp;</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
      <td nowrap><asp:CheckBox ID="ReadOnlyCheckBox" Runat="server" Checked='<%# (bool)((DataRowView)Container.DataItem)["Checked"] %>' AutoPostBack="True" OnCheckedChanged="ReadOnlyCheckBox_CheckedChanged"/></td>
      <td nowrap><asp:TextBox ID="CommentsTextBox" Runat="server" Width="95%" Text='<%# (string)((DataRowView)Container.DataItem)["Comments"]%>' /></td>
      <td nowrap align="right"><asp:LinkButton ID="DeleteButton" Runat="server" CommandName="delete" CausesValidation="False">[delete]</asp:LinkButton>&nbsp;&nbsp;&nbsp;</td>
</tr>
</ItemTemplate>
<FooterTemplate>
<tr>
      <td>&nbsp;</td>
      <td nowrap><asp:TextBox ID="CommentsTextBox" Runat="server" Width="95%" /><asp:RequiredFieldValidator ID="CommentsValidator" Runat="server" ControlToValidate="CommentsTextBox"><b title="required" style="color:red;cursor:hand;">***</b></asp:RequiredFieldValidator></td>
      <td nowrap align="right"><asp:LinkButton ID="AddButton" Runat="server" CommandName="add" CausesValidation="True">[add]</asp:LinkButton>&nbsp;&nbsp;&nbsp;</td>
</tr>
</FooterTemplate>
</asp:Repeater>
     </form>
      
  </body>
</html>
0
 
b1xml2Commented:
aspx.cs
=====
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace b1xml2.ExpertsExchange.CSharp.April
{
      /// <summary>
      /// Summary description for Repeater.
      /// </summary>
      public class Repeater : System.Web.UI.Page
      {
            protected System.Web.UI.WebControls.Repeater ExampleRepeater;
            private static DataTable _table;

            private DataTable TableItems
            {
                  get
                  {
                        if (_table == null)
                        {
                              _table = new DataTable();
                              _table.Columns.Add("Id",typeof(Guid));
                              _table.Columns.Add("Checked",typeof(bool));
                              _table.Columns.Add("Comments",typeof(string));

                              _table.PrimaryKey = new DataColumn [] { _table.Columns[0] };

                        }

                        return _table.Copy();
                  }
            }
            
            private void Page_Init(object sender, EventArgs e)
            {
                  this.ExampleRepeater.ItemCommand += new RepeaterCommandEventHandler(ExampleRepeater_ItemCommand);
                  this.ExampleRepeater.ItemDataBound += new RepeaterItemEventHandler(ExampleRepeater_ItemDataBound);

            }

            private void Page_Load(object sender, System.EventArgs e)
            {
                  // Put user code to initialize the page here
                  if (! IsPostBack)
                  {
                        this.BindData();
                  }
            }


            private void BindData()
            {
                  this.ExampleRepeater.DataSource = PageSource.DefaultView;
                  this.ExampleRepeater.DataBind();
            }

            private DataTable PageSource
            {
                  get
                  {
                        if (ViewState["PageSource"] == null)
                        {
                              ViewState["PageSource"] = TableItems;
                        }

                        return (DataTable)ViewState["PageSource"];
                  }
            }

            public void ReadOnlyCheckBox_CheckedChanged(object sender,EventArgs e)
            {
                  CheckBox readonlyCheckBox = (CheckBox)sender;
                  RepeaterItem item = (RepeaterItem)readonlyCheckBox.Parent;
                  TextBox commentsTextBox = (TextBox)item.FindControl("CommentsTextBox");
                  commentsTextBox.ReadOnly = readonlyCheckBox.Checked;
            }

            #region Web Form Designer generated code
            override protected void OnInit(EventArgs e)
            {
                  //
                  // CODEGEN: This call is required by the ASP.NET Web Form Designer.
                  //
                  InitializeComponent();
                  base.OnInit(e);
            }
            
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {    
                  this.Load += new System.EventHandler(this.Page_Load);
                  this.Init += new EventHandler(Page_Init);

            }
            #endregion

            private void ExampleRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
            {
                  switch (e.CommandName)
                  {
                        case "add":
                              RefreshData();
                              PageSource.Rows.Add(new object [] {Guid.NewGuid(),false,((TextBox)e.Item.FindControl("CommentsTextBox")).Text});
                        break;
                        case "delete":
                              RefreshData();
                              PageSource.Rows.RemoveAt(e.Item.ItemIndex);
                        break;
                  }
                  BindData();
            }

            private void RefreshData()
            {
                  for(int count=0;count< this.ExampleRepeater.Items.Count;count++)
                  {
                        RepeaterItem item = this.ExampleRepeater.Items[count];
                        TextBox commentsTextBox = (TextBox)item.FindControl("CommentsTextBox");
                        CheckBox readonlyCheckBox = (CheckBox)item.FindControl("ReadOnlyCheckBox");
                        DataRow row = PageSource.Rows[count];
                        row["Checked"] = readonlyCheckBox.Checked;
                        row["Comments"] = commentsTextBox.Text;
               
                  }
            }

            private void ExampleRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
            {
                  switch (e.Item.ItemType)
                  {
                        case ListItemType.Item:
                        case ListItemType.AlternatingItem:
                              DataRowView rowView = (DataRowView)e.Item.DataItem;
                              TextBox commentsTextBox = (TextBox)e.Item.FindControl("CommentsTextBox");
                              commentsTextBox.ReadOnly = (bool)rowView["Checked"];
                        break;

                  }

            }
      }
}
0
 
b1xml2Commented:
The pasted code in full uses the server-side approach.
0
 
raterusCommented:
Here is the javascript to do what you are after, without getting the server involved.  Just pass it id's of the controls to modify.

<script language="javascript">

function setTextboxVals(chkID, txtID)
{
      var chk = document.getElementById(chkID);
      var txt = document.getElementById(txtID);

      if (chk.checked == true)
      {
            txt.disabled = true;
            txt.value = "User did not want to answer this question";
      }
      else
      {
            txt.disabled = false;
            txt.value = "";
      }            
      
      return true;
}
</script>

<input type="checkbox" id="chkTest" onClick="setTextboxVals(this.id,'txtTest');" />
<textarea id="txtTest"></textarea>
0
 
Jon500Author Commented:
I need to digest the responses. I'll post my reply later tonight or early tomorrow.
0
 
Jon500Author Commented:
b1xml2:
Thank you for your comments. However, your code does not compile as posted. Also, I specified that I was seeking an exclusively client-side solution.
0
 
Jon500Author Commented:
raterus:
Your solution is exactly what I was seeking. Thank you!!!

I did not know about .ClientID until you mentioned it to me. It is EXTREMELY USEFUL whenever JavaScript is required! I am embarrassed to admit that I was going to hard-code the ID's into the JavaScript function, and vary only the Repeater (datasource) index as needed. .ClientID is obviously the correct solution because hard-coding would create a maintanence nightmare should the names ever change on the server.

To help others who may read this thread, I wanted to explain how I handled the server side...

In the ItemDataBound function of my Repeater control, I first assign a variable to the CheckBox and TextBox controls:

System.Web.UI.WebControls.TextBox txtAnswer = (System.Web.UI.WebControls.TextBox)(e.Item.FindControl("txtAnswer"));
System.Web.UI.WebControls.CheckBox chkNoResponse = (System.Web.UI.WebControls.TextBox)(e.Item.FindControl("chkNoResponse"));

Then I add the "onclick" function call to the CheckBox's HTML (also in the ItemDataBound function) as follows:

chkNoResponse.Attributes.Add("onclick","setTextboxVals('" + chkNoResponse.ClientID.ToString() +
                              "', '" +
                              txtAnswer.ClientID.ToString() +
                              "');");

Notice that I am surrounding the arguments to the "setTextboxVals" function with single quotes--they're needed by JavaScript.

I have accepted your answer. It's a very elegant solution, and I thank you for your help!

Cheers,
-- Jon
0
 
raterusCommented:
Glad I could help!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

  • 4
  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now