views:

763

answers:

2

I have a gridview column that's gets a large amount of text from the server. So instead of showing all that text after the grid loads I want to show it only if a user clicks an Expand link then closes it with a collapse link. Here is what I have. Please note that I already know that I can put both javascript functions in one; I'm testing right now in two separate functions.

<script type="text/javascript" language="javascript" >
function hidelink() {
    var col = $get('col');
    var exp = $get('exp');
    col.style.display = 'none';
    exp.style.display = '';

}
function showlink(){
    var col = $get('col');
    var exp = $get('exp');
   col.style.display = '';
   exp.style.display = 'none';
}

<asp:GridView ID="GridView2" Width="400px" runat="server" AutoGenerateColumns="False"   
AllowPaging ="True"
BackColor="White" BorderColor="#999999" 
BorderStyle="None" BorderWidth="1px" 
CellPadding="3" DataKeyNames="APPID" 
DataSourceID="SqlDataSource3" 
PagerSettings-Mode="NextPreviousFirstLast"                EnableSortingAndPagingCallbacks="True">

<PagerSettings Mode="NextPreviousFirstLast" />

 <RowStyle BackColor="#EEEEEE" ForeColor="Black" />
 <Columns>
 <asp:BoundField DataField="stuff" HeaderText="Name" ReadOnly="True" 
 SortExpression="app" />
 <asp:BoundField DataField="Description" HeaderText="Short Descr" 
 ReadOnly="True" SortExpression="des" />
 <asp:TemplateField HeaderText="Long Descr" SortExpression="data">
 <EditItemTemplate>
 <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("data") %>'></asp:TextBox>
 </EditItemTemplate>
 <ItemTemplate>
 <div id="col">
 <asp:LinkButton ID="expand" runat="server" OnClientClick ="hidelink();return false;">Expand</asp:LinkButton>  
  </div>
  <div id="exp" style="display:none">
  <asp:LinkButton ID="collapse" runat="server" OnClientClick ="showlink();return false;">Collapse</asp:LinkButton>  
   </div>
  <asp:Panel ID="Panel1" runat="server" >
  <table>
    <tr>
        <td>                                                                     <%#Eval("LongDescription")%>
        </td>
     </tr>
  </table>

My issue is that only the first record does everything it should. (expand/collapse) but the other rows only expand and does not hide the expand link in the div tag. It is only finding the id of the first row because when the expand button is hit on any other row it changes the first row to show the collapse link. How can i fix this?

A: 

You need to use unique IDs for each row. IDs can only apply to one element in the page, and your code is applying one ID to all the instances of this large column in the table.

Alternatively, you can just use the DOM methods to locate the right element to show/hide. For example:

<div>
  <a href="#" onclick="showHideDesc(this); return false;">Expand</a>
  <table style="display: none;">
    <tr>
      <td><%#Eval("LongDescription")%></td>
    </tr>
  </table>
</div>

Then for your script:

function showHideDesc(link) {
    var table = link.parentNode.getElementsByTagName("TABLE")[0];
    if (table.style.display == "none") {
        table.style.display = "";
        link.innerHTML = "Collapse";
    }
    else {
        table.style.display = "none";
        link.innerHTML = "Expand";
    }
}
Jon Benedicto
How do I do that in Javascript
Eric
This seems to only work for the first row also.
Eric
Are you saying to remove my panel that i'm using?
Eric
Yes, remove the Panel and the LinkButton controls that you are using. It's a lot simpler to just use straight HTML.
Jon Benedicto
"This seems to only work for the first row also" - Sorry, I had a bug in my code - it's fixed now.
Jon Benedicto
+2  A: 

The problem is that because you have repeating elements, the ids of the DIVs are being reused. This is illegal in HTML. The id property of each element must be unique. A better way to handle it is to pass in a reference to the current element to the handler and have it derive the element that it needs to operate on by traversing the DOM.

<div>
   <asp:LinkButton ID="expand" runat="server" OnClientClick ="hidelink(this);return false;">Expand</asp:LinkButton>
</div>
<div style="display:none">
   <asp:LinkButton ID="collapse" runat="server" OnClientClick ="showlink(this);return false;">Collapse</asp:LinkButton>
</div>

Note: I'm using jQuery in these functions as it makes it easier to traverse the DOM. You can do the same with your own DOM traversal functions and by setting the style properties if you like.

function hidelink(ctl) {
    var myDiv = $(ctl).closest('div');
    myDiv.hide();
    myDiv.next('div').show();
}

function showlink(ctl){
    var myDiv = $(ctl).closest('div');
    myDiv.hide();
    myDiv.prev('div').show();
}
tvanfosson
You've got my attention, but I get an object expected error. And though you are missing the ctl parameter in the showlink, I did catch it and put it in my showlink function eg. showlink(ctl). What am i missing?
Eric
Are you using jQuery -- my example depends on jQuery being loaded. If you aren't using jQuery, you'll need to rewrite the functions to find the relative DOM elements using whatever framework/native javascript you are using.
tvanfosson
I'm not really as familiar with jquery. I have used it....but very little. What do you mean by having Jquery loaded? how would I do that?
Eric
I am able to use Jquery if that is what you mean. i can do a window.onload = function() { alert("welcome"); } So I assume jquery is loading fine. Am I right?
Eric
Nope. Your function is only using javascript. jQuery != javascript. jQuery is a framework built with javascript that allows you more convenient ways of manipulating the DOM. You'd need something like <script type="text/javascript" src="..../jquery-1.3.2.js"></script> to load jquery before using the referenced code.
tvanfosson
I see what you mean. I did have that. except i had "/js/jquery-1.2.6.js" My issue is that it doesn't see to like $(ctl).closest('div');I'm getting object expected. +1 for your help thus far!
Eric
Closest is new in 1.3.2. You can probably use parent() in 1.2.6.
tvanfosson
Right. Shouldn't something like this work?var myDiv = $(ctl).parent().get(0).tagName;
Eric
You should be able to do show/hide without getting the actual element. Those functions operate on the jQuery object.
tvanfosson