I have a traditional ASP.NET GridView. Inside of it I have a Template Field with edit capabilities. I need to use a jQuery autocomplete plugin on the edit piece. It works anywhere but inside of this GridView. In other words, I know the plugin works.
Here is the ASP.NET stuff (yes, I'm using a SqlDataSource):
<%# Eval("INGREDIENT_CODE") %>
And here is the jQuery in the document.ready():
$('[id$=txtEditIngredients]').autocomplete("LookupCodes.aspx?type=IC", { mustMatch: true });
What might I be doing wrong here?
I think the best way to do it to specify a Class for the textbox and handle it based on class and not ID.
$('.AutoCompleteField').autocomplete("LookupCodes.aspx?type=IC", { mustMatch: true });
I have had problems when I tried to access controls inside gridview using ID.
HTH
you will want to use within the item template:
<%# ((GridViewRow)Container).FindControl("txtEditIngredients").ClientID %>
If you look at the source of your rendered page you will see the controls ID of the textbox in the gridview is not just txtEditIngredients, it has pre-appended information.
Another option would be to add a class to the textboxs and apply the autocomplete based on the class. This way they are not id-dependent
$('.ICLookup').autocomplete("LookupCodes.aspx?type=IC", { mustMatch: true });
Also if using the client ID, make sure you put a specific document.ready(): into the EditTemplate to make sure it is only only being called when the edit controls are visible.
Well, now that you said it is inside an updatepanel, it makes a lot more sense. The code in the updatepanel is not necessarily going to be rendered by the time your jquery runs. Doing the alert with .size like I suggested in my other answer would confirm this.
If you did a .live('autocomplete') call instead of .autocomplete(), it should work even with the updatepanel. The jQuery .live function causes the jQuery event to be added to all controls that match the selector, even if they are added after you make the call. See http://api.jquery.com/live/ for details.
You can use a class to do the selecting if you want (as others have mentioned), but to me, if you are adding a class for just that purpose and you have an ID you can select with, it seems like a waste.
I created a very simple example and it shows that the way you are doing it (with [id$=txtField] as your selector does indeed work with the plugin. Here's the .aspx code:
<head runat="server">
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="jquery.autocomplete.min.js"></script>
<link type="text/css" href="jquery.autocomplete.css" rel="stylesheet" />
<script type="text/javascript">
$(function() {
$('[id$=txtTest]').autocomplete(["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "pearl"], {
mustMatch: true
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView runat="server" ID="grdView" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox runat="server" ID="txtTest" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
And here's the codebehind updates needed to run the test:
protected void Page_Load(object sender, EventArgs e)
{
List<string> data = new List<string>();
data.Add("test");
data.Add("test2");
this.grdView.DataSource = data;
this.grdView.DataBind();
}
If you create a test webapp with this as your test page and run it, the autocomplete will work just fine.
Since this is not working for your app, you need to check to make sure that the selector you are using ([id$=txtEditIngredients]) actually matches something. To test this, put this code in place before it in your document.ready event:
alert($('[id$=txtEditIngredients]').size());
This should alert a number with the number of rows in your GridView. If it doesn't, view the source and find that text field in one of your rows to see what the ID is, and adjust your selector accordingly.
Edit: I just wanted to add that I use the [id$=controlName] all the time in jQuery/.Net because of the .Net control naming structure and it works fine every time, so this should not be an issue at all.
Related
I am developing an application in which I have a asp.net form with a lot of textboxes.I need to use the same JavaScript function for all the textboxes to validate whether it contains any non alphabetic character in it. How can I use the same method for all the textboxes? I am stuck at how could I pass the id of the textbox to the JavaScript function.
<script type="text/javascript" language="JavaScript">
function CheckAlphabet(textboxId)
{
if (!document.getElementById('<%=textboxId.ClientId %>').value.match("/^[a-zA-Z]+/"))
return false;
}
</script>
asp.net code part is like this....
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown="CheckAlphabet(TxtEmpFirstname)"
runat="server" MaxLength="100"></asp:TextBox>
The Javascript code gave an error. Please help with passing the id of the asp.net textbox. I need to use the same Javascript function for many textboxes to validate for non alphabet characters in the textbox. Please help.
Right approach would be carefully look at code and see what runs on server and what runs in the browser (i.e. print the code and mark in 2 colors)...
You onkeydown="CheckAlphabet(TxtEmpFirstname)" is mix of server side and client side intentions: you should construct client ID with server side code instead of TxtEmpFirstname and remove it from the function itself.
onkeydown="CheckAlphabet('<%=textboxId.ClientId %>')"
Try this:
function CheckAlphabet(textboxId)
{
if (!textboxId.value.match("/^[a-zA-Z]+/"))
return false;
}
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown="javascript:CheckAlphabet(this)" runat="server" MaxLength="100"></asp:TextBox>
You're on the right track. Try something like this:
<script type="text/javascript" language="JavaScript">
function CheckAlphabet(textboxId){
if (!document.getElementById(textboxId).value.match("/^[a-zA-Z]+/")) return false;
}
</script>
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown='CheckAlphabet("<%=TxtEmpFirstname.ClientId %>")' runat="server" MaxLength="100"></asp:TextBox>
Notice that the client-side script only references the contents of the variable that is passed to it. When the TextBox is rendered to the page, the inline tag (<%=...%>) will be converted into the client-side ID of the input field.
Also take note of the quote usage. When you put an inline server-side command in the property of a server-side tag, you have to wrap the property with single quotes and then use double quotes to represent literal strings in what will be the final output.
use this:
function CheckAlphabet(textboxId)
{
if (!document.getElementById(textboxId).value.match("/^[a-zA-Z]+/"))
return false;
}
<asp:TextBox CssClass="select" ID="TxtEmpFirstname" onkeydown="CheckAlphabet(this.value)" runat="server" MaxLength="100"></asp:TextBox>
javascript code will be complained after server side codes compiled
I have a strange problem to which I could not find a solution. In order to clarify my problem, I did a simply test page:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="test1.aspx.cs" Inherits="MyApplication.Web.Surveillance.Reports.test1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="scriptmanager" runat="server" />
<asp:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
<asp:Button ID="btn1" runat="server" Text="test1" />
<%= DateTime.Now %>
</ContentTemplate>
</asp:UpdatePanel>
<asp:Button ID="btn2" runat="server" Text="test2" />
<script type="text/javascript" language="javascript">
$(document).ready(pageInit);
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(pageInit);
function pageInit() {
window.location.hash = "#0";
}
</script>
</form>
</body>
</html>
In this test page, I have two button. "test1" button is inside an updatepanel. "test2" button is outside. When I run this page, I can see the url, for example "http://localhost/test/test1.aspx#0". After I click the "test1" button, I can see the url changed to "http://localhost/test/test1.aspx#". The "0" is missed. And after that, everything is ok. If I test the "test2" button. Everything is ok too.
I also find this problem only happens in IE. FireFox works fine.
My question is how can I keep the right url when I click the "test1" button?
Thanks
I found a solution. As seen on this blog.
The following stuff happens on the page :
In order to make a partial postback using the Update Panel on an ASP.NET page, one has to embed a Script Manager on the page. This Script Manager control will render a large amount of Javascript on the page, that controls like the UpdatePanel will utilize to make the snazzy partial update of the page.
This Javascript tampers with the url’s hash value, appearently to enable history and deeplinking when using Update Panels, and for some (to me still unknown) reason it changes the url, removing everything after the hash mark.
The first solution he provided worked for me. You need to add a line like that to your ASP.NET page after the scriptmanager declaration :
<script type=”text/javascript”>
Sys._Application.prototype._setState = function() {}
</script>
try to use something else than 0, for example :
window.location.hash = "#a";
I think #0 mean the scroll to the tag that name is 0 and this is not allowed by default at least in the IE none-standard :P
Instead of using window.location.hash, you also could use the href:
window.location.href = '#0';
This works in all browsers and it could be applied on every webpage.
I had a simulair problem, where I listen for hasg changes and Scriptmanager keept reseting the hash on the first postback. Pascals solution by overriding the _setState function didnt work for me, but I figure out a diffrent approch that might help someone.
$(window).hashchange(function () {
if (window.location.hash == '#' || window.location.hash == '') {
window.history.back(-1);
}
});
hashchange is a jQuery-plugin I found here
Big thanks to Pascal on this one. His solution worked. I placed it directly after the scriptmanager tag. I was seeing the behaviour in all browsers when landing on the page when the URL had a hash in it.
My page uses a function to scroll to the particular hash location using .animate and this still functions nicely with Pascal's fix:
function goToByScroll(id) {
$('html,body').animate({ scrollTop: $("#" + id).offset().top +160 }, 'slow');
}
if (window.location.hash != '') {
goToByScroll(window.location.hash.substr(1));
};
As far as I can tell there is no detriment to any other functionality on the page. I have tested the solution successfully in IE9, FF 20.0.1, Chrome 26.0.1410.64 and Opera 12.1 all on Windows 7.
If I could vote you up Pascal I would.
Simply I am trying to pass the client Id of one textBox 'txtPersonId' for the client-click event so that I can traverse to that textBox control and pass its jQuery wrapper to the loadePerson() function.
This is how I decalre it in the aspx mark-up:
<asp:Button ID="btnSearch" runat="server" Text="ARA" OnClientClick="loadPerson(jQuery('#<%=txtPersonId.ClientID %>'))"/>
But when I render it, the
<%=txtPersonId.ClientID %>
place holder stays as it is and it is not replaced with the rendered control's client Id.
Any idea why this happens and how should I overcome that?
When I've had issues like this I've resorted to wrapping the entire expression in the brackets and building the result as a string. I assume that it's because the parser doesn't recognize the render block syntax embedded inside the string property.
<asp:Button ID="btnSearch" runat="server" Text="ARA"
OnClientClick='<%= "loadPerson(jQuery(\"#" + txtPersonId.ClientID + "\"))" %>' />
I've long since moved on to keeping my javascript completely separate from my mark up, so I may be a little fuzzy on the exact details. If you wanted to separate your javascript from your mark up you could either add the handler with an explicit or relative DOM reference in a script block. Using the "ends with" selector matching on the id removes the need to find the explicit id, though you could also do that -- the example below shows both styles.
<script type="text/javascript">
$(function() {
$('#' + '<%= btnSearch.ClientID %>').click( function() {
loadPerson( $('input[id$=txtPersonId]') );
});
});
</script>
I don't know what it does your LoadPerson,but if you want write a function for your click event in Jquery you can make something like:
'#'+ '<%=txtPersonId.ClientID %>' to address your txtbox ID you can do the samething for your button $('#' + '<%=btnSearch.ClientID%>').click(function(){//click event process});
I have a simple aspx page with a few TextBoxes and a submit button. Some fields are required and below the button is a ValidationSummary. The complete form is larger than screen height so one has to scroll down to reach the submit button. If I don't fill all required fields and click on submit validation fails as expected and the validation summary displays some info messages below the button. Validation happens on the client and no postback occurs.
So this all works as wished. But disturbing is that the page moves ("jumps") to top position when I click on the submit button. To see the validation summary one has to move down the page again.
I've tried to set the ShowSummary property to false (which doesn't make much sense): The validation still works (no postback) but in this case the page does not move to top position. So the problem seems to depend on rendering the validation texts.
Is there a way to prevent this page jump?
Thank you in advance!
Update:
The behaviour I described above doesn't seem to be browser dependent. I've tested in five different browsers and it's everywhere the same.
I've asked the question on asp.net (http://forums.asp.net/p/1545969/3779312.aspx) and got replies with two solutions. The better one is this piece of Javascript which maintains the scroll position:
<script type="text/javascript">
window.scrollTo = function( x,y )
{
return true;
}
</script>
This is only to put on the page and nowhere to call.
The other solution is similar to RioTera's proposal here (using MaintainScrollPositionOnPostBack) but adds EnableClientScript="false" to the Validators to force a postback. It works too, but the price is an artificial postback.
You can use the the Page property MaintainScrollPositionOnPostBack :
In the code-behind:
Page.MaintainScrollPositionOnPostBack = true;
or in your webform:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" MaintainScrollPositionOnPostback="true" %>
Try setting the page focus Page.SetFocus(control);
I have an insert button which adds an extra row to my gridview, which is one of many items on a page so I can add Page.SetFocus(control) as the last method in my btnInsert_Click event.
I've found that setting the property:
maintainScrollPositionOnPostBack="true"
in your Web.config <pages> section works well.
The page flickers because the whole page is posted back to the server and the content is sent back from server again. You need to use UpdatePanel tag to surround the place you want to refresh. It will only postback the information which is inside the tag
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<!-- Place updatable markup and controls here. -->
</ContentTemplate>
</asp:UpdatePanel>
Read http://msdn.microsoft.com/en-us/library/bb386573(v=vs.100).aspx#CodeExamples
Unfortunately MantainScrollPositionOnPostback doesn't work anymore on modern browsers.
For a cross-browser-compatible solution you can use this snippet (requires jQuery):
<asp:HiddenField runat="server" ID="hfPosition" Value="" />
<script type="text/javascript">
$(function () {
var f = $("#<%=hfPosition.ClientID%>");
window.onload = function () {
var position = parseInt(f.val());
if (!isNaN(position)) {
$(window).scrollTop(position);
}
};
window.onscroll = function () {
var position = $(window).scrollTop();
f.val(position);
};
});
</script>
See also my answer here.
I'm using MVC5 and the only way to stop the jump was with the JQuery code below.
I've tested the solution on Safari, Chrome, Mozilla, Internet Explorer and Opera.
$(document).scrollTop($('form#formCheckout').offset().top);
event.stopPropagation();
event.preventDefault();
Disabling window.scrollTo is not a good solution because it could unknowingly break other scripts on the page.
Instead, on your ValidationSummary, set the ClientIDMode to Static and define a very unique ID, e.g.:
<asp:ValidationSummary id="VeryUniqueValidationSummaryID"
ClientIDMode="Static" ...
Next, on your submit button, set OnClientClick to scroll the validation summary back into view, like this:
<asp:LinkButton ID="MyButton"
OnClientClick="ScrollToValidationSummary();"
The Javascript function first checks if the page is valid. If not, then it scrolls the validation summary back into view after a brief timeout:
function ScrollToValidationSummary() {
if (!Page_ClientValidate()) {
setTimeout(function () {
var summary = document.getElementById('VeryUniqueValidationSummaryID');
summary.scrollIntoView();
}, 500);
}
}
Due to setTimeout not firing at the right time, occasionally the scroll position may still be off. But it should be correct for the vast majority of users.
Note: If you are using a ValidationGroup, you need to call Page_ClientValidate("ValidationGroupName") instead of Page_ClientValidate().
I can get simple examples to work fine as long as there's no master page involved. All I want to do is click a button and have it say "hello world" with the javascript in a .js file, using a master page. Any help very much appreciated :)
EDIT
As #Adam points out in the comments, there is a native jQuery mechanism that basically does the same thing as the hack in my original answer. Using jQuery you can do
$('[id$=myButton]').click(function(){ alert('button clicked'); });
My hack was originally developed as a Prototype work around for ASP.NET and I adapted it for the original answer. Note that jQuery basically does the same thing under the hood. I recommend using the jQuery way, though, over implementing my hack.
Original answer left for comment context
When you use a master page, ASP.NET mangles the names of the controls on the dependent pages. You'll need to figure out a way to find the right control to add the handler to (assuming you're adding the handler with javascript).
I use this function to do that:
function asp$( id, tagName ) {
var idRegexp = new RegExp( id + '$', 'i' );
var tags = new Array();
if (tagName) {
tags = document.getElementsByTagName( tagName );
}
else {
tags = document.getElementsByName( id );
}
var control = null;
for (var i = 0; i < tags.length; ++i) {
var ctl = tags[i];
if (idRegexp.test(ctl.id)) {
control = ctl;
break;
}
}
if (control) {
return $(control.id);
}
else {
return null;
}
}
Then you can do something like:
jQuery(asp$('myButton','input')).click ( function() { alert('button clicked'); } );
where you have the following on your child page
<asp:Button ID="myButton" runat="server" Text="Click Me" />
If your site has content pages in other folders, using the Page's ResolveUrl method in the src path will ensure that your js file can always be found:
<script type="text/javascript" src='<%= ResolveUrl("~/Scripts/jquery-1.2.6.min.js") %>' ></script>
Make sure that jQuery is being added in the master page. Given that you have this control:
<asp:Button ID="myButton" runat="server" Text="Submit" />
You can wireup the javascript with this:
$(document).ready(function() {
$('[id$=myButton]').click(function() { alert('button clicked'); });
});
$(document).ready() fires when the DOM is fully loaded, and all the elements should be there. You can simplify this further with
$(function() {});
The selector syntax $('[id$=myButton]') searches elements based on their id attribute, but matches only the end of the string. Conversely, '[id^=myButton]' would match the beginning, but for the purposes of filtering out the UniqueID that wouldn't be very useful. There are many many more useful selectors you can use with jQuery. Learn them all, and a lot of your work will be done for you.
The problem is that ASP.Net creates a unique id and name attribute for each element, which makes finding them difficult. It used to be that you'd need to pass the UniqueID property to the javascript from the server, but jQuery makes that unneccessary.
With the power of jQuery's selectors, you can decouple the javascript from the server-side altogether, and wireup events directly in your javascript code. You shouldn't have to add javascript into the markup anymore, which helps readability and makes refactoring much easier.
Just move the <script type="text/javascript" src="jquery.js" /> tag into the head tag in the master page. Then you can use jquery in all content pages.
There is no magic about using master pages with jQuery.
Adam's solution is the best. Simple!
Master page:
<head runat="server">
<title></title>
<link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.3.2.js" type="text/javascript"></script>
<asp:ContentPlaceHolder ID="HeadContent" runat="server">
</asp:ContentPlaceHolder>
</head>
Content page:
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script type="text/javascript">
$(document).ready(function () {
$("[id$=AlertButton]").click(function () {
alert("Welcome jQuery !");
});
});
</script>
</asp:Content>
where the button is
<asp:Button ID="AlertButton" runat="server" Text="Button" />
Reference the the Jquery .js file in the head of the MasterPage as follows:
<script type="text/javascript" src="/Scripts/jquery-1.2.6.min.js"></script>
(some browsers don't like ending it with />)
Then you can write things like
$('#<%= myBtn.ClientID%>').show()
in your javascript making sure to use the ClientId when referencing an ASP.Net control in your client code. That will handle any "mangling" of names and ids of the controls.
Master page:
The jQuery library goes in the master page. See if the path is correctly referenced. You might like to add the extra documentation like this:
<head>
<script type="text/javascript" src="/Scripts/jquery-1.2.6.min.js"></script>
<% if (false) { %>
<script type="text/javascript" src="/Scripts/jquery-1.2.6-vsdoc.js"></script>
<% } %>
</head>
Master page:
<head>
<script type="text/javascript">
$(document).ready(
function()
{
alert('Hello!');
}
);
</script>
</head>
CodeBehind for content pages and user controls:
this.textBox.Attributes.Add("onChange",
String.Format("passElementReferenceToJavascript({0})", this.textBox.ClientID));
Check out this post:
http://blogs.msdn.com/webdevtools/archive/2008/10/28/rich-intellisense-for-jquery.aspx
also explains how to get intellisense for jQuery in Visual studio.
When pages are rendered along with master pages, control id gets changed on page rendering so we can't refer them in jQuery like this #controlid. Instead we should try using input[id$=controlid]. If control is rendered as input control or if as anchor tag use a[id$=controlid] in jQuery.
In case if some one wants to access a label, here is the syntax
$('[id$=lbl]').text('Hello');
where lbl is the label id and the text to display in the label is 'Hello'
I also started with the simplest of examples and had no luck. I finally had to add the jquery .js file outside of the <head> section of the master page. It was the only way I could get anything to work in Firefox (haven't tried other browsers just yet).
I also had to reference the .js file with an absolute address. Not entirely sure what's up with that one.
Adam Lassek linked to using jQuery selectors, though I think its worth explicitly calling out selecting elements by their class, as opposed to their id.
e.g. Instead of $("#myButton").click(function() { alert('button clicked'); });
instead use $(".myButtonCssClass").click(function() { alert('button clicked'); });
and add the class to the button:
<asp:Button ID="myButton" runat="server" Text="Submit" CssClass="myButtonCssClass" />
This has the benefit of not having to worry about whether two control ids 'end' the same way in addition to being able to apply the same jQuery code to multiple controls at a time (with the same css class).
PROBLEM --> when using Site.Master pages the control id names (for ASP controls) get the ContentPlaceHolderID prefixed to them.
(Note this not a problem for non-asp controls as they don't get 'reinterpreted' - i.e. they just appear as written)
SOLUTIONS:
Simplest --> add ClientIDMode="Static" to the asp control definition (or set with properties) in aspx page
Alternatives include:
Hardcoding the ContentPlaceHolderID name in the js code e.g "#ContentPlaceHolder1_controlName" - eek!!!!
using the <%= controlName.ClientID %> in the ASP page - plus, assigning it - there- to a variable (or object of variables). The variable (or object dot notation) can then be used in external js page
(NOTE: Can't use <%= controlName.ClientID %> in external js)
Using CssClass with a unique(same name as ID) in ASP page and refering to the control as ".controlName" instead of "#controlName"
Using the "[id$=_controlName]" instead of "#controlName" - this is involves a small search and is looking for a control that ends with the unique name - that way the start is irrelevant