This really is bizarre. I'm trying to implement the AutoCompleteExtender using a database. I enter the first character, let's say 'T' into the textbox, and the drop down results panel shows all of the page's source code (client side rather than server side), one character per line as seen in the image.
AutoComplete Results Screenshot
Incidentally, Google Chrome displays this straight away, while IE has a good think about it, saying localhost is not responding because it's running a long script.
If I then select any one of those characters it then displays the correct results beginning with 'T', though replaces the character I typed with whatever I selected.
I pulled the code from a tutorial on codeproject.com and apart from changing the textbox ID and a bit of ADO so it points to my database, it's identical.
I'll include the code. What's going wrong?
Now for some reason, it's not letting me post the code, regardless of how I format, but this is what I used. AutoComplete With DataBase and AjaxControlToolkit
It is very hard to give answer without seeing the code... try this
<asp:TextBox ID="txtSearchKey" runat="server" Width="350" AutoPostBack="true" OnTextChanged="txtSearchKey_TextChanged" />
<asp:TextBoxWatermarkExtender ID="weSearchKey" runat="server" Enabled="True" TargetControlID="txtSearchKey" WatermarkText="Search by Name" WatermarkCssClass="watermark" />
<asp:AutoCompleteExtender ServiceMethod="YourWebMethod" MinimumPrefixLength="3" CompletionInterval="100" EnableCaching="false" CompletionSetCount="10" TargetControlID="txtSearchKey" ID="searchExtender" runat="server" FirstRowSelected="false" OnClientItemSelected="GetSelectedId" CompletionListCssClass="completionList" CompletionListItemCssClass="listItem" CompletionListHighlightedItemCssClass="itemHighlighted" CompletionListElementID="divCompletionListElement" />
<input type="hidden" id="hdnSelectedId" name="hdnSelectedId" value="" />
Have a javascript method to ensure selected item is captured
function GetSelectedId(source, eventArgs) {
var selectedId = eventArgs.get_value();
var e = document.getElementById('hdnSelectedId');
if (e) {
e.value = selectedId;
}
}
Create a WebMethod in your back end code that is configured in ServiceMethod property of AutoCompleteExtender
[ScriptMethod()]
[WebMethod]
public static List<string> YourWebMethod(string prefixText, int count)
{
var totalRecords = 0;
var searchResults = <<get your results here into a list or whatever container>>
//I used DataTable as a container here for searchResults
if (searchResults.Rows.Count == 0)
return new List<string>() { "No result found" };
//Create a List from your search results and return it
List<string> items = new List<string>();
foreach (DataRow searchResult in searchResults.Rows)
items.Add(AutoCompleteExtender.CreateAutoCompleteItem(searchResult["Name"].ToString(), searchResult["BuilderID"].ToString());
return items;
}
Related
I'm having an issue with the cycle of a page reload and I can't figure it out. I have an ASP button the runs at the server but it has an associated client side click. The client side Javascript is running correctly and returning true to the button click so it is also running. The Javascript makes a modification to the query string on the URL and this is also working. However, in the C# code behind, the query string is not there. Somewhere, I'm missing something.
The HTML link:
<asp:Button ID="btnRunMOReport" class="button-dbg" runat="server"
Text="Run MO Report" OnClick="btnMO_Report_Click"
OnClientClick="return validateCheckBoxesMO()" />
The JavaScript portion:
function validateCheckBoxesMO() {
token='xyz';
let url1 = window.location.href;
if (url1.indexOf("?") > 0) {
url1 = url1.substring(0, url.indexOf("?"));
}
url1 += "?hiddenToken=" + token;
window.location.replace(url1);
return true;
}
The hiddenToken is now represented on the page (?hiddenToken=xyz).
The code behind:
protected void btnMO_Report_Click(object sender, EventArgs e)
{
MailMessage mailtest = new MailMessage();
mailtest.IsBodyHtml = true;
SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);
mailtest.To.Add("Whoever#test123.com");
mailtest.From = new MailAddress("Whoever#test123.com");
mailtest.Subject = Request.QueryString["hiddenToken"];
mailtest.Body = "Whatever";
}
The mail comes just fine but the subject is blank. Somehow, during the page reload cycle, the query string has not yet been set.
If there is a better way to pass data from the JavaScript to the code behind, I'm all ears.
I want to launch another page from the code behind but I need some data that is returned from the JS. The token is actually something I fetch, process the JSON and now I want to make that token available to the code behind for additional information to add to the new URL I am constructing. Probably TMI for this but it is what I am trying to do.
Thanks for your assistance.
Your script isn't working because the browser makes a POST request to submit the form (and __VIEWSTATE) using the action="" attribute of the <form> that WebForms adds to your page.
When your client-script sets window.location it isn't changing how the <form> will behave. You could use your script to append the new querystring value to the <form>'s action="" attribute and this may work, however it will likely fail if the application has request-validation enabled (in which case ASP.NET will reject a tampered form submission).
As you're using WebForms (and you shouldn't be using WebForms in 2021...) you shouldn't try to fight it unless you understand how it all works (I'm not trying to be condescending: it took me years to figure it all out and I've been using WebForms since 2004).
Instead, provide the value through an <asp:HiddenField>:
Change your .aspx markup to this:
<asp:Button runat="server" ID="btnRunMOReport" class="button-dbg"
Text="Run MO Report" OnClick="btnMO_Report_Click"
OnClientClick="return validateCheckBoxesMO()" />
<asp:HiddenField runat="server" ID="superSecretHiddenField" />
Change your client script to this:
function validateCheckBoxesMO() {
const hiddenFieldId = '<%= this.superSecretHiddenField.ClientID %>';
const hiddenField = document.getElementById( hiddenFieldId );
token='xyz';
hiddenField.value = token;
return true; // <-- This is wrong, btw. Instead use `Event.prototype.stopPropagation()` - but that requires the on-click function to be wired-up correctly and I don't remember the specifics other than that WebForms *doesn't* do things correctly (not out-of-spite, but because WebForms predates the standardisation of client-script events).
}
And your code-behind to this:
protected void btnMO_Report_Click(object sender, EventArgs e)
{
MailMessage mailtest = new MailMessage();
mailtest.IsBodyHtml = true;
SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);
mailtest.To.Add("Whoever#test123.com");
mailtest.From = new MailAddress("Whoever#test123.com");
mailtest.Subject = this.superSecretHiddenField.Value;
mailtest.Body = "Whatever";
}
As noted, a button post back will in general over-write the url that you change. Unless you actually do a navigation client side that is caused by the js, then it will not persist.
So, on the most simple level, just drop in a text box, or hidden field, and put the value you need/want into that hidden textbox or field.
So, client side? Markup?
You can use this:
<asp:Button ID="Button1" runat="server" Text="Delete"
OnClientClick="SetHidden();"/>
<asp:HiddenField ID="HiddenField1" runat="server" ClientIDMode="Static"/>
<br />
<script>
function SetHidden() {
hField = document.getElementById('HiddenField1');
hField.value = 'zoo';
return true;
}
</script>
So in above, we set our value in js to zoo, and of course we do return true. If we return false then the asp.net button code server side will not run - so we can control this, or even say pop up a confirm dialog and return true/false based on that to control if the server side code behind will run.
Server side, code behind? You can now use this:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Debug.Print(HiddenField1.Value)
End Sub
So the above is easy, clean. You can also use a text box, and set the style="display:none", but a hidden field is just as well and easy.
I'm using the above control (note it's the ASP.NET one. I seem to see lots of people using a similarly named one written in javascript) to allow upload multiple uploads of files with a progress bar, drag-n-drop, etc. That part all works fine but I need to return two pieces of data along with the file. Specifically, it's a user entered latitude and longitude that comes from two text boxes. Since the upload control is async, the contents of the text boxes don't get posted back so I can't access them. There seems to be a property I can hook into, ContextKeys, which will send the data back to the server, but it's a static field and I don't know how to manipulate it dynamically. I've tried hooking the ontextchanged events from the textboxes and using those to set the context keys. The post back works and it seems to set the value, but when the user presses the upload button the ContextKeys value is empty.
Does anyone how to programtically set the ContextKeys property, or another way to send data back with the upload?
Here's the code:
.ASPX
<div style="float:left; width: 325px;">
<cc1:AjaxFileUpload ID="AjaxFileUpload1" runat="server" Width="325px"
onuploadcomplete="UploadComplete" ClientIDMode="Static" />
<cc1:DynamicPopulateExtender ID="AjaxFileUpload1_DynamicPopulateExtender"
runat="server" Enabled="True" PopulateTriggerControlID=""
TargetControlID="AjaxFileUpload1">
</cc1:DynamicPopulateExtender>
</div>
<div style="float:left">Latitude:
<asp:TextBox ID="tbUploaderLat" runat="server"
ontextchanged="tbUploaderLat_TextChanged" AutoPostBack="True"></asp:TextBox><br />
Longitude:
<asp:TextBox ID="tbUploaderLon" runat="server"
ontextchanged="tbUploaderLon_TextChanged" AutoPostBack="True"></asp:TextBox>
</div>
code-behind:
protected void UpdateLatLon() //this is called from the two events above
{
AjaxFileUpload1.ContextKeys = tbUploaderLat.Text + "|" + tbUploaderLon.Text;
}
You can customize AjaxFileUpload control as described here and here and pass textboxes values to UploadCompleted event handler as below:
function uploadStarted(sender, args) {
var latitude = $get("<%= tbUploaderLat.ClientID %>").value;
var longitude = $get("<%= tbUploaderLon.ClientID %>").value;
sender.contextKeys = { "latitude": latitude, "longitude": longitude };
}
After that, you can get latitude & longitude values in UploadComplete handler:
protected void AjaxFileUpload1_OnUploadComplete(object sender, AjaxFileUploadEventArgs file)
{
if (!string.IsNullOrEmpty(file.ContextKeys))
{
var longLat = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Dictionary<string, string>>(file.ContextKeys);
var longitude = longLat["longitude"];
var latitude = longLat["latitude"];
}
//code to save file
}
I have a dynamic data web site into which I am attempting to add a text box with an AutoCompleteExtender. I have declared the control like so
<asp:TextBox ID="tbTerm" runat="server" Width="300px"/>
<asp:AutoCompleteExtender runat="server"
id="autoCompleteExtenderTerms"
TargetControlID="tbTerm"
ServiceMethod="GetCompletionList"
UseContextKey="True">
</asp:AutoCompleteExtender>
And in the codebehind on that page I have declared the web method like so
[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public static List<string> GetCompletionList(string prefixText, int count)
{
using (ProductDataEntities context = new ProductDataEntities())
{
var terms = (from t in context.Terms
where t.Name.StartsWith(prefixText, StringComparison.CurrentCultureIgnoreCase)
select t.Name).ToList();
return terms;
}
}
Currently this method is not getting called, this is not a forgien key column so I cant use the standard filter for this.
I have ensured that EnablePageMethods="true" is set on the ScriptManager and I am out of ideas as to why this method is not being fired from the page.The contol is not wrapped within an update panel nothing else stands out to me on this.
Set up ServicePath property value.
My script isnt checking the requirement can u help me out with this?
I'm trying to make it run the script before it run the onclick to check if login is right.
<script type="text/javascript">
function checkform() {
var name = document.getElementsByTagName("UserName");
var pw = document.getElementsByTagName("Password");
if(name.charAt(0)!='s'){
document.getElementById("divMessage").innerHTML = "Please insert an S infront";
return false;
if(pw.length< 8 && pw.length>16){
document.getElementById("divMessage").innerHTML = "Please key in a longer password";
return false;
}
}else{
return true;
}
</script>
<asp:Button ID="btnLogin" class="button" runat="server" CommandName="Login"
OnClientClick ="return checkform()" onclick="btnLogin_Click" text="Login" />
You are trying to grab the controls based on tagNames. This way it could also return you a collection of controls as it says "document.get Elements ByTagName" Elements is plural. If your controls which you are trying to grab: UserName & Password are the actual ID in the Server controls use the following code:
<script type="text/javascript">
function checkform() {
var name = document.getElementById("<%=UserName.ClientID %>");
var pw = document.getElementById("<%=Password.ClientID %>");
if(name.charAt(0)!='s'){
document.getElementById("divMessage").innerHTML = "Please insert an S infront";
return false;
if(pw.length< 8 && pw.length>16){
document.getElementById("divMessage").innerHTML = "Please key in a longer password";
return false;
}
}else{
return true;
}
</script>
<asp:Button ID="btnLogin" class="button" runat="server" CommandName="Login"
OnClientClick ="return checkform()" onclick="btnLogin_Click" text="Login" />
In the case of the UserName & Password are not server controls by which I mean an asp control but rather its run on the client, for example its not a <asp:TextBox....
BUT a <input ... (which runs on the client) you could specify its id tag with the value of UserName and Password for the other one, with one change replace:
var name = document.getElementsByTagName("UserName");
var pw = document.getElementsByTagName("Password");
With:
var name = document.getElementById("UserName");
var pw = document.getElementById("Password");
Alternatively if you are trying to get it based on tagNames then you have to go thru the returned collection and find out which one is the control you want. For example if there is only one control with that name it will be the only item in the collection starting at 0 and if you go higher like 1 its out of range.
Hope this has been helpful to you.
When asp.net controls are rendered they have different id may be following are generating error
var name = document.getElementsByTagName("UserName");
var pw = document.getElementsByTagName("Password");
Set the ClientIDMode of the controls to Static.
http://msdn.microsoft.com/en-us/library/system.web.ui.control.clientidmode.aspx
this way the client ids will be the same as the server ones.
Once you have done that, change your js script to use getElementById();
Hope it helps.
I have the following client side code in .aspx page within a datalist itemtemplate that takes questions from the database like this:
<Itemtemplate>
<b> <%=GetQuestionNum()%>)
<%#Server.HtmlEncode(Eval("Text").ToString())%></b>
<br />
<asp:Panel ID="A" runat="server" Visible='<%#GetVisible(Eval("OptionA").Tostring())%>'>
<input name="Q<%#Eval("ID")%>" type="radio" value="A">
<%#Server.HtmlEncode(Eval("OptionA").ToString())%>
</option><br />
</asp:Panel>
<asp:Panel ID="B" runat="server" Visible='<%#GetVisible(Eval("OptionB").Tostring())%>'>
<input name="Q<%#Eval("ID")%>" type="radio" value="B">
<%#Server.HtmlEncode(Eval("OptionB").ToString())%>
</option><br />
</asp:Panel>
<asp:Panel ID="C" runat="server" Visible='<%#GetVisible(Eval("OptionC").Tostring())%>'>
<input name="Q<%#Eval("ID")%>" type="radio" value="C">
<%#Server.HtmlEncode(Eval("OptionC").ToString())%>
</option><br />
</asp:Panel>
<asp:Panel ID="D" runat="server" Visible='<%#GetVisible(Eval("OptionD").Tostring())%>'>
<input name="Q<%#Eval("ID")%>" type="radio" value="D">
<%#Server.HtmlEncode(Eval("OptionD").ToString())%>
</option><br />
</asp:Panel></itemtemplate>
The output is like:
1) What is your age group?
- Option 1
- Option 2
- Option 3
- Option 4
The ID's of the radio buttons are dynamic ("Q" & QuestionID). If there is no answer to a question then the GetVisible function returns false and the containing panel is hidden.
I have been trying to get rid of the html and replace these with asp:radiobuttons but it is not possible to set id's from databinding.. only simply. I was trying something like:
<asp:RadioButton ID="Q<%#Eval("ID")%>" runat="server" Visible='<%#GetVisible(Eval("OptionA").Tostring())%>'
Text='<%#Server.HtmlEncode(Eval("OptionA").ToString())%>' />
Here is the function that provides data:
Public Shared Function GetQuestionsForSurvey(ByVal id As Integer) As DataSet
Dim dsQuestions As DataSet = New DataSet()
Try
Using mConnection As New SqlConnection(Config.ConnectionString)
Dim mCommand As SqlCommand = New SqlCommand("sprocQuestionSelectList", mConnection)
mCommand.CommandType = CommandType.StoredProcedure
Dim myDataAdapter As SqlDataAdapter = New SqlDataAdapter()
myDataAdapter.SelectCommand = mCommand
mCommand.CommandType = CommandType.StoredProcedure
mCommand.Parameters.AddWithValue("#id", id)
myDataAdapter.Fill(dsQuestions)
mConnection.Close()
Return dsQuestions
End Using
Catch ex As Exception
Throw
End Try
End Function
but I'm finding it impossible to work with the html controls, i.e get their .text value from codebehind, or adding events!
Please can an expert suggest a better way to replace the html with suitable asp.net web controls or from the codebehind and output it. Or point me in the right direction?
Thanks :0)
I had some experience with ASP controls and data binding. The problem you are facing is probably the fact that once you declare a control via markup you can't access it from data binding. Also, you should not confuse the server-side ID with the client-side ID.
The server-side ID, mapped to Id property of controls, is used to programmatically access the control from code behind. Client-side ID is the ID that will be placed in tag's id attribute and is mapped to ClientId property.
Judging from your question, what you need is to build a multi-choice survey, and, in my opinion, it's not important how the IDs are generated, just that they are properly grouped for each question.
I'll answer the part of programmatically accessing controls in data binding, which is a part of your question.
Here is an example from my code. Suppose you have a very simple GridView like this
<asp:GridView ID="example" runat="server" OnRowDataBound="DataBound">
<Columns>
<asp:TemplateField HeaderText="New">
<ItemTemplate>
<asp:Image ID="imgExample" runat="server" />
</ItemTemplate>
</Columns>
</asp:GridView>
It takes a data set during data binding and sets the image according to some property. It works the same as DataList, don't worry.
Now, in code behind, you handle the RowDataBoundEvent. You can't access the imgExample object directly, because it's a child of the ItemTemplate. When the row is bound, you have direct access to the row and then you can use the FindControl method of Control class
Here is C# code example (easy to convert to VB)
protected void DataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow) //Required
{
GridViewRow row = e.Row;
[...] //get an email message
(row.Cells[0].FindControl("imgExample") as Image).ImageUrl = (email.AlreadyRead)
? "Mail_Small.png"
: "Mail_New_Small.png";
}
}
Application to your case
In order to build a multi-choice survey, my advice is to create a DataList that will hold questions (the outer control) and then, for each row, declare a RadioButtonList that holds answers (the inner control). Bind the outer data list to the data set of questions and answers. Handle the RowDataBound event or whatever it's called in the DataList world. When you handle that event, bind the inner radiobuttonlist to the answers.
It should work for you
I am actually working on something similar at the moment. I am using javascript and jQuery to dynamically add controls to my page. After adding them to my page I have to get the new controls, their text, etc. The way I've been doing it is something like this:
<table id='BuilderTable' class="BuilderTable">
<tbody class='BuilderBody'>
</tbody>
</table>
<asp:Button runat="server" ID="saveButton" OnClick="SaveButton_Click" OnClientClick="SaveData()"
Text="Save Form" />
<asp:HiddenField runat="server" ID="controlsData" />
This table is where I put all my new controls.
Then when the client clicks the save button it first calls this javascript / jQuery function:
function SaveData() {
var controlRows = $('#BuilderTable tr.control');
var controls= [];
controlRows.each(function (index) {
//process control information here ...
controlText = //use jQuery to get text, etc...
var control = {
Index: (index + 1),
Text: controlText
};
controls.push(control);
});
var str = JSON.stringify(questions);
$('#<%= controlsData.ClientID %>').val(str);
}
Then the server side function for the button click is called (this in in C#, adapt to VB).
protected void SaveButton_Click(object sender, EventArgs e)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
string str = controlsData.Value;
List<Control> controls = jss.Deserialize<List<Control>>(str);
}
Using a Control class like this:
public class Control
{
public int Index { get; set; }
public string Text { get; set; }
}
This code uses javascript and jQuery to get your controls, JSON to serialize the data and save it in a asp hiddenfield then grab the data server-side and deserialize into objects that your code can use. Then take the data and do whatever you need to.