AutoPostback with TextBox loses focus - asp.net

A TextBox is set to AutoPostback as changing the value should cause a number of (display-only) fields to be recalculated and displayed.
That works fine.
However, when the field is tabbed out of, the focus briefly moves on to the next field, then disappears when the page is redrawn so there is no focus anywhere.
I want the focus to be on the new field, not the textbox I've just changed.
Is there a way to work out which field had the focus and force it to have it again when the page is redrawn?

This is "by design". If you are using ASP.NET 2.0+ you can try calling the Focus method of your TextBox once the postback occurs (preferably in the TextChanged event of the TextBox).
I am not sure if there is any built-in way to track focus but I found this article in CodeProject which should do the trick.

You could also consider refresh display-only fields using AJAX UpdatePanel. This way you won't lose focus from the new field.
Also I have proposed pure server-side solution based on WebControl.Controls.TabIndex analysis, you can use it, if you like.

This is what is happening:
1) TAB on a field - client event
2) Focus on next field - client event
3) Postback - server event
4) Page redrawn - client event new page overrides preious client events
The solution of your problem is to:
a) get the element that has gained focus BEFORE postback
<script>
var idSelected;
$("input").focusin(function () {
idSelected = this.id;
});
</script>
b) store the ClientID (actually in var idSelected) somewhere (i.e. an hidden Textbox, vith ViewState = true) BEFORE postback
** b) get ClientID ** (extract from hidden TextBox and put it in var idSelected) AFTER postback
d) get the element with ClientID and set focus AFTER postback
<script>
$(document).ready(function () {
if (idSelected != null) {
$("#" + idSelected).focus();
idSelected = null;
});
});
</script>
Note: this sample scripts use JQuery.
Remember to put Jquery.js in your solution and a reference in your page
<form id="form1" runat="server" enctype="multipart/form-data" method="post">
<asp:ScriptManager runat="server" >
<Scripts>
<asp:ScriptReference Path="~/Scripts/jquery.js" ScriptMode="Auto" />
....
Note2: this solution works without AJAX.
Look at this answer: to make Javascript work over Ajax you must use code like this:
<script type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler);
function EndRequestHandler(sender, args)
{
MyScript();
}
</script>

Related

Validation based on visibility of a label

I like to add a validation on a label based on its visibility, in that a submit button will raise a validation message or error if the label is not visible.
I am used to the validation controls in the Toolbox, which wont allow this functionality!
It seems as though if an asp:Label's visibility is set to false, the asp.net engine will not even put it in the DOM. So you can check in javascript, using the onclick property of the (html) button to check if the label is in the DOM or not, and use asp.net's __doPostBack() javascript function to post back to the server if it is there:
<script type="text/javascript">
function testMe()
{
var lbl = document.getElementById('lblTest');
if(lbl == null)
document.getElementById('msg').innerHTML = "Error";
else
__doPostBack('testButton');
}
</script>
<asp:Label ID="lblTest" runat="server" Visible="false" Text="Hello"></asp:Label>
<button onclick="testMe();">test</button>
To be completely honest, I thought the lbl would be undefined if the label did not exist in the DOM, but Firebug revealed it is actually null. Anyway, a couple things to note is that in order for asp.net to define the __doPostBack() method, I believe you need some control in the form that has autopostback="true", and in the code-behind you can check what caused the postback in the Page_Load method like so:
if(Request.Form["__EVENTTARGET"] == "testButton") {}

How to change the visibility of CascadingDropDown control

What is the preferred method to change the visibility property of a .NET Ajax Control Toolkit CascadingDropDown control? I would like to render the control "invisible" when a null value is returned from a query.
It appears that "OnSelectedIndexChanged" event does not fire from the <asp:DropDownList> when using the toolkit extender.
Honestly, I would just target the DropDownList that the CascadingDropDownExtender is attached to with the display:none css style. You could do this in javascript on the page like this:
<script type="text/javascript">
function hideDDL(){
// Get the DropDownList by its ID value
var ddl = document.getElementById("<%= myDropDownList.ClientID %>");
// If there are no items in the drop down, hide it
if (ddl.options.length == 0)
ddl.style.display = "none";
}
</script>
And then, in your DropDownList markup, just add the function above to the client-side onchange event:
<asp:DropDownList runat="server" ID="myDropDownList" onchange="hideDDL();" ... >
...
</asp:DropDownList>
Note: Obviously, you will want logic in the javascript function to indicate whether or not the DropDownList should be hidden (such as checking to see if the control has no elements to select, etc). If you have trouble with that, let me know and I can try and help with that too.
EDIT: I have added a possible example of said logic =)

ASP.NET TextBox's OnTextChanged server event should fire some client code before going to server

