I'm loading a repeater with data and then on a button click i'm trying to save the data.
Heres what I have but the tbDate.text or tbAmount.texts are always being reported back as "" instead of the values.
<asp:Repeater runat="server" ID="rptInstallments" OnItemDataBound="rptInstallments_ItemDataBound">
<ItemTemplate>
<div class="form-group">
<label class="control-label">Installment Amount</label>
<div class="controls">
<asp:TextBox runat="server" ID="txtAmount" CssClass="form-control"></asp:TextBox>
</div>
</div>
<div class="form-group">
<label class="control-label">Installment Date</label>
<div class="controls">
<asp:TextBox runat="server" ID="txtDate" CssClass="form-control datepicker"></asp:TextBox>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
Heres the backend code:
protected void btGo_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in rptInstallments.Items)
{
TextBox tbDate = item.FindControl("txtDate") as TextBox;
TextBox tbAmount = item.FindControl("txtAmount") as TextBox;
String myAmount = tbAmount.Text;
String myDate = tbDate.Text;
var rInstall = dtInstall.NewSubPIDInstallmentsRow();
rInstall.SPID = SPID;
rInstall.InstallmentAmount = Convert.ToDecimal(myAmount);
rInstall.InstallmentDue = Convert.ToDateTime(myDate);
dtInstall.AddSubPIDInstallmentsRow(rInstall);
taInstall.Update(dtInstall);
}
}
EDIT
I'm hacking in the repeater to no real data source. Could this be the problem?
int[] RowCount = new int[numberOfInstallments];
rptInstallments.DataSource = RowCount;
rptInstallments.DataBind();
Add your code of Binding the Repeater control with in the if (!IsPostBack) condition of Page_load. This worked for me.
Related
I'm having issues with dynamically updating a drop down list control when it is inside a repeater.
Basically I have a repeater and inside that repeater are 2 drop down lists. The one list is defined in my aspx page, the other drop down list is inside an update panel where I want to be able to have it dynamically update based on the selection of the first drop down list. I think part of my problem is the updatepanel is getting confused because I have more than one repeater item?
Here is the code for my repeater:
<asp:Repeater ID="billingTemplate" runat="server" OnItemDataBound="template_ItemDataBound">
<ItemTemplate>
<tr style="font-size: 100%" runat="server">
<td colspan="4" style="width: 100%; vertical-align: top">
<div class="panel panel-default panel-billing">
<asp:Panel CssClass="row panel-heading panel-heading-billing text-left" ID="headingBilling" ClientIDMode="Static" runat="server">
<div class="col-xs-1">
<input type="hidden" id="templateUK" runat="server" value='<%#Eval("templateUK")%>' />
</div>
<div class="col-sm-3">
<label for="ddlInvFilterType" class="col-sm-4 control-label text-right labelCls testclass">Filter Type:</label>
<div class="col-sm-8">
<asp:DropDownList runat="server" ID="ddlInvFilterType" ClientIDMode="Static" placeholder="Choose Filter Type" CssClass="form-control smallSize FilterType" AutoPostBack="true" OnSelectedIndexChanged="ddlFilterType_SelectedIndexChanged">
<asp:ListItem Value="">- None -</asp:ListItem>
<asp:ListItem Value="RevType1">Revenue Type 1</asp:ListItem>
<asp:ListItem Value="RevType2">Revenue Type 2</asp:ListItem>
<asp:ListItem Value="RevType3">Revenue Type 3</asp:ListItem>
<asp:ListItem Value="ServiceTeams">Service Team</asp:ListItem>
</asp:DropDownList>
</div>
</div>
<asp:UpdatePanel ID="InvFilterValuePanel" ClientIDMode="Static" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false">
<ContentTemplate>
<div class="col-sm-3">
<label for="ddlInvFilterValue" class="col-sm-4 control-label text-right labelCls">Filter Value:</label>
<div class="col-sm-8">
<asp:DropDownList runat="server" ID="ddlInvFilterValue" ClientIDMode="Static" placeholder="Choose Filter Value" CssClass="col-sm-6 form-control smallSize">
<asp:ListItem Value="">- None -</asp:ListItem>
</asp:DropDownList>
</div>
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ddlInvFilterType" EventName="SelectedIndexChanged" />
</Triggers>
</asp:UpdatePanel>
</asp:Panel>
<asp:Panel CssClass="panel-collapse collapse" ID="collapseBilling" ClientIDMode="Static" runat="server">
<div class="panel-body">
<table class="table table-condensed table-bordered" style="margin: 0; padding: 0; border-top: none; border-bottom: none; border-left: thin; border-right: thin">
<tbody>
<%-- other controls --%>
</tbody>
</table>
</div>
</asp:Panel>
</div>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
Heres the code for my selected index change:
protected void ddlFilterType_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
DropDownList ddl = (DropDownList)sender;
string ddlClass = ddl.CssClass;
string[] classes = ddlClass.Split(' ');
string repeaterClass = classes[classes.Length - 1];
string repeaterID = "0";
string appendStr = "";
if (repeaterClass.Contains("templateID"))
{
repeaterID = repeaterClass.Substring(repeaterClass.Length - 1);
appendStr = "_" + repeaterID;
}
foreach (RepeaterItem item in billingTemplate.Items)
{
HtmlInputHidden hidden = item.FindControl("headingBilling").FindControl("templateUK") as HtmlInputHidden;
if (hidden.Value == repeaterID)
{
DropDownList d1 = item.FindControl("headingBilling").FindControl("ddlInvFilterType") as DropDownList;
DropDownList d2 = item.FindControl("headingBilling").FindControl("ddlInvFilterValue") as DropDownList;
if (d1.SelectedValue.Length > 0)
{
d2.Items.Clear();
d2.Items.Add(new ListItem(" - None - ", ""));
switch (d1.SelectedValue)
{
case "ServiceTeams":
foreach (var pair in serviceTeamsController.GetAllServiceTeamsLOVs())
{
if (!String.IsNullOrWhiteSpace(pair.Value))
d2.Items.Add(new ListItem(pair.Value, pair.Key));
}
break;
default:
foreach (var pair in masterController.GetMasterLOVs(filterTypeDict[d1.SelectedValue]))
{
if (!String.IsNullOrWhiteSpace(pair.Value))
{
d2.Items.Add(new ListItem(pair.Value, pair.Key));
}
}
break;
}
}
else
{
d2.Items.Clear();
d2.Items.Add(new ListItem(" - None - ", ""));
}
}
}
}
catch (Exception ex)
{
}
}
Heres a screenshot of what I'm looking at when theres more than one repeater item:
Basically whats happening now is if I update the filter type in item2 it will update the filter value in item 1. If I update the filter type in item1 it will update the filter value in item 1 as expected.
What I want is to be able to update item2 filter type and then the filter value in item 2 is updated accordingly.
Anyone have any ideas on what I could be missing?
So ended up getting this to work, I think the main issue was the clientidmode was confusing the update panel somehow, so I removed that and made the update panel go around both drop downs. I also didnt end up needing the trigger so I removed that as well.
I am creating a web aplication to access data in a SQL Server 2008 database. I show the data in a Gridview and I can succesfully edit the rows (even with DropDownLists), but I want to implement the edit of those records with a modal dialog/popup using Bootstrap.
However, I can not get working these DropDownLists in this modal, because resides in a DIV outside the <asp:GridView> element. I can bind others text fields in the modal dialog, with this code (the modal dialog is fired with a command ) [code_behind]:
if (e.CommandName.Equals("editRecord"))
{
GridViewRow gvrow = GridView2.Rows[index];
txtRUT.Text = HttpUtility.HtmlDecode(gvrow.Cells[2].Text);//.ToString();
txtDIGITO.Text = HttpUtility.HtmlDecode(gvrow.Cells[3].Text);
txtCOD_FISA.Text = HttpUtility.HtmlDecode(gvrow.Cells[4].Text);
txtNOMBRE.Text = HttpUtility.HtmlDecode(gvrow.Cells[5].Text);
//ddlCARGO is the DropDownList
ddlCARGO.Text = HttpUtility.HtmlDecode(gvrow.Cells[6].Text);
lblResult.Visible = false;
//I know that the DropDownList ist outside the GridView, but i don't know how to access/bind data to it
DropDownList combo_cargo = GridView2.Rows[index].FindControl("ddlCARGO") as DropDownList;
if (combo_cargo != null)
{
combo_cargo.DataSource = DataAccess.GetAllCargos(); //in GridView default edit mode, this works OK
combo_cargo.DataTextField = "cargo";
combo_cargo.DataValueField = "idCARGO";
combo_cargo.DataBind();
}
combo_cargo.SelectedValue = Convert.ToString(HttpUtility.HtmlDecode(gvrow.Cells[6].Text));
}
The modal html code [.aspx]:
<!-- EDIT Modal Starts here -->
<div id="editModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="editModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close"
data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="editModalLabel">Editar Empleado</h3>
</div>
<asp:UpdatePanel ID="upEdit" runat="server">
<ContentTemplate>
<div class="modal-body">
<p> Nombre: <asp:TextBox ID="txtNOMBRE" runat="server" columns="40"></asp:TextBox> </p>
<p>RUT: <asp:TextBox ID="txtRUT" runat="server" columns="8"></asp:TextBox> -
<asp:TextBox ID="txtDIGITO" runat="server" columns="1"></asp:TextBox></p>
<p>Código Fisa: <asp:TextBox ID="txtCOD_FISA" runat="server" columns="7"></asp:TextBox></p>
<%--<p>Cargo: <asp:TextBox ID="txtCARGO" runat="server" columns="7"></asp:TextBox></p>--%>
<p>Cargo: <asp:DropDownList ID="ddlCARGO" runat="server"></asp:DropDownList></p>
<%-- <p>Estado: <asp:TemplateField HeaderText="ESTADO" SortExpression="idESTADO">
<EditItemTemplate>
<asp:DropDownList ID="ddlESTADO" runat="server"></asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblESTADO" runat="server" Text='<%# Bind("ESTADO") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField> </p> --%>
</div>
<div class="modal-footer">
<asp:Label ID="lblResult" Visible="false" runat="server"></asp:Label>
<asp:Button ID="btnSave" runat="server" Text="Update" CssClass="btn btn-info" OnClick="btnSave_Click" />
<button class="btn btn-info" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="GridView2" EventName="RowCommand" />
<asp:AsyncPostBackTrigger ControlID="btnSave" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
</div>
</div>
</div>
<!-- Edit Modal Ends here -->
I can give you an idea.
Create a DIV/user control with those controls that you need to edit.
On ROW click - open the DIV in model (jq you can use) and then either pass the Row content to the Model.open Or pass some unique ID of that ROW and load again from DB the Row corresponding detail. And allow editing there and on Save over there - saving to DB with that unique ID preserved.
Let us know
Finally I have found the solution:
Modal html (.aspx):
<div class="form-group">
<asp:TextBox ID="txtCARGO" runat="server" CssClass="hiddencol"></asp:TextBox> <%--data value field (hidden with CSS)--%>
<label class="col-xs-3 control-label" for="editModalCargo">Cargo</label>
<div class="col-xs-3 input_medio">
<asp:DropDownList id="editModalCargo" runat="server" name="editModalCargo" class="form-control input-md"/> <%--data text field--%>
</div>
</div>
<div class="form-group hiddencol"> <%--field with row id (hidden with CSS)--%>
<asp:TextBox ID="txtID" runat="server" columns="2"></asp:TextBox>
</div>
I've put OnRowCommand="GridView2_RowCommand" on <asp:GridView> and created a <asp:ButtonField> with CommandName="editRecord"> to edit the row.
Code behind (.aspx.cs):
protected void GridView2_RowCommand(object sender, GridViewCommandEventArgs e)
{
int index = Convert.ToInt32(e.CommandArgument);
if (e.CommandName.Equals("editRecord"))
{
GridViewRow gvrow = GridView2.Rows[index];
txtID.Text = HttpUtility.HtmlDecode(gvrow.Cells[17].Text); //Pass value from Gridview's column to <asp:TextBox ID="txtID">
txtCARGO.Text = HttpUtility.HtmlDecode(gvrow.Cells[13].Text); //Pass value from Gridview's column to <asp:TextBox ID="txtCARGO">
lblResult.Visible = false;
BindEditCargo(txtCARGO.Text);
}
}
private void BindEditCargo(string cargoValue) //Populates <asp:DropDownList id="editModalCargo">
{
editModalCargo.DataSource = DataAccess.GetAllCargos();
editModalCargo.DataTextField = "cargo";
editModalCargo.DataValueField = "idCARGO";
// Bind the data to the control.
editModalCargo.DataBind();
// Set the default selected item, if desired.
editModalCargo.SelectedValue = cargoValue;
}
DataAccess.cs:
public static DataTable GetAllCargos()
{
DataTable dt = new DataTable();
string sql = #"SELECT * FROM CARGO";
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["BRconn"].ToString()))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
}
return dt;
}
To read the value from modal (to pass it to a Update query for example), you can use (in code behind):
protected void btnSave_Click(object sender, EventArgs e) // Handles Update Button Click Event
{
int idEMPLEADO = Convert.ToInt32(txtID.Text); //Read value from <asp:TextBox ID="txtID">
int idCARGO = Convert.ToInt32(editModalCargo.SelectedValue); //Read value from <asp:DropDownList id="editModalCargo">
DataAccess.UpdateEmpleado(idEMPLEADO, idCARGO); //Update Query
BindData(); //Refresh Gridview
}
I am creating a data list that will have multiple person records displayed inside a collapsible panel and iside each dataItem user can edit the record etc.
Following is my code
<%# Register TagName="CreateEditPerson" Src="~/ascx/create_edit_person.ascx" TagPrefix="WD" %>
<asp:DataList ID="dlPerson" runat="server" OnItemDataBound="dlPerson_OnItemDataBound">
<ItemTemplate>
<div class="personRow">
<div class="personRowHeader" id="divEditPerson">
<div class="lastNameColumn">
<asp:Label ID="lblLastName" runat="server"></asp:Label </div>
<div class="firstNameColumn">
<asp:Label ID="lblFirstName" runat="server"></asp:Label>
</div>
<div class="editColumn">
<asp:Image ID="imgExpandImage" runat="server" Class="divSearchLabel" meta:resourcekey="imgExpandImage" />
<asp:Label ID="lblEditPerson" runat="server" meta:resourcekey="lblEditPerson"></asp:Label>
</div>
<div style="clear: both">
</div>
</div>
<ajaxToolkit:CollapsiblePanelExtender ID="cpPerson" runat="server" meta:resourcekey="cpPerson"
Collapsed="true" TargetControlID="pnlpersonEdit" CollapseControlID="divEditPerson"
ExpandControlID="divEditPerson" TextLabelID="lblEditPerson" CollapsedSize="0"
ScrollContents="false" SuppressPostBack="True" ImageControlID="imgExpandImage">
</ajaxToolkit:CollapsiblePanelExtender>
<asp:Panel ID="pnlpersonEdit" runat="server">
<div class="product_technical_details">
<WD:CreateEditPerson ID="createEditPerson1" runat="server" />
</div>
</asp:Panel>
</div>
</ItemTemplate>
</asp:DataList>
My Problem is,
1. When I click on 1st dataitem panel, All the panels expands. Do i need the dynamic id of the TargetControlID ?
I solved it as follows:
on ItemDataBound event of the datalist, I just set dynamic ID of the collapsible panel, target panel and collaped/expand control; and set the "TargetControlID", "CollapseControlId" and "ExpandControlId"
I am giving the code snippet here:
protected void dlPerson_OnItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
//Find the controls in the Item Template
Panel pnlPersonEdit = e.Item.FindControlRecursive("pnlPersonEdit") as Panel;
CollapsiblePanelExtender cpPersonEdit =
e.Item.FindControlRecursive("cpPersonEdit") as CollapsiblePanelExtender;
//This panel was a div previously "divEditPerson" I have changed it to panel
Panel pnlEditPersonHead = e.Item.FindControlRecursive("pnlEditPersonHead") as Panel;
//Some object from db
PersonObject personObject = e.Item.DataItem as PersonObject;
//Set Id of the collapsed/expanded panel from unique key
pnlEditPersonHead.ID += personObject.CrmddressId.ToString();
//Set Id of the target panel from unique key
pnlPersonEdit.ID += personObject.CrmddressId.ToString();
//simillarly set Id of the collapsible panel extender
cpPersonEdit.ID += personObject.CrmddressId.ToString();
//Now set the TargetControlID, CollapseControlID and ExpandControlID
cpPersonEdit.TargetControlID = pnlPersonEdit.ID;
cpPersonEdit.CollapseControlID = pnlEditPersonHead.ID;
cpPersonEdit.ExpandControlID = pnlEditPersonHead.ID;
}
}
I am creating a survey, it has 60 textboxes I need to require that at least 40 of these textboxes are filled in upon hitting the submit button, it doesn't matter which ones as long as 40 have text within them. Any ideas how to accomplish this with C# or maybe another way?
A few of my textboxes:
<div class="row">
<div class="span3">
<div class="control-group">
<asp:Label ID="SupperLbl" class="control-label required" runat="server" Text="Best Supper Club"></asp:Label>
<div class="controls">
<asp:TextBox ID="SupperTxtBox" class="span3" runat="server"></asp:TextBox>
</div>
</div>
</div>
<div class="span3">
<div class="control-group">
<asp:Label ID="YogurtLbl" class="control-label required" runat="server" Text="Best Place for Frozen Yogurt"></asp:Label>
<div class="controls">
<asp:TextBox ID="YogurtTxtBox" class="span3" runat="server"></asp:TextBox>
</div>
</div>
</div>
</div>
<div class="row">
<div class="span3">
<div class="control-group">
<asp:Label ID="Label1" class="control-label required" runat="server" Text="Best Place for Dessert"></asp:Label>
<div class="controls">
<asp:TextBox ID="DessertTxtBox" class="span3" runat="server"></asp:TextBox>
</div>
</div>
</div>
<div class="span3">
<div class="control-group">
<asp:Label ID="Label2" class="control-label required" runat="server" Text="Best Place for Chicken"></asp:Label>
<div class="controls">
<asp:TextBox ID="ChickenTxtBox" class="span3" runat="server"></asp:TextBox>
</div>
</div>
</div>
</div>
.....
Place your textboxes in an array, then do some validation.
//Place textboxes in array for easy access
TextBox[] validatedTexboxes = new TextBox[] {
textbox1, textbox2, textbox3, ...
};
//On submit, make sure 40 are filled in.
var filledTextboxes = validatedTexboxes.Count(x => !String.IsNullOrWhiteSpace(x.Text));
if (filledTextboxes > 40)
//Do Something
string[] txtArr = { "SupperTxtBox", "YogurtTxtBox", "DessertTxtBox" };
protected void Page_Load(object sender, EventArgs e)
{
string[] lblArr = { "Best Supper Club", "Best Place for Frozen Yogurt", "Best Place for Dessert" };
for (int i = 0; i < lblArr.Length; i++)
{
Label lbl = new Label();
lbl.Text = "<br>" + lblArr[i] + "<br>";
TextBox txt = new TextBox();
txt.ID = txtArr[i];
Form.Controls.Add(lbl);
Form.Controls.Add(txt);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
int Count = 0;
foreach (string item in txtArr)
{
TextBox t = (TextBox)Form.FindControl(item);
if (t != null)
{
if (t.Text.Trim() != "")
Count++;
}
}
if (Count < 3)
{
Response.Write("<br>You fill " + Count + " textbox, Please fill 3 textbox!");
}
}
If you want the validation on the server side, you can loop recursively on all the controls of the page, take the textboxes and verify if at least 40 contains text.
For the recursive loop, you can use the extension method from this answer :
public static IEnumerable<T> FindControls<T>(this Control control, bool recurse) where T : Control
{
List<T> found = new List<T>();
Action<Control> search = null;
search = ctrl =>
{
foreach (Control child in ctrl.Controls)
{
if (typeof(T).IsAssignableFrom(child.GetType()))
{
found.Add((T)child);
}
if (recurse)
{
search(child);
}
}
};
search(control);
return found;
}
All you need to do now is get the array and verify that at least 40 of them contain text :
private bool AreAtLeast40TextBoxesFilled()
{
var allTextBoxes = this.Page.FindControls<TextBox>(true);
return allTextBoxes.Count(t => !string.IsNullOrWhiteSpace(t.Text)) >= 40;
}
Use Phil Haack's tutorials on MVC list model binding so you can keep track of the value and the id of the textbox in a list and then check the count on the server side.
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
If the total count of elements in the list is less than your limit than return a modelstate validation error and return the same view.
If you need a specific example let me know.
I have a repeater control as listed below. It has a textbox control. When a save button is clicked, I need to get the updated text from the textbox. I have the following code; but it gives me the old value when I take the textbox text.
How can we get the updated text?
Code Behind
protected void Save_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in repReports.Items )
{
if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem )
{
string updatedEmail = ((TextBox)item.Controls[5]).Text;
string originalEmail = ((HiddenField)item.Controls[7]).Value;
}
}
}
Control Markup
<div class="repeaterTableBorder">
<asp:Repeater ID="repReports" runat="server">
<ItemTemplate>
<div id="repeaterIdentifier" class="repeaterIdentifier">
<div class="reportTitle">
<%# Eval("ReportName") + ":"%>
<asp:HiddenField ID="hdnLastChangeTime" runat="server" Value= '<%# ((DateTime)Eval("RecordSelectionTime")).ToString("MM/dd/yyyy hh:mm:ss.fff tt")%>' />
<asp:HiddenField ID="hdnReportID" runat="server" Value='<%# Eval("ReportTypeCode")%>' />
</div>
<div class="reportFrequency">
<%# " Frequency - Weekly" %>
</div>
</div>
<div class="reportContent">
<div class="repeaterLine">
<asp:TextBox ID="txtEmailRecipients" runat="server" class="textEdit"
Text='<%# Eval("ExistingRecipients") %>'
TextMode="MultiLine"></asp:TextBox>
<asp:HiddenField ID="hdnOriginalRecipients" runat="server" Value='<%# Eval("ExistingRecipients")%>' />
</div>
</div>
</ItemTemplate>
</asp:Repeater>
</div>
I assume that you are binding the Repeater to it's DataSource also on postbacks. You should do that only if(!IsPostBack). Otherwise the values will be overwritten.
protected void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
// databinding code here
}
}