Jquery – ASP.NET + jQuery + Dynamically Created HyperLink controls

asp.netjquery

I have an ASP.NET application that uses jQuery. My ASP.NET application dynamically generates some HyperLink elements based on some values in a database. When a user clicks one of these HyperLink elements, I want to display a jQuery dialog box that allows the user to edit the text of the HyperLink. I have this part working.

When a user clicks the "Save" button, I need to read the values of the HyperLink elements and save them back to the database. Currently, I get the initial values of the HyperLink elements. However, I cannot get any modified values. How do I get the values that were provided by the user? I have provided my .aspx and .aspx.cs code here:

test

Report:

    <div id="recommendDialog" title="Number">
        <table border="0" cellpadding="0" cellspacing="0">
            <tr><td>Number</td></tr>
            <tr><td><input id="optionName" type="text" /></td></tr>
        </table>
    </div>

    <asp:Button ID="saveButton" runat="server" Text="Save" OnClick="saveButton_Click" />
</div>
</form>    

<script type="text/javascript">
    var editingID = null;

    $("#recommendDialog").dialog({
        autoOpen: false,
        height: 200,
        modal: true,
        buttons: {
            Cancel: function() {
                $(this).dialog('close');
            },

            'OK': function() {
                var newValue = $("#optionName").val();
                if (editingID != null) {
                    $(editingID).attr("name", newValue);
                    $(editingID).html(newValue);
                }
                $(this).dialog('close');
            }
        },
        close: function() {

        }
    });

    function update_Click(link) {
        editingID = "#" + link.id;
        $("#optionName").val(link.name);
        $('#recommendDialog').dialog('open');            
    }
</script>

Here is my code-behind:

public partial class _Default : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
AddHyperlinks();
}

protected void Page_Load(object sender, EventArgs e)
{}

protected void saveButton_Click(object sender, EventArgs e)
{
    foreach (TableCell cell in reportTable.Rows[0].Cells)
    {
        HyperLink h = (HyperLink)(cell.Controls[0]);
        string newValue = h.Attributes["name"];

        // Save value to database here. newValue does not show 
        // changed values.
        Console.WriteLine(newValue); 
    }
}

private void AddHyperlinks()
{
    TableRow row = new TableRow();
    for (int i = 1; i < 11; i++)
    {
        HyperLink hyperlink = new HyperLink();
        hyperlink.NavigateUrl = "#";
        hyperlink.Text = i.ToString();
        hyperlink.Attributes.Add("id", "h" + i);
        hyperlink.Attributes.Add("name", i.ToString());
        hyperlink.Attributes.Add("onclick", "update_Click(this);");
        AddLinkButtonToRow(hyperlink, row);
    }
    reportTable.Rows.Add(row);
}

private void AddLinkButtonToRow(HyperLink linkButton, TableRow row)
{
    TableCell cell = new TableCell();
    cell.Controls.Add(linkButton);
    row.Cells.Add(cell);
}

}

Best Answer

What you're trying to do isn't possible that way. You create links every time the page is created. Although you change the name of these links in JavaScript, these values are not posted back to you.
On Sumbit, only form elements get posted back to the server (<input>s, for example), not <a> elements, so your server doesn't "know" the changes were made.

Secondly, even if you'll change the <a>s to <input>s, you still have a problem: you won't be able to find these values in reportTable.Rows[0].Cells as you expect. Normally asp.net will fill these values correctly, even for dynamically generated controls, but not here - since you've changed their names! Asp.net cannot rebind these values.

So, what should you do? One option is to add an hidden field to every cell.
On AddLinkButtonToRow, add the following:

HtmlInputHidden hidden = new HtmlInputHidden();
hidden.ID = "hidden" + linkButton.ID;
hidden.Name = hidden.ID; //so it will be posted!
hidden.Style["display"] = "none"; //better to have a CssClass

Using jQuery, which you seem to know, change the values of these input fields, not their names (something like $(editingID).parent().find(":hidden")).

Next, you might not see the values on the controls, but you can find them at Request.Form["hiddenh1"] ... Request.Form["hiddenh11"] - All input fields will names will be posted, and you know their names this time.