My UserControl has a TextBox, that is subscribed to OnTextChanged event. However, since a lots of business logic and integrations happens on server, I want to disable a form while postback is being performed with some client-side javascript and I'm not sure how to achieve it the right way.
Can I solve this with ClientScriptManager.GetPostBackEventReference?
Edit: as my question seems to be misunderstood:
TextBox is subscribed to event OnTextChanged="tb_TextChanged" which will result on client in onchange=__doPostBack('tb') so I want to inject my javascript disableForm() to onchange DOM event. I know how to implement disableForm(), the question is how to inject my javascript properly?
I would suggest you use the javascript onblur event and check if the field value is changed. If so, you can use jQuery like the below to disable the form elements.
To disable a form element such as a text input or a button (with a made-up id: #elm):
$("#elm").attr("disabled", "disabled");
To enable a disabled form element:
$("#elm").removeAttr("disabled");
You should be able to do this with some simple JavaScript:
<script type="text/javascript">
disableFormFields = function(){
if (document.all || document.getElementById){
for (i = 0; i < document.forms[0].elements.length; i++){
var el = document.forms[0].elements[i];
if (el){
el.disabled = true;
}
}
}
}
</script>
<asp:TextBox ID="TextBox1" runat="server" onchange="disableFormFields();" OnTextChanged="TextBox1_TextChanged" />

How can I prevent a page to jump to top position after failed validation?

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().

Disable a button on click

I have a button control. Once the user clicks on it, the click event should fire and then the button should get disabled. How can I do this? I have the option to use JQuery or JavaScript or both.
Here is my button declaration:
<asp:Button
ID="Button1"
runat="server"
Text="Click Me"
onclick="Button1_Click"
/>
On the button click code behind, I have added a Response.Write(). That should get executed and then the button should be disabled
For whatever reason, the HTML spec dictates that disabled elements should not be included in POST requests. So, if you use JavaScript to disable the HTML element in the client-side onclick event, the input element will be disabled when the browser assembles the POST request, the server won't be properly notified which element raised the postback, and it won't fire server-side click event handlers.
When you set the UseSubmitBehavior property to false, ASP.NET renders an input element of type button instead of the regular input of type submit that the ASP.NET Button control normally generates. This is important because clicking a button element does not trigger the browser's form submit event.
Instead of relying on a browser form submission, ASP.NET will render a client-side call to __doPostBack() within that button element's onclick handler. __doPostBack will raise the postback explicitly, regardless of what POST data comes through in the request.
With the postback being raised independent of the browser submit event, you're freed of the previously mentioned HTML quirk. Then, you can set an OnClientClick of "this.disabled = true;", which will render as "this.disabled = true; __doPostBack('Button1', '');", and things will work as intended.
add an OnClientClick="this.disabled = true;" to your button.
If you are using Asp.net Ajax you might want to look at using PostBack Ritalin.
Have you tried this?
Add an OnClientClick="MyFunction();" to your .NET button.
Then in the .aspx page script tags you add the following JS function:
<script type="text/javascript">
function MyFunction()
{
window.setTimeout(function ()
{
// get the button/control to disable using your favourite clientside ...
// ... control grabbing code snippet ...
// ... eg. JQUERY $('Button1'), getElementById, etc.)
document.getElementsByName('Button1').Button1.disabled = true;
// I've used "getElementsByName" because .NET will render a button with
// ... a "name" attribute, and not an "id" attribute, by default
}, 1);
}
</script>
This gives the browser a chance to post back, followed by a quick button disable.
You need to be careful that the postback occurs before you disable the button through client script. This is a common gotcha with ajax and input boxes. Disabling an input box prevents the data from being sent from the browser, even if you can see text within it while it is disabled. The answer is that you need to use jquery for this to ensure the server-side code runs first before it is disabled.
-Oisin
// to disable
this.setAttribute('disabled', true);
// to enable
this.removeAttribute('disabled');
this is a cross browser solution
There is really cool event for body tag "<"body onBeforeunload="buttonId.disabled = true;" ">"
This event triggers right before form submits, in other words your data will be submitted correctly.
When using the "this.disabled = true" method make sure you check if the page is valid before disabling the control if you have validators on the page. If validation fails you won't be able to re-enable the control without reloading the page.
if (Page_IsValid) this.disabled = true;
<script type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler);
function BeginRequestHandler(sender, args) {
document.getElementById('<%= lblMessage.ClientID %>').innerText = "Processing...";
document.getElementById('<%= btnSubmit.ClientID %>').innerText = "Processing";
args.get_postBackElement().disabled = true;
}
</script>
Add Script Tag in source page . change Id of button in code . You can disable the button till the process completes execution .
you can disable it server side
Button1.Enabled = false;

Resources