jp2code jp2code - 2 months ago 12
ASP.NET (C#) Question

How do I read/write ListView ItemTemplate field using jQuery?

I have been struggling with this, so I put together a stripped down version to show the problems I am having.

Start with a generic class like the Member class shown below:

public class Member
{

public Member()
{
Number = String.Empty;
Name = String.Empty;
Email = String.Empty;
Phone = String.Empty;
}
public String Number { get; set; }
public String Name { get; set; }
public String Email { get; set; }
public String Phone { get; set; }
public String LinkNumber
{
get
{
var result = String.Empty;
if (!String.IsNullOrEmpty(Number))
{
result = String.Format("<a class=\"showpopup\" id=\"{0}\">{0}</a>", Number);
}
return result;
}
}

}


I want to display that in an ASP.NET Framework 4.6 WebForm using a ListView control.

ASIDE:

Is there a JSFiddle tool that works with ASP.NET? I can't get the ASP.NET to render there, so I post the HTML here, in sections.

In the HEAD of the document, I have some simple javascript and CSS:

<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.js"></script>
<script>
$(document).ready(function () {
$('div.popup_hider').hide();
$('div.popup_box').hide();
//on click hide the message and the
//on click show the hider div and the message
$('.showpopup').click(function () {
$('div.popup_hider').fadeIn("slow");
$('div.popup_box').fadeIn("slow");
$('tdMember').val($('#<%=lnkMemberNumber.ClientID%>').val());
$('tdName').val($('#<%=lnkMemberName.ClientID%>').val());
$('tdPhone').val($('#<%=lnkMemberPhone.ClientID%>').val());
$('tdEmail').val($('#<%=lnkMemberEmail.ClientID%>').val());
});
$('#tdCancel').click(function () {
$('div.popup_hider').fadeOut("slow");
$('div.popup_box').fadeOut("slow");
});
$('#tdSave').click(function () {
$('div.popup_hider').fadeOut("slow");
$('div.popup_box').fadeOut("slow");
$('lnkMemberNumber').val($('tdMember').val());
$('lnkMemberName').val($('tdName').val());
$('lnkMemberPhone').val($('tdPhone').val());
$('lnkMemberEmail').val($('tdEmail').val());
});
});
</script>
<style>
div.popup_box {
background-color: #888888;
display: table;
filter: alpha(opacity=100);
border: 1px solid #999999;
margin: auto;
opacity: 1;
position: fixed;
z-index: 11;
-moz-opacity: 1;
}
div.popup_hider {
background-color: #004392;
filter: alpha(opacity=55);
height: 100%;
left: 0px;
opacity: .55;
position: fixed;
top: 0px;
width: 100%;
z-index: 10;
-moz-opacity:.55;
}
</style>


The controls referenced above are defined in the HTML below:

<body>
<form id="form1" runat="server">
<div>
<div class="popup_hider"></div>
<div class="popup_box">
<table>
<tr>
<td>Member:<br /><input type="text" id="tdMember" /></td>
<td>Name<br /><input type="text" id="tdName" /></td>
</tr>
<tr>
<td>Phone:<br /><input type="tel" id="tdPhone" /></td>
<td>Email:<br /><input type="email" id="tdEmail" /></td>
</tr>
<tr>
<td><a id="tdSave">Save</a></td>
<td><a id="tdCancel">Cancel</a></td>
</tr>
</table>
</div>
<asp:ListView ID="listView1" runat="server">
<LayoutTemplate>
<table border="1">
<tr>
<th><asp:LinkButton runat="server" ID="lnkMemberNumber">Member</asp:LinkButton></th>
<th><asp:LinkButton runat="server" ID="lnkMemberName">Name</asp:LinkButton></th>
<th><asp:LinkButton runat="server" ID="lnkMemberPhone">Phone</asp:LinkButton></th>
<th><asp:LinkButton runat="server" ID="lnkMemberEmail">Email</asp:LinkButton></th>
</tr>
<tr id="itemPlaceholder" runat="server" class="listview"></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:Label runat="server" ClientIDMode="Static" ID="lblMemberNumber"><%#Eval("LinkNumber") %></asp:Label></td>
<td><asp:Label runat="server" ClientIDMode="Static" ID="lblMemberName"><%#Eval("Name") %></asp:Label></td>
<td><asp:Label runat="server" ClientIDMode="Static" ID="lblMemberPhone"><%#Eval("Phone") %></asp:Label></td>
<td><asp:Label runat="server" ClientIDMode="Static" ID="lblMemberEmail"><%#Eval("Email") %></asp:Label></td>
</tr>
</ItemTemplate>
</asp:ListView>
</div>
</form>
</body>


That is how every page I see shows how to access ASP.NET controls with jQuery; however, the ASP.NET controls referenced in the head section are part of the ItemTemplate, so are not actually visible inside the HTML:

$('tdMember').val($('#<%=lnkMemberNumber.ClientID%>').val());
$('tdName').val($('#<%=lnkMemberName.ClientID%>').val());
$('tdPhone').val($('#<%=lnkMemberPhone.ClientID%>').val());
$('tdEmail').val($('#<%=lblEmail.ClientID%>').val());


If you put that into a Visual Studio 2015 project, you will see Red Squiggly lines that read:


The name 'xxx' does not exist in the current context


You get a Compilation Error with the same message if you try running it.

So, how can I read (and eventually write) values from a ListView ItemTemplate control to HTML using jQuery?

To make this simple, I populated static data in the Page_Load event:

private List<Member> _roster;

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (_roster == null)
{
_roster = new List<Member>();
_roster.Add(new Member() { Name = "John Doe", Number = "ABC123", Email = "jdoe@email.com", Phone = "5551234" });
_roster.Add(new Member() { Name = "Jane Doe", Number = "ABC124", Email = "janed@email.com", Phone = "5551111" });
_roster.Add(new Member() { Name = "Jenny", Number = "ABC1233", Email = "jenny@hotmail.com", Phone = "8675309" });
}
listView1.DataSource = _roster;
listView1.DataBind();
}
}


