简体   繁体   中英

Creating dynamic id for textbox in repeater

So I am getting information from DB and using it in an ASP repeater to get a table.

    <asp:Repeater ID="repS" runat="server">
                        <ItemTemplate>
                                            <a class="card-title text-secondary" href="#">
                                                <%#Eval("FirstName") %>
                                                <%#Eval("LastName") %> 
                                            (<%#Eval("Id")%>)
                                            </a>
                                            <asp:DropDownList ID="reasonStd<%#Eval("Id")%>" runat="server">
                                                <asp:ListItem Enabled="true" Text="Select Month" Value="-1"></asp:ListItem>
                                                <asp:ListItem Text="1" Value="1"></asp:ListItem>
                                                <asp:ListItem Text="2" Value="2"></asp:ListItem>
                                                <asp:ListItem Text="3" Value="3"></asp:ListItem>
                                                ...
                                            </asp:DropDownList>
                                            <span>

It can go as long as 10 options. Now I want to choose an option (id=reasonStd) and I use a button to save each option in the DB, but I do not get how can I get each id for each item in the repeater.

When I inspect the code I can see the dropdownlist creates it just fine in the front end (reasonStd1248, reasonStd2371), but can't find a way to call it and save it to the DB (I already have the method tested and running). I tried something like...

foreach (objetType obj in DataSource)
            {
                saveObject(obj, reasonStd+obj.Id+.Text.SelectedValue);
            }

Ok, then, the issue is the nulls twisting things up.

(and I agree this is a probelm + challenge).

So, shoving back the values - in general not a issue. And be it a text box, check box etc. - then again no real issues.

However, the combo box has two problems. Often the list we feed it does NOT have a blank (no choice), and MUCH WORSE is we can't feed it a null value from the database DOUBLE WORSE!!!

Now your droplist (combo) is filled with a static list. But it could VERY well be filled with a data table. I'll post a example with a data table driving our "items" (the repeater), and then also include a dropdown list that ALSO is from a table of choices.

so, say the markup is like this:

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <div style="border-style:solid;color:black;width:250px;float:left">

        <div style="padding:5px;text-align:right">
            Hotel Name: <asp:TextBox ID="txtHotelName" runat="server" Text ='<%# Eval("HotelName") %>' Width="130px" />
            <br />
            First Name: <asp:TextBox ID="txtFirst" runat="server" Text ='<%# Eval("FirstName") %>'  Width="130px" />
            <br />
            Last Name: <asp:TextBox ID="txtLast" runat="server" Text ='<%# Eval("LastName") %>'  Width="130px" />
            <br />
            City : <asp:DropDownList ID="cboCity" runat="server" DataTextField="City" 
                DataValueField="City" Width="130px">
                </asp:DropDownList>
            <br />
            Active: <asp:CheckBox ID="chkActive" runat="server" Checked = '<%# Eval("Active") %>'/>
        </div>
    </div>

    </ItemTemplate>

</asp:Repeater>

So, in above, we have a some text boxes, a drop down, and a check box.

YOu can see that we fill these controls with Eval().

So, the code to fill the repeater looks like this:

public void LoadGrid()
{

// load up our drop down list from database
string strSQL;
strSQL = "SELECT City from tblCity Order by City";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
    cmdSQL.Connection.Open();
    rstCity.Load(cmdSQL.ExecuteReader);
}

// now load up our repeter

strSQL = "SELECT ID, FirstName, LastName, HotelName, City, Active from tblHotels ORDER BY HotelName";

using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
    cmdSQL.Connection.Open();
    rstTable.Load(cmdSQL.ExecuteReader);

    Repeater1.DataSource = rstTable;
    Repeater1.DataBind();
}
}

Ok, the above is now working. You will NOTE very carefull that I delcare both the rstHotels datatable at the class level, since we need it later. And in my case, since my droplist does NOT have a static/fixed source like yours, then above also loads that up.

the result is this:

在此处输入图像描述

You will note in above, we have a save button. The save button code does this:

