Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are commas inserted when innerHTML is copied after Postback?

This case is going to sound complicated, but it's not that bad. The javascript at the end of this code seems to be sound.

EDIT: Here's the page running on a live server. The first example doesn't alternate between open and closed because I ripped out a lot of code in order to narrow the example down as much as I could.

http://69.64.80.239/tmp/borked2.aspx

There are two cases listed in the following client code. The first case posts back when an imagebutton is clicked, and adds a call to the large javascript function, using the clientid of the imagebutton as the argument.

The second case simply uses an onClientClick, and executes the javascript without a postback.

Both methods accomplish the display and hiding of the textbox that should appear. However, with the postback method, commas are inserted every time you go back and forth - first 1 then 3 then 7 then 15 then 31. This odd behaviour does not occur with case #2, which makes me believe that the javascript in this case is sound.

When the postback occurs, a 'value=","' attribute appears in my textbox that was not there before. the increasing numbers of commas fit into the newly added attribute.

This case is extremely stripped down so as to highlight the problem effectively. Ultimately this is causing a detailsview I am performing the same copy on to add a comma to the beginning of every form value that it submits.

I'm completely stumped, so I'm just going to post the code as well as I can! Any ideas would be appreciated!

<h5>CASE 1: Using Serverside postback to insert Javascript into a Literal</h5>
<table><tr><td>

    <asp:ImageButton id="CollapseExpand" runat="server" ImageUrl="/images/plus.gif" src="/images/plus.gif"
        AlternateText="Hide Tasks" Width="12" Height="12"  onclick="CollapseExpand_Click"
        />

     <div style="display:none">
     <asp:TextBox runat="server" ID="Textbox1"></asp:TextBox>
     <asp:Button runat="server" ID="btnSubmit1" Text="Submit 1" />
     </div>

    <asp:Literal runat="server" ID="ScriptAnchorTest"></asp:Literal>     

</td></tr></table>

CASE 1 Codebehind

protected void CollapseExpand_Click(object sender, ImageClickEventArgs e)
{

    Literal l = (Literal)this.ScriptAnchorTest;
    l.Text = "<script type=\"text/javascript\">Expand(document.getElementById('" + this.CollapseExpand.ClientID + "'));</script>";

}


CASE 2: Executing Javascript Clientside directly

    <asp:ImageButton id="CollapseExpand2" runat="server" src="/images/plus.gif" 
        AlternateText="Hide Tasks" Width="12" Height="12"  onClientClick="Expand(this); return false;"
        />

     <div style="display:none">
     <asp:TextBox runat="server" ID="TextBox2"></asp:TextBox>
     <asp:Button runat="server" ID="btnSubmit2" Text="Submit 2" />
     </div>

</td></tr></table>    

// The Javascript Function function Expand(image, index) { // get the source of the image var src = image.getAttribute("src");

    // if src is currently "plus.", then toggle it to "minus.png"    
    if (src.indexOf("plus") > 0) {

        //  toggle the  image
        image.src = image.src.replace("plus", "minus");

        var tr = image.parentNode.parentNode;
        // Get a reference to the next row from where the image is
        var next_tr = tr.nextSibling;

        // Get a refernece to the <tbody> tag of the grid
        var tbody = tr.parentNode;

        // Get a reference to the image's column
        var td = image.parentNode;
        var detailnode

        //loop through the content of the image's column. if hidden div is found, get a reference
        for (var j = 0; j < td.childNodes.length; j++) {
            if (td.childNodes[j].nodeType == 1) {
                if (td.childNodes[j].nodeName.toLowerCase() == 'div') {
                    detailnode = td.childNodes[j].cloneNode(true);
                }
            }
        }

        // Create a new table row for "Expand"  
        var newtr = document.createElement('tr');
        var newtd = document.createElement('td');
        var newfirsttd = newtd.cloneNode(true);

        /* insert an empty cell first */
        newtr.appendChild(newfirsttd);
        newtd.colSpan = 8;

        // insert the  hidden div's content  into the new row
        newtd.innerHTML = detailnode.innerHTML;


        newtr.appendChild(newtd);
        tbody.insertBefore(newtr, next_tr);

        tr.className = "selected";
    }


    else {
        image.src = src.replace("minus", "plus");
        var row = image.parentNode.parentNode;
        var rowsibling = row.nextSibling;
        var rowparent = row.parentNode;
        rowparent.removeChild(rowsibling);
    }
like image 313
Andrew Edvalson Avatar asked Dec 31 '22 07:12

Andrew Edvalson


2 Answers

I don't have time to read your entire code, but please pay attention to the following: you may be copying a HTML chunk and creating a clone of it in your code. This way, you actually get two textboxes with the same Id, although you see only one of them. At postback, the browser concatenates the values as a comma-separated list. For example, if you enter "Test1" and "Test2" in the textboxes, respectively, and then submit, both textboxes get the value doubled. Now, if you only expand one of them (the first, let's say), and submit, only the expanded one gets doubled again, while the one not expanded stays the same over postbacks.

For a solution, if you only need to show or hide a div, the best way is to do it from javascript, client side, by changing the style (visibility) of that div, and not by cloning it. This way, your function could be reduced to one line of code.

like image 173
Sergiu Damian Avatar answered Jan 01 '23 19:01

Sergiu Damian


Sergiu is right, you are creating two html input with the same ID "Textbox1" as you can see in the screenshot captured using Firebug

Stackoverflow Answer

This ends up concatenating the two values separated by a comma.

like image 31
Eduardo Molteni Avatar answered Jan 01 '23 19:01

Eduardo Molteni