It's years that I don't touch asp webforms and I got back into it with a legacy project.
I couldn't remember exactly the page lifecycle but at my surprise, I built a form, with a submit button at the end of the form that saves on DB.
The expected event order would have been:
First load of the page
Page_Load -> I load form data (wheter it's empty or reading data from db and populate the form
Button_event -> When I click to save on db if someone changes the form
What i expected when I try to save:
Button event saves to db
Page_load comes into play and i can refresh the form with new data
Of course I dusted my rust on ASP Webforms to discover that Page_Load always come first.
At this point I tought it was a good way to solve the problem by checking what button has been called and then in the IsPostback event manage the save and load of the form.
So in the Page_Load I would do:
if(IsPostBack){
if(button is save){
save data
}
}
//Code to load db data into models
var data = getDataFromDb();
Control1.text = data.text1;
//etc etc...
My question is:
Is this the correct way?
what is the standard way to handle this?
I see also updatepanels are used but didn't want to get into too complicated stuff for a simple form.
a good way to solve the problem by checking what button has been called and then in the IsPostback event manage the save and load of the form.
No, the instant you do that, is very same instant you quite much broken the whole idea of how the page is to work!!!
Page load:
It WILL fire on every post back. So, you have to make that assumption, and thus your code, your ideas, your thinking? It cannot matter, or better said should not matter.
In effect, say we do something REALLY simple, like in page load, fill out a grid, or dropdown list (combo box) or whatever?
Well, then ALL of that page setup, page load of data can only (should only) occur one time.
So, all of that code will be placed inside of the REAL first page load.
that is your if (!IsPostBack) code stub. In fact, out of the last 200 webform pages, 99% of them have that all important (!IsPostBack) stub.
If you don't do above? Then say a user selected a combo box value, and then you click some button on the page - (to say look at the combo box value). if on-load fires again, and you RE-load the combo box, you JUST lost the selection the user made on that page.
So, once you adopt the above concept (if (!IsPostBack) to setup the page, then you are NOW free to simple drop in a button, or even a drop-down list with auto post-back. You never have to care.
So, with above in mind????
You have a save button? Then write the code in the save button to save the data. this is really the ONLY way to build working web form pages.
But, you never care about page load.
Now, to be fair, a boatload of this confusing would have been eliminated if they had a actual event called FirstPage load, but we don't, and thus page load does double duty.
For the most part, and in most cases then, the page load event on additional post-backs should not matter, and you should not care, since it not going to do anything much of value. However, often there are some things that have to run each time - especially if you as a developer don't use the auto-"magic" view state that makes webforms oh so easy. So, in some cases, I will turn off view state (say for a drop down, or gridview - but then that means I DO HAVE to re-load that whatever content each time).
so, no, drop a button on the web form, double click on it, and you are now jumped to the "one little bit" of code that you can think about, and deal with. So, you are now free to write (and ONLY worry about that one nice little code stub). So, if that little code stub is to save data, then write the code to save the data, and you are done.
Keep in mind, that EVEN when you introduce a update panel, and thus don't have to post back the WHOLE page, but only update a small part of the web page (and not have to go to JavaScript and ajax school to achieve that ability to ONLY post-back and only update a small part of the web page? - Well, EVEN that cool update panel triggers the page load event each time!!!
So, from a developers point of view?
You drop buttons on the form, they each have their own code stub to do whatever the heck you want, and that makes/keeps the code VERY simple and easy to write.
But, this DOES mean you better not have code in the page load event that fires each time that re-loads data into say a dropdown list, or grid view. but, since one adopts the concept that the "one time" setup of values, loading of data ONLY ever occurs one time (in that all important if (!IsPostBack) code stub, then you really should never care, or worry or have to check which, or what button triggers the page life cycle, and the page load event thus will never matter anyway - it it only being used on FIRST page load to setup and load and pull data into the page on that first page load).
So, the assumption is that a page will often have many post backs from many different buttons (or even a drop down list with auto-postback). But, as such, it will not matter, since from the get go, the page is assumed to allow and have multiple post-backs occurring, and all of them do trigger the page load event each time, and will trigger page load BEFORE the button (or whatever) code stub for the given event THEN runs.
So, no, page load should not have to check, nor worry nor care about what button was clicked. You need some save code in a button, put that save code in that button stub, and it should just work.
So, in effect flip around what you have!
The "real" page load (!IsPostBack) stub in page load event is to load up the page data. Every other post back thus will not load that data again, including your save button and its code stub.
edit:
Lets take a really simple example. I will on page load fill out a drop down list, then after the user selects a value from drop down list, we display details about that selection.
So, the drop down list will be/have/execute a post-back. (and it could have been simple button - don't matter).
So, a dropdown, and some text boxes etc. to display that hotel information.
We have this markup:
(there is a bit more markup below, but it not important here).
So, on page load, we will load up the combo box. But, as noted, we can NOT load up the box each time on page load, since it would "over write" or "blow up" the selection we make each time for a post-back.
So, our page load even will look like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadCombo();
}
void LoadCombo()
{
SqlCommand cmdSQL
= new SqlCommand("SELECT ID, HotelName FROM tblHotelsA ORDER BY HotelName");
DropDownList1.DataSource = MyRstP(cmdSQL);
DropDownList1.DataBind();
// add extra please select option to drop down
DropDownList1.Items.Insert(0, new ListItem("Select Hotel", "0"));
}
public DataTable MyRstP(SqlCommand cmdSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (cmdSQL)
{
cmdSQL.Connection = conn;
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
And then we have the combo box selected index change event - a post back, like any other button click or whatever.
So, we have this code for that combo choice:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
if (DropDownList1.SelectedItem.Value != "0")
{
// user selected a hotel, get all hotel information
SqlCommand cmdSQL =
new SqlCommand("SELECT * FROM tblHotelsA WHERE ID = #ID");
cmdSQL.Parameters.Add("#ID", SqlDbType.Int).Value = DropDownList1.SelectedItem.Value;
DataRow rstData = MyRstP(cmdSQL).Rows[0];
txtHotel.Text = rstData["HotelName"].ToString();
tFN.Text = rstData["FirstName"].ToString() ;
tLN.Text = rstData["LastName"].ToString() ;
tCity.Text = rstData["City"].ToString() ;
tProvince.Text = rstData["Province"].ToString();
chkActive.Checked = (bool)rstData["Active"];
chkBalcony.Checked = (bool)rstData["Balcony"];
txtNotes.Text = rstData["Description"].ToString();
}
}
So, now the result is this:
however, if we did NOT use that !IsPostBack block, then above would not work. But, with this "simple" design pattern?
Then I am free to add more buttons, more code, more events, more post-backs, and they all simple work, and I can ignore the page load event code, since it was only ever used one time on the "real" first page load to load up the data and controls on that page.
Edit2: A grid and edit example
so, lets use all of the above we learned, and build a typical CURD edit example.
So, lets edit a list of hotels, much like above, but we will "pass" our form "div" to some genreal routines I wrote - routines out side of the form.
so, first up, a grid to display the list of hotels (with a edit button).
So, we have this markup:
<asp:GridView ID="GridView1"
runat="server" CssClass="table table-hover" AutoGenerateColumns="false"
width="48%" DataKeyNames="ID" OnRowDataBound="GridView1_RowDataBound" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" ItemStyle-Width="160" />
<asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="270" />
<asp:TemplateField HeaderText="" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<button runat="server" id="cmdEdit"
type="button" class="btn myshadow"
onserverclick="cmdEdit_Click">
<span class="glyphicon glyphicon-home"></span> Edit
</button>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Ok, so now our code to load up this grid (with a data table we pull from the database).
We have this (again, that "all important" !IsPostBack stub for our first load of the data.
thus, this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
string strSQL = "SELECT * FROM tblHotelsA ORDER BY HotelName";
DataTable rstData = General.MyRst(strSQL);
GridView1.DataSource = rstData;
GridView1.DataBind();
}
And now we have this:
Ok, so far, not much code (since I have those helper routines in that "general" code class (a static one, since it just a "module" of code I want to call/use/enjoy).
Ok, now in the above, we have a edit button. That edit button will get the current row, pull the data, and then FILL OUT some controls on the page. As noted, you can do assignment of values in code behind, but it really amounts to re-writing the same code over and over. So, after doing that a few times, I wrote some code to do that for me.
So, right below the GV, lets drop in another div. This will be our "edit record" area (to edit details of one row).
So, it really just markup. but, as noted, I had to cook up some kind of "mapping" from the data base columns to the controls on the web page. So, I just out of the blue decided to use a tag "f".
So, f="data base column name" is a standard I adopted.
So, ok, now our markup to edit:
<div id="EditRecord" runat="server" style="float: left; display: none; padding: 15px">
<div style="float: left" class="iForm">
<label>HotelName</label>
<asp:TextBox ID="txtHotel" runat="server" Width="280" f="HotelName" /><br />
<label>First Name</label>
<asp:TextBox ID="tFN" runat="server" Width="140" f="FirstName"/><br />
<label>Last Name</label>
<asp:TextBox ID="tLN" runat="server" Width="140" f="LastName" /><br />
<label>City</label>
<asp:TextBox ID="tCity" runat="server" Width="140" f="City" /><br />
<label>Province</label>
<asp:TextBox ID="tProvince" runat="server" Width="75" f="Province" /><br />
</div>
<div style="float: left; margin-left: 20px" class="iForm">
<label>Description</label>
<br />
<asp:TextBox ID="txtNotes" runat="server" Width="400" TextMode="MultiLine"
Height="150px" f="Description"></asp:TextBox><br />
<asp:CheckBox ID="chkActive" Text=" Active" runat="server"
TextAlign="Right" f="Active" />
<asp:CheckBox ID="chkBalcony" Text=" Has Balcony" runat="server"
TextAlign="Right" f="Balcony"/>
</div>
<div style="clear: both"></div>
<button id="cmdSave" runat="server" class="btn myshadow" type="button"
onserverclick="cmdSave_Click">
<span aria-hidden="true" class="glyphicon glyphicon-floppy-saved">Save</span>
</button>
<button id="cmdCancel" runat="server" class="btn myshadow" style="margin-left: 15px"
type="button"
onclick="MyClose();return false">
<span aria-hidden="true" class="glyphicon glyphicon-arrow-left">Back/Cancel</span>
</button>
<button id="cmdDelete" runat="server" class="btn myshadow" style="margin-left: 15px"
type="button"
onserverclick="cmdDelete_ServerClick"
onclick="if (!confirm('Delete Record?')) {return false};">
<span aria-hidden="true" class="glyphicon glyphicon-trash">Delete</span>
</button>
</div>
I mean, it a bit much to post here, but it not a huge amount. it really just amounts to markup I created (and most of it was by drag + drop).
Ok, so now, what does the edit button look like to fill out the above "edit" area?
The edit button code looks like this:
protected void cmdEdit_Click(object sender, EventArgs e)
{
HtmlButton btn = sender as HtmlButton;
GridViewRow gRow = btn.NamingContainer as GridViewRow;
int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
ViewState["PKID"] = PKID;
string strSQL = $"SELECT * FROM tblHotelsA WHERE ID = {PKID}";
DataRow rstData = General.MyRst(strSQL).Rows[0];
General.FLoader(this.EditRecord, rstData);
// pop the edit div using jQuery.UI dialog
string sJava = $"pophotel('{btn.ClientID}')";
Page.ClientScript.RegisterStartupScript(Page.GetType(), "MyJava", sJava, true);
}
So, note the "floader" routine. I passed that "div from the page to the routine that "loads" the database columns into the controls for me. (and I can thus use that one same routine for any web page I create now).
So, next up, we need a "save" button. That code looks like this:
protected void cmdSave_Click(object sender, EventArgs e)
{
int PKID = (int)ViewState["PKID"];
General.FWriter(this.EditRecord, PKID, "tblHotelsA");
LoadData(); // re-load grid to show any changes
}
And while I could have JUST hide the gridview, and display the EditReocrd div with this code:
GridView1.Style.Add("display", "none");
EditRecord.Style.Add("display", "nomral");
Well, since I have jQuery, and jQuery.UI as part of this project? I might as well just use a jQuery.UI "dialog" and pop that.
So, out of this whole page, I did have to bite the bullet, and write about 8 lines of js code to pop that dialog.
Not a lot of code, and I have this:
<script>
function pophotel(btnT) {
btn = $('#' + btnT)
var mydiv = $("#EditRecord")
mydiv.dialog({
modal: true, appendTo: "form",
title: "Edit Hotel", closeText: "",
width: "835px",
position: { my: 'right top', at: 'right bottom', of: btn },
dialogClass: "dialogWithDropShadow"
});
}
function MyClose() {
popdiv = $('#EditRecord')
popdiv.dialog('close')
}
</script>
Gee, that is ALL the js code I had to write.
So, now when I run the above, I get this effect:
Now, I can post the "general" routines. I mean, MyRst was simple, and is this:
public static DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
But, as you can see how the simple event model was leveraged, and you can see that we really did not write a lot of code here.
So, I could (am free) to pass any part of that web page class to any other routine I want, so for example, in place of passing the "div" as per my example like this:
General.FWriter(this.EditRecord, PKID, "tblHotelsA");
I am free to pass the WHOLE page class like this:
General.FWriter(this.Page, PKID, "tblHotelsA");
And while "General" is a static class? It does/did not have to be for this example.
If YOU HAVE a better web framework that is LESS work then the above?
Then by all means do suggest which one it is!!! - I want to know!!!
Just try the above in MVC, or even introduce say react.js, and you find it takes 3x times the work. So much so, that those frameworks would NEVER post a working example code like I did above, and the reason is simple: it would take WAY WAY too much work and time to do so!!! Webforms very much rock and are amazing as the above example shows, since all of the code was rather simple, and I really did not even require any client side js code, but I tossed in the dialog code for a good example anyway. I REALLY do not know of ANY web based framework that is less efforts for the above given results as compared to how webforms work. Not only are they easy, they also tend to require less code, since we have data bound controls like the gridview I used, and we don't even have any looping code for the grid - we just feed it a datatable.
I'm having an odd problem in that one of the 4 custom validators on my web page is not firing. Everything looks correct based on the working validators. Below is the simplified code.
ASPX code -
<asp:TextBox ID="CMT_TXT" runat="server" Columns="60" Rows="8"
TextMode="MultiLine" Text='<%#Eval("CMT_TXT")%>'></asp:TextBox><br />
<asp:CustomValidator ID="csvCMT_TXT" runat="server" ControlToValidate="CMT_TXT"
Display="Dynamic" EnableClientScript="False" ErrorMessage="Msg">
</asp:CustomValidator>
VB code -
Public Sub csvCMT_TXT_ServerValidate(source As Object,
args As ServerValidateEventArgs) _
Handles csvCMT_TXT.ServerValidate
dim s As String = CMT_TXT.Text
args.IsValid = s.Length <= 3500
End Sub
When testing,
The contents of field CMT_TXT has approximately 3000 characters. So it is not an empty field issue.
Page.Validate is called in the main body of the code
for server side validation to fire you need to call Page.Validate, this should trigger all your server side validation and update Page.IsValid
Also it does not look like you have the event set up on the custom val. may want to add the prop OnServerValidate
OnServerValidate="csvCMT_TXT_ServerValidate"
<asp:CustomValidator ID="csvCMT_TXT" runat="server" ControlToValidate="CMT_TXT"
Display="Dynamic" EnableClientScript="False" ErrorMessage="Msg" OnServerValidate="csvCMT_TXT_ServerValidate">
</asp:CustomValidator>
I'm not too familiar with VB.NET, but with C# I'll check the Page.IsValid field before continuing on with a page that has a CustomValidator.
An example with a Wizard control that contains a CustomValidator in the final stage, I will check this value in the FinishButtonClick event.
protected void Wizard1_FinishButtonClick(object sender, WizardNavigationEventArgs e)
{
if (Page.IsValid == false)
{
// validator failed, stop wizard from continuing
return;
}
// page is valid, continue on
// ...
}
Not sure if there are any differences with VB.NET, but may be worth a shot
At a glance, it looks like you named your handler incorrectly. The control ID is csvCMT_TXT while the handler is csv_CMT_TXT.ServerValidate. There's an extra _ in the handler.
The problem turned out to be a problem with the VS2010 project build.
To this the problem, I had to
Deleted all files in BIN directory
Deleted all file in OBJ directory
Deleted Custom Validator
Rebuilt the Project
Add Custom Validation back into program. Added the original code back into program
It's a bit extreme, but this is what it took to resolve the problem.
I have a Results.aspx page that displays the resulting records queried using a SqlDataSource object via a ListView. I want to add a "View" button that will appear next to each record, and when clicked will take me to a separate page that will display details about that record. How do I accomplish this?
Edit
I have tried what you said, citronas and here's what I've come up with:
<td>
<asp:CheckBox ID="CheckBox1" runat="server" />
</td>
<td>
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="ViewButtonClick" CommandArgument='<%# Eval("ServiceId") %>'>View</asp:LinkButton>
</td>
And here is the method that I want to be called:
protected void ViewButtonClick(object sender, CommandEventArgs e)
{
var serviceId = Convert.ToInt32(e.CommandArgument);
ServiceToView = DataAccessLayer.Service.Select(new Service { ServiceId = serviceId });
Server.Transfer("~/ViewService.aspx");
}
Unfortunately nothing actually happens...am I missing something?
Edit -- Fixed
I was missing something! I had CommandName equal to my method name instead of OnCommand. I took out CommandName, kept the argument bit and replaced CommandName with OnCommand. Everything works now, but what would I ever need CommandName for?
You can add a LinkButton into the ItemTemplate of the ListView.
Bind the value that identifies each record to the CommandArgument of the LinkButton.
Subscribe to the Command-Event of the LinkButton. There you have access to CommandEventArgs.CommandArgument
What you wound up doing worked Storm. I decided to go with Citronas' suggestion and share my answer.
FIRST:
On the aspx I added a LinkButton to my ItemTemplate with my own CommandName and CommandArgument. I passed my item's ID as a CommandArgument so I could later use it inside my sub.
<asp:LinkButton ID="lnkBtnAnswers" runat="server" CommandName="Answers"
CommandArgument='<%# Eval("ID")%>'>Answers</asp:LinkButton>
SECOND:
On the codebehind I created a sub that would be called whenever the user conducted an action. As Citronas mentioned normally you use "Select", "Add", "Edit", or "Delete" here. I decided to create "answers".
Note: Handles MyControl.ItemCommand is very important here as it is what subscribes you to the command event.
Protected Sub lvQuestions_Command(sender As Object, e As CommandEventArgs) Handles lvQuestions.ItemCommand
If e.CommandName.ToLower() = "answers" Then
hfSelectedQuestionID.Value = e.CommandArgument
End If
End Sub
Done! Now since every command goes through the new sub, it is important to check for the right commandName so you can conduct the appropriate action. Don't forget to use the CommandArgument to your advantage.
This question already has answers here:
Facebox adding commas to input
(3 answers)
Closed 3 years ago.
I'm using jQuery FaceBox to show a textbox, a dropdownlist and a button. The user can write a text in the textbox, select a value in the ddl abd hit the button. This fires some code in the codebehind. The FaceBox shows fine, and the content in it is also ok. Also, the button event is fired. This is the code for the button event handler:
protected void Button1_Click(object sender, EventArgs e)
{
_favorit = new Favoritter();
ListItem fav = ddl_favoritter.SelectedItem;
_favorit.FavoritterFolderID = int.Parse(fav.Value);
//_favorit.FavoritterFolderID = Convert.ToInt32(ddl_favoritter.SelectedItem);
_favorit.FavoritterNavn = txt_favoritNavn.Text;
_favorit.FavoritterUserID = UserID;
_favorit.FavoritterUrl = HttpContext.Current.Request.Url.ToString();
FavoritterManager.InsertFavoritter(_favorit);
}
A business object is created, and its properties set with the values read from the controls. The object is then inserted into a database, which works just fine. The problem is that the textbox and dropdown values are not set properly. The textbox value is empty, and the ddl selected value is allways 1, even though I write in the textbox, and select another ddlitem before I hit the button. The ddl is loaded like this:
if (!Page.IsPostBack)
{
_favoritter = FavoritterFolderManager.GetFavoritterFolderByUser(UserID);
ddl_favoritter.DataSource = _favoritter;
ddl_favoritter.DataBind();
}
I tried putting this code outside if (!Page.IsPostBack), and also filling it using an objectdatasource, still the same issue. It's like the controls are "reset" as I hit the button, and I don't think it has anything to do with the FaceBox, as all it does is to show the div that contains the controls... Then again, it might... Any ideas?
This is the code in the aspx page:
<div id="showme" style="display:none;">
Add to favourites.<br />
<br />
<p>
Title: <span><asp:TextBox ID="txt_favoritNavn" runat="server"></asp:TextBox></span></p>
<p>
select folder: <span><asp:DropDownList ID="ddl_favoritter" runat="server" DataTextField="FavoritterFolderNavn"
DataValueField="FavoritterFolderID" AppendDataBoundItems="true">
</asp:DropDownList>
</span>
</p>
<br />
<asp:Button ID="Button1" runat="server" Text="Gem" onclick="Button1_Click"/>
</div>
You need to have the code that fills the text box and selects the drop down item inside of the if(!IsPostBack) block, because the page load event fires again before the button event (See the ASP.NET Page Life Cycle for more info on this). Have you tried enabling view state on the control? That may be part of the issue.
Change
$('body').append($.facebox.settings.faceboxHtml)
to
$('form').append($.facebox.settings.faceboxHtml)
The problem is a lot of these controls, not just FaceBox append themselves to the body by default. jQuery UI dialog does this as well.
See this question for a fix: JQuery Facebox Plugin : Get it inside the form tag
When things happen outside the <form> tag, they're disconnected from how ASP.Net works. When you clicked submit, the values from those inputs weren't inside the form, so didn't submit to the server...which is why you aren't seeing the values.
This is the quick answer from that question, credit to Kevin Sheffield:
poking around the facebox.js I came across this line in the function init(settings)...
$('body').append($.facebox.settings.faceboxHtml)
I changed that to ...
$('#aspnetForm').append($.facebox.settings.faceboxHtml)
I have an AutoCompleteExtender AjaxControlToolkit control inside a repeater and need to get a name and a value from the web service. The auto complete field needs to store the name and there is a hidden field that needs to store the value. When trying to do this outside of a repeater I normally have the event OnClientItemSelected call a javascript function similiar to
function GetItemId(source, eventArgs)
{
document.getElementById('<%= ddItemId.ClientID %>').value = eventArgs.get_value();
}
However since the value needs to be stored in a control in a repeater I need some other way for the javascript function to "get at" the component to store the value.
I've got some JavaScript that might help you. My ASP.Net AutoComplete extender is not in a repeater, but I've modified that code to detect the ID of the TextBox you are going to write the erturned ID to, it should work (but I haven't tested it all the way through to post back).
Use the value from 'source' parameter in the client side ItemSelected method. That is the ID of the calling AutoComplete extender. Just make sure that you assign an ID the hidden TextBox in the Repeater Item that is similar to the ID of the extender.
Something like this:
<asp:Repeater ID="RepeaterCompareItems" runat="server">
<ItemTemplate>
<ajaxToolkit:AutoCompleteExtender runat="server"
ID="ACE_Item"
TargetControlID="ACE_Item_Input"
...other properties...
OnClientItemSelected="ACEUpdate_RepeaterItems" />
<asp:TextBox ID="ACE_Item_Input" runat="server" />
<asp:TextBox ID="ACE_Item_IDValue" runat="server" style="display: none;" />
</ItemTemplate>
</asp:Repeater>
Then the JS method would look like this:
function ACEUpdate_CustomerEmail(source, eventArgs) {
UpdateTextBox = document.getElementById(source.get_id() + '_IDValue');
//alert('debug = ' + UserIDTextBox);
UpdateTextBox.value = eventArgs.get_value();
//alert('customer id = ' + UpdateTextBox.value);
}
There are extra alert method calls that you can uncomment for testing and remove for production. In a simple and incomplete test page, I got IDs that looked like this: RepeaterCompareItems_ctl06_ACE_Item_IDValue (for the text box to store the value) and RepeaterCompareItems_ctl07_ACE_Item (for the AC Extender) - yours may be a little different, but it looks practical.
Good Luck.
If I understand the problem correctly, you should be able to do what you normally do, but instead of embeding the ClientId, use the 'source' argument. That should allow you to get access to the control you want to update.
Since you are using a Repeater I suggest wiring the OnItemDataBound function...
<asp:Repeater id="rptResults" OnItemDataBound="FormatResults" runat="server">
<ItemTemplate>
<asp:PlaceHolder id="phResults" runat="server" />
</ItemTemplate>
</asp:Repeater>
Then in the code behind use something like
`Private Sub FormatResults(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)
Dim dr As DataRow = CType(CType(e.Item.DataItem, DataRowView).Row, DataRow) 'gives you access to all the data being bound to the row ex. dr("ID").ToString
Dim ph As PlaceHolder = CType(e.Item.FindControl("phResults"), PlaceHolder)
' programmatically create AutoCompleteExtender && set properties
' programmatically create button that fires desired JavaScript
' use "ph.Controls.Add(ctrl) to add controls to PlaceHolder
End Sub`
Voila