Send data from repeater BACK TO THE SAME table that filled the repeater. (yes, we do and did persist that table in Session().

So, the code is really simple - and not a lot of code:

protected void cmdSave_Click(object sender, EventArgs e)
{

// pull repeater rows back to table.

foreach (RepeaterItem rRow in Repeater1.Items)
{
    int RecordPtr = rRow.ItemIndex;
    DataRow OneDataRow;

    OneDataRow = rstTable.Rows(RecordPtr);

    OneDataRow.Item("HotelName") = rRow.FindControl("txtHotelName") as TextBox.Text;
    OneDataRow.Item("FirstName") = rRow.FindControl("txtFirst") as TextBox.Text;
    OneDataRow.Item("LastName") = rRow.FindControl("txtLast") as TextBox.Text;
    OneDataRow.Item("City") = rRow.FindControl("cboCity") as DropDownList.Text;
    OneDataRow.Item("Active") = rRow.FindControl("chkActive") as CheckBox.Checked;
}

// now send table back to database with updates
string strSQL = "SELECT ID, FirstName, LastName, City, HotelName, Active from tblHotels WHERE ID = 0";

using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
    cmdSQL.Connection.Open();
    SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
    SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);

    daupdate.Update(rstTable);
}
}

And a FYI: While gridview, listview and probably a DOZEN more controls? If you don't drop in or have a alternatving template, then you don't worry and don't bother. The repeater ocntrol is one of those exceptions. (you as per above have to test for both a item row, and the alternative row - I have no idea why - but you MUST do this - don't leave that alternative row check out).

Ok, so all the above does is loop the repeater, and send the values back to the table. And then we take the table, and execute a SINGLE.update command.

So, the ONLY real issue now is to deal with the null drop down list.

You deal with that issue in the itemdata bound event. Say like this:

protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{

// set combo box data source
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{

    // setup drop down list
    // 
    int ix = e.Item.ItemIndex;
    DropDownList cboDrop = e.Item.FindControl("cboCity");
    cboDrop.DataSource = rstCity;
    cboDrop.DataBind();
    cboDrop.Items.Insert(0, new ListItem(string.Empty));     // add blank row

    if (IsDBNull(rstTable.Rows(ix).Item("City")) == false)
        cboDrop.Text = rstTable.Rows(ix).Item("City");
    else
        cboDrop.Text = "";
}
}

Now in YOUR code? You can skip the fill + data bind, but note that last bit - the test/check for nulls. And ALSO note how I added a extra BLANK selection in the drop list. You need that blank extra choice, since many of the rows of data may VERY well not yet have a selected value. And you can't shove in null, and you can't shove in a exmpty string UNTILL such time that allowing blank empty string option is ADDED to the drop down ist. Now in your case, since it is hard code - then you could add the extra blank choice in your markup - I could not, since my drop list was database driven.

As noted, I did and do persist the data table that drives the whole mess and I did this for easy sending back to the database. You could re-pull or create a blank datatable (select id = 0, and then do add rows, but given that the data sets are only about say 20-40 items, then persisting the data table is not a large strain on the session() system.

So, the first page post-back load looks like this:

private DataTable rstTable = new DataTable();
private DataTable rstCity = new DataTable();

protected void Page_Load(object sender, System.EventArgs e)
{
    if (System.Web.UI.Page.IsPostBack == false)
    {
        LoadGrid();
        System.Web.UI.Page.Session["MyTable"] = rstTable;
        System.Web.UI.Page.Session["MyCity"] = rstCity;
    }
    else
    {
        rstTable = System.Web.UI.Page.Session["MyTable"];
        rstCity = System.Web.UI.Page.Session["MyCity"];
    }
}
}

So above is how I persited the table, and our tblCity for the drop down list (which you don't have).

So, you have to catch + set the dropdown list on itemdata bound. You could perahps NOT have to do this if you in the markup were to just set the dropdown list

eg:

Text = '<%# Eval("City") %>'

But, the above fails for me, since some columns don't have a value yet, and the combo box gets rather mad/nasty when you attempt to set/use values that don't exist. And toss nulls on top that - it gets even worse. So, I in itemdatabound have to fill the dropdown list for each "repeating" item, and I thus also have to add the blank row choice to the dropdown. I then check for null, and shove in a blank (empty string), or the value.

Note that if you look close, the above posted code will thus result in emptry strings for text boxes and values that were null. You can freely assign a null.Item() from the data row to a text box, but you can't set Text from dropdown list to null - hence we used itematabound to setup our dropdown list.

In theory, the update code should test/check for empty strings, and save back a "null" to the database if that is your current convention. (ie: either no nulls and empty strings, or nulls and no empty strings). So, one should stick to which ever convention you have now.

As noted, you don't have to fill the drop list in itemdata bound, but you DO HAVE to deal with the null values check - and as noted the code that adds that extra dropdown choice (blank one) could also be skipped by you, and simply added to your hard coded list of choices you have. But you still have to deal with the null - and I above simply check for a null row value, and shove in a empty string for this to work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM