locked
Repeater and dynamic content RRS feed

  • Question

  • User517361227 posted

    Hello all,

    I have a web form where I am using Repeater. I need to add options dynamically which would get saved on form submit.

    If it is about just adding new items with (in edit mode) or without (in create mode) repeater then it works fine but I may need to remove some items as well and save them again.

    To avoid checking for options within Repeater and dynamically added items using Request.Form[""] I am trying to do with just Request.Form[""] approach, and it works well until I remove any option from existing options list. If I delete then in code behind I get just first option and rest are null no matter at what index I remove option from.

    Please check my code sample below
    Page

    <div class="row item-options">
            <div class="col-xs-12">
                <section class="panel">
                    <header class="panel-heading">
                        <h2 class="panel-title">Add/Edit Options</h2>
                    </header>
                    <div class="panel-body">
                        <div class="form-horizontal form-bordered">
                            <asp:Panel ID="pnlItemOptions" CssClass="options" runat="server">
                                <asp:Repeater ID="rptOptions" runat="server">
                                    <ItemTemplate>
                                        <div class="item-opt">
                                            <div class="form-group">
                                                <div class="col-md-9">
                                                    <asp:TextBox ID="txtOption" runat="server" Text='<%# Eval("Option") %>' CssClass="form-control" TextMode="MultiLine"></asp:TextBox>
                                                </div>
                                                <div class="col-md-3">
                                                    <input id="btnRemove" class="btn btn-warning btnRemove" type="button" value="Remove" />
                                                </div>
                                            </div>
                                        </div>
                                    </ItemTemplate>
                                </asp:Repeater>
                            </asp:Panel>
                            <div class="item-opt add-opt" style="display: none;">
                                <div class="form-group">
                                     <div class="col-md-9">
                                        <textarea name="ctl00$ContentPlaceHolder1$rptOptions$ctl00$txtOption" id="txtOption" class="form-control"></textarea>
                                    </div>
                                    <div class="col-md-3">
                                        <input id="btnRemove" class="btn btn-warning btnRemove" type="button" value="Remove" />
                                    </div>
                                </div>
                            </div>
                            <div class="form-group">
                                <div class="col-md-6 col-md-offset-3">
                                    <asp:HiddenField ID="hdnCount" runat="server" Value="0" />
                                    <input id="addMore" class="btn btn-default" type="button" value="Add option" />
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </div>
        </div>

    <div class="row">
            <div class="col-lg-12">
                <section class="panel">
                    <div class="panel-footer">
                        <div class="row">
                            <div class="form-group">
                                <div class="col-md-6 col-md-offset-3">
                                    <asp:Button ID="btnSave" runat="server" Text="Save" CssClass="btn btn-primary saveData" OnClick="btnSave_Click" ValidationGroup="Save" />
                                    <asp:Button ID="btnCancel" runat="server" Text="Cancel" CssClass="btn btn-default" PostBackUrl="~/Manage/Items.aspx" />
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </div>
        </div>

    In above code I have regular Repeater so that I can show existing options on web form and a hidden div with Add More button which will be cloned and appended to panel.
    I am renaming textarea's name attribute and finding that control in code behind with same name

    Below is jQuery code which clones the hidden div and updates the name of textarea.

    <script type="text/javascript">
     $(document).ready(function () {
                $('#addMore').click(function () {
                        var opt = $(".add-opt").clone();
                        $(opt).show().removeClass('add-opt');
    
                        $(opt).find('span').text(i);
                        $(".options").append(opt);
                    }
                });
    
                //remove item options
                
                $(".item-options").on('click', '.btnRemove', function () {
                    $(this).closest("div.item-opt").remove();
                });
    
                $(".saveData").click(function () {
                        var i = 0;
    
                        $(".item-opt").each(function () {
                            i++;
                            $(this).find("textarea, input[type='text'], input[type='checkbox']").each(function () {
                                $(this).attr({
                                    'id': function (_, id) { return id + "_" + i },
                                    'name': function (_, name) { return name + "_" + i }
                                });
                            });
                        });
                        $("#<%= hdnCount.ClientID %>").val(i);
                    });
    </script>

    So in above code I have both Add more and remove code feature.
    On click of Remove I am removing item from DOM
    On click of Save button I am updating name of every textarea in every item element (existing or newly added)
    If I do not click on Remove to delete items then it works fine (it saves every item) but if I am removing any item at any index then it gives me just 1st item in code behind and rest are null

    Below is my code behind

    int totalOptions = Convert.ToInt32(hdnCount.Value);
                        for (int i = 1; i <= totalOptions; i++)
                        {
    
                            if (!string.IsNullOrWhiteSpace(Request.Form["ctl00$ContentPlaceHolder1$rptOptions$ctl00$txtOption_" + i.ToString()]))
                            {
                                string option = Request.Form["ctl00$ContentPlaceHolder1$rptOptions$ctl00$txtOption_" + i.ToString()];
                            
                        }


    Can anybody please tell me what wrong could be going on and what is solution to fix this.

    Many thanks

    Wednesday, October 25, 2017 4:27 PM

Answers

  • User-707554951 posted

    Hi  vinod_praviram

    I use the following code to produce your problem.

    I find reason for you problem,

    When you remove a item from repeater. The key name in Request.Form will be change.

    You could check the following example for understanding:

     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script>
            $(document).ready(function () {
                $('#addMore').click(function () {
                    var opt = $(".add-opt").clone();
                    $(opt).show().removeClass('add-opt');
    
                    $(opt).find('span').text(i);
                    $(".options").append(opt);
                });
                 $(".item-options").on('click', '.btnRemove', function () {
                $(this).closest("div.item-opt").remove();
            });
    
            $(".saveData").click(function () {
                var i = 0;
                $(".item-opt").each(function () {
                    i++;
                    $(this).find("textarea, input[type='text'], input[type='checkbox']").each(function () {
                        $(this).attr({
                            'id': function (_, id) { return id + "_" + i },
                            'name': function (_, name) { return name + "_" + i }
                        });
                    });
                });
                $("#<%= hdnCount.ClientID %>").val(i);
                });
                });
    
            //remove item options
                
           
    
        </script>
      <div class="row item-options">
                <div class="col-xs-12">
                    <section class="panel">
                        <header class="panel-heading">
                            <h2 class="panel-title">Add/Edit Options</h2>
                        </header>
                        <div class="panel-body">
                            <div class="form-horizontal form-bordered">
                                <asp:Panel ID="pnlItemOptions" CssClass="options" runat="server">
                                    <asp:Repeater ID="rptOptions" runat="server">
                                        <ItemTemplate>
                                            <div class="item-opt">
                                                <div class="form-group">
                                                    <div class="col-md-9">
                                                        <asp:TextBox ID="txtOption" runat="server" Text='<%# Eval("Option") %>' CssClass="form-control" TextMode="MultiLine"></asp:TextBox>
                                                    </div>
                                                    <div class="col-md-3">
                                                        <input id="btnRemove" class="btn btn-warning btnRemove" type="button" value="Remove" />
                                                    </div>
                                                </div>
                                            </div>
                                        </ItemTemplate>
                                    </asp:Repeater>
                                </asp:Panel>
                                <div class="item-opt add-opt" style="display:none">
                                    <div class="form-group">
                                        <div class="col-md-9">
                                            <textarea name="rptOptions$ctl04$txtOption" id="rptOptions$ctl04$txtOption" class="form-control"></textarea>
                                        </div>
                                        <div class="col-md-3">
                                            <input id="btnRemove" class="btn btn-warning btnRemove" type="button" value="Remove" />
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <div class="col-md-6 col-md-offset-3">
                                        <asp:HiddenField ID="hdnCount" runat="server" Value="0" />
                                        <input id="addMore" class="btn btn-default" type="button" value="Add option" />
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                </div>
            </div>
    
            <div class="row">
                <div class="col-lg-12">
                    <section class="panel">
                        <div class="panel-footer">
                            <div class="row">
                                <div class="form-group">
                                    <div class="col-md-6 col-md-offset-3">
                                        <asp:Button ID="btnSave" runat="server" Text="Save" CssClass="btn btn-primary saveData" OnClick="btnSave_Click" ValidationGroup="Save" />
                                        <asp:Button ID="btnCancel" runat="server" Text="Cancel" CssClass="btn btn-default" PostBackUrl="~/Manage/Items.aspx" />
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                </div>
            </div>

    Codebehind:

      protected void Page_Load(object sender, EventArgs e)
            {
                DataTable dt = new DataTable();
                dt.Columns.AddRange(new DataColumn[4] { new DataColumn("Id"), new DataColumn("Group"), new DataColumn("Name"), new DataColumn("Option") });
                dt.Rows.Add(1, "A", "John Hammond", "United States");
                dt.Rows.Add(2, "B", "Mudassar Khan", "India");
                dt.Rows.Add(3, "A", "Suzanne Mathews", "France");
                dt.Rows.Add(4, "B", "Robert Schidner", "Russia");
                rptOptions.DataSource = dt;
                rptOptions.DataBind();
    
            }
    
            protected void btnSave_Click(object sender, EventArgs e)
            {
                string[] keys = Request.Form.AllKeys;
    
                for (int i = 0; i < keys.Length; i++)
                {
                    if (keys[i].Contains("txtOption")) { 
                    string key = keys[i];
                    Response.Write(keys[i] + ": " + Request.Form[keys[i]] + "<br>");
                    }
                }

    //just use above code int totalOptions = Convert.ToInt32(hdnCount.Value); Response.Write(totalOptions); for (int i = 1; i <= totalOptions; i++) { if (!string.IsNullOrWhiteSpace(Request.Form["rptOptions$ctl0" + (i - 1).ToString() + "$txtOption_" + i.ToString()])) { string option = Request.Form["rptOptions$ctl0" + (i - 1).ToString() + "$txtOption_" + i.ToString()]; Response.Write(option); } } }

    Output:

    Best Regards

    Cathy

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, October 26, 2017 9:42 AM

All replies

  • User-707554951 posted

    Hi  vinod_praviram

    I use the following code to produce your problem.

    I find reason for you problem,

    When you remove a item from repeater. The key name in Request.Form will be change.

    You could check the following example for understanding:

     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script>
            $(document).ready(function () {
                $('#addMore').click(function () {
                    var opt = $(".add-opt").clone();
                    $(opt).show().removeClass('add-opt');
    
                    $(opt).find('span').text(i);
                    $(".options").append(opt);
                });
                 $(".item-options").on('click', '.btnRemove', function () {
                $(this).closest("div.item-opt").remove();
            });
    
            $(".saveData").click(function () {
                var i = 0;
                $(".item-opt").each(function () {
                    i++;
                    $(this).find("textarea, input[type='text'], input[type='checkbox']").each(function () {
                        $(this).attr({
                            'id': function (_, id) { return id + "_" + i },
                            'name': function (_, name) { return name + "_" + i }
                        });
                    });
                });
                $("#<%= hdnCount.ClientID %>").val(i);
                });
                });
    
            //remove item options
                
           
    
        </script>
      <div class="row item-options">
                <div class="col-xs-12">
                    <section class="panel">
                        <header class="panel-heading">
                            <h2 class="panel-title">Add/Edit Options</h2>
                        </header>
                        <div class="panel-body">
                            <div class="form-horizontal form-bordered">
                                <asp:Panel ID="pnlItemOptions" CssClass="options" runat="server">
                                    <asp:Repeater ID="rptOptions" runat="server">
                                        <ItemTemplate>
                                            <div class="item-opt">
                                                <div class="form-group">
                                                    <div class="col-md-9">
                                                        <asp:TextBox ID="txtOption" runat="server" Text='<%# Eval("Option") %>' CssClass="form-control" TextMode="MultiLine"></asp:TextBox>
                                                    </div>
                                                    <div class="col-md-3">
                                                        <input id="btnRemove" class="btn btn-warning btnRemove" type="button" value="Remove" />
                                                    </div>
                                                </div>
                                            </div>
                                        </ItemTemplate>
                                    </asp:Repeater>
                                </asp:Panel>
                                <div class="item-opt add-opt" style="display:none">
                                    <div class="form-group">
                                        <div class="col-md-9">
                                            <textarea name="rptOptions$ctl04$txtOption" id="rptOptions$ctl04$txtOption" class="form-control"></textarea>
                                        </div>
                                        <div class="col-md-3">
                                            <input id="btnRemove" class="btn btn-warning btnRemove" type="button" value="Remove" />
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <div class="col-md-6 col-md-offset-3">
                                        <asp:HiddenField ID="hdnCount" runat="server" Value="0" />
                                        <input id="addMore" class="btn btn-default" type="button" value="Add option" />
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                </div>
            </div>
    
            <div class="row">
                <div class="col-lg-12">
                    <section class="panel">
                        <div class="panel-footer">
                            <div class="row">
                                <div class="form-group">
                                    <div class="col-md-6 col-md-offset-3">
                                        <asp:Button ID="btnSave" runat="server" Text="Save" CssClass="btn btn-primary saveData" OnClick="btnSave_Click" ValidationGroup="Save" />
                                        <asp:Button ID="btnCancel" runat="server" Text="Cancel" CssClass="btn btn-default" PostBackUrl="~/Manage/Items.aspx" />
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                </div>
            </div>

    Codebehind:

      protected void Page_Load(object sender, EventArgs e)
            {
                DataTable dt = new DataTable();
                dt.Columns.AddRange(new DataColumn[4] { new DataColumn("Id"), new DataColumn("Group"), new DataColumn("Name"), new DataColumn("Option") });
                dt.Rows.Add(1, "A", "John Hammond", "United States");
                dt.Rows.Add(2, "B", "Mudassar Khan", "India");
                dt.Rows.Add(3, "A", "Suzanne Mathews", "France");
                dt.Rows.Add(4, "B", "Robert Schidner", "Russia");
                rptOptions.DataSource = dt;
                rptOptions.DataBind();
    
            }
    
            protected void btnSave_Click(object sender, EventArgs e)
            {
                string[] keys = Request.Form.AllKeys;
    
                for (int i = 0; i < keys.Length; i++)
                {
                    if (keys[i].Contains("txtOption")) { 
                    string key = keys[i];
                    Response.Write(keys[i] + ": " + Request.Form[keys[i]] + "<br>");
                    }
                }

    //just use above code int totalOptions = Convert.ToInt32(hdnCount.Value); Response.Write(totalOptions); for (int i = 1; i <= totalOptions; i++) { if (!string.IsNullOrWhiteSpace(Request.Form["rptOptions$ctl0" + (i - 1).ToString() + "$txtOption_" + i.ToString()])) { string option = Request.Form["rptOptions$ctl0" + (i - 1).ToString() + "$txtOption_" + i.ToString()]; Response.Write(option); } } }

    Output:

    Best Regards

    Cathy

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, October 26, 2017 9:42 AM
  • User517361227 posted

    Hi Cathy,

    Thank you so much for your reply and efforts you have put in demo.
    You made it clear and pointed out the exact issue.
    Now I have renamed all name attributes to txtOptions_i.ToString() and in code behind now I can use easily Request.Form("") in for loop, and it is working fine.

    Just 1 more query, is it possible to find element by partial name from Request.Form() collection ?
    Like if I wish to use fully qualified name of option textbox which is preceded by repeater name and just find that element using something like Contains txtOption within Request.Form("") ?

    Thanks
    Vinod K.

    Thursday, October 26, 2017 5:37 PM
  • User-707554951 posted

    Hi  vinod_praviram,

    is it possible to find element by partial name from Request.Form() collection ?

    string[] keys = Request.Form.AllKeys;
    
                for (int i = 0; i < keys.Length; i++)
                {
                    if (keys[i].Contains("txtOption")) { 
                    string key = keys[i];
                    Response.Write(keys[i] + ": " + Request.Form[keys[i]] + "<br>");
                    }
                }

    When you want to get a data summit by form by using Request.Form(), You must provided fully qualified name.

    However, you could filter the data by using keys[i].Contains("txtOption"). Then you could use the filtered key to get summit data in if statement.

    Best Regards

    Cathy

    Friday, October 27, 2017 1:35 AM
  • User517361227 posted

    Hi Cathy,

    Thanks for clarifying this, but this will not work in my case as I have more controls with Option textbox which I need to consider as part of single repeater item and hence finding element at index would not work in my case, so I would stick with first approach as I did in last post based on your suggestion.

    Once again thanks a lot :)

    Wednesday, November 1, 2017 6:19 PM