Solved!



https://jsfiddle.net/jp2code/z7tpuagf/

Answer

Here is an example. Add a unique class name and ID to the <tr> by using the row index from the ListView.

<tr id="listRow_<%# Container.DataItemIndex %>" class="listRow">

Then the jQuery can bind the onclick event to the row and loop the <span> elements in the table cells.

<script type="text/javascript">
    $(document).ready(function () {
        $('.listRow').click(function () {
            //loop al span elements in the td
            $(this).find('td span').each(function (index, value) {
                alert($(value).text());
            });
            //or use the row number to do stuff and hardcode the elements
            var rowNumber = this.id.split("_")[1];
            var lbl1 = "mainContentPane_listView1_lblMemberEmail_" + rowNumber;
            alert($("#" + lbl1).text());
        });
    });
</script>

The problem is that you are using ClientIDMode="Static". Normally a ListView (and all other controls that loop data to generate content) will create a unique id per row and control within the row. That looks something like this: mainContentPane_listView1_lblMemberName_1.

That is why you are getting the errors when using <%=lnkMemberNumber.ClientID%>. It does not exist outside of the ListView and thus is not accessible, even with a static ClientID.

Also enabling ClientIDMode="Static" in a repeater element will result in multiple ID's that are exactly the same and that is not what you want.

UPDATE

<script type="text/javascript">
    //set the rowNumber as global variable
    var rowNumber;

    $(document).ready(function () {
        $('.listRow').click(function () {
            //loop al span elements in the td and fill the textboxes
            $(this).find('td span').each(function (index, value) {
                if (index == 0) {
                    $("#tdMember").val($(value).text());
                } else if (index == 1) {
                    $("#tdName").val($(value).text());
                } else if (index == 2) {
                    $("#tdPhone").val($(value).text());
                } else if (index == 3) {
                    $("#tdEmail").val($(value).text());
                }
            });
            //or use the row number to do stuff and hardcode the elements, but we'll use the rowNumber later
            rowNumber = this.id.split("_")[1];
            var lbl1 = "mainContentPane_listView1_lblMemberEmail_" + rowNumber;
            var lbl1Text = $("#" + lbl1).text();
        });

        $('#tdSave').click(function () {
            $('div.popup_hider').fadeOut("slow");
            $('div.popup_box').fadeOut("slow");

            //and now we do the reverse, find the row ID with listRow_ + rowNumber and update the values in the cell
            $('#listRow_' + rowNumber).find('td span').each(function (index, value) {
                if (index == 0) {
                    $(value).text($("#tdMember").val());
                } else if (index == 1) {
                    $(value).text($("#tdName").val());
                } else if (index == 2) {
                    $(value).text($("#tdPhone").val());
                } else if (index == 3) {
                    $(value).text($("#tdEmail").val());
                }
            });
        });
    });
</script>
Comments