I have a page with multiple CustomValidators and I want the focus to be brought to the offending validator when there is an error. I know this is possible with client side validation, but is it possible with server side?
Additionally, the CustomValidators are located in different parts of the page so I can't simply scroll the page to one general location when there is any validation failure.
I have tried:
SetFocusOnError
CustomValidator.Focus() immediately after validation, after the button click, and in Page.PreRender()
Thanks in advance
Thanks to a colleague, I have a solution to this question. It's so simple I wish I had come up with it! Just inject javascript when the validator fails and that javascript will be executed on postback.
Private Sub CustomValidator_ServerValidate(ByVal source as Object, ByVal args as System.Web.UI.WebControls.ServerValidateEventArgs) Handles CustomValidator.ServerValidate
If someCondition Then
args.IsValid = True
Else
args.IsValid = False
System.Web.UI.ScriptManager.RegisterStartupScript(Me, Me.GetType(), "JumpToValidator", "jumpToValidator(validatorId);", True)
End If
End Sub`
where jumpToValidator(validatorId) is a javascript function that scrolls to the element passed in as an argument.
Related
I have the following simple test asp.net form, with following vb.net load event:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim strScript As String
strScript = "function MyMsg()"
strScript += "{"
strScript += "alert(document.getElementById('TextBox3').value);"
strScript += "}"
ClientScript.RegisterStartupScript(Me.GetType(), "MyMsg", strScript, True)
End Sub
It simply displays the contexts of a text box in the web page when the script is called.
I then have this button code:
Protected Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
If ClientScript.IsStartupScriptRegistered("MyCall") Then
Me.TextBox3.Text = "My text - registered"
Else
Me.TextBox3.Text = "my text NOT registered"
End If
ClientScript.RegisterStartupScript(Me.GetType(), "MyCall", "MyMsg();", True)
End Sub
However, the button when clicked on always shows the text NOT registered. So, the code seems to run ok. It grabs the text from the text box no problme. However, the True part of the code never runs.
Is this a state or scope issue? (or the the fact that the code is only injected one time) that prevents this from running the code block for true?
How can I get the "true" part of the above code to run?
Consolidating(and elaborating on) the comments on the original question here.
The issue is that ASP.NET buttons cause full post backs to the server everytime they are clicked and when a page does a full postback it resets all scripts that may have been registered from previous actions. This means that any script that was registered the last time the button was clicked will be wiped out and the page will not know anything about it the second time around.
There are a few ways to get around this.
UpdatePanel: My prefered way is to declare all your controls that need to be manipulated in the button click handler inside an AJAX Update Panel like:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
What this does is limits what the button can change when it is clicked and causes a post back. In order to use this you will also need to declare a Scriptmanager anywhere before the updatepanel. When you register the script you will need to use that scriptmanagers RegisterScriptControl function.
Manual AJAX Postback: Another way to accomplish this would be to use a "manual" AJAX call. I've done this a few times but it is much more complex than the update panel version and I'm not sure if the way that I've done it is the "right" way to go about it. First you will change you ASP button to a regular HTML input button. On the HTML button the onclick should be a javasciprt function that you designate. Inside the javascript function you will need to go through the process of declaring an XMLHttpRequst object. This site goes over how to use the object pretty thoroughly. The way that I have gotten information back and forth is by using the headers attached to the request/response. You need to add them using setRequestHeader function and get them from the getAllResponseHeaders function. Once you get into the page load event on the server side you will need to evaluate the headers of the request and if one exists that signifies that the button was clicked(which you will need to add manually) then you can call a function and add a header to the response that will tell the javascript what to display in the pop up box. I'm sure using headers isn't the best method for getting inormation back and forth but if you are just talking about booleans that only dictate what to print to the user then you probably don't need to go through the process of setting up a JSON or XML response. This is also assuming that you are doing more on the server side than just checking how many times the button has been clicked because if thats all you need to do you should use option 3.
The simplest way to accomplish this would be to make the entire thing a javascript function. Declare a variable(int) on the page and set it to 0 on load. Then when the button is clicked you would just need to check the counter, if its greater than 0 display one message, if its 0 then display a different message. This will only work if your condition is very basic(it can get very complex but sometimes thats overkill).
So, In my opinion, those three options should be able to handle whatever you need to do. The first is very simple to use, the second is very versatile and can become very powerful if you implement XML or JSON in your communications with the server and the third is much faster than communicating with the server every time. Deciding which will be the best fit is up to you.
You did not add the script tag to enclose your script.
Adding function
strScript = "<script type=\"text/javascript\">";
strScript = "function MyMsg()"
strScript += "{"
strScript += "alert(document.getElementById('TextBox3').value);"
strScript += "}"
strScript = "</script>";
ClientScript.RegisterStartupScript(Me.GetType(), "MyMsg", strScript, True)
Calling function
ClientScript.RegisterStartupScript(Me.GetType(), "MyCall", "<script type=\"text/javascript\">MyMsg();</script>", True)
I researched this problem here on SO and tried the apparent solution which did not work, so here it is:
I have a very complex form with among other controls, three autocompleting textboxes.
I also have a client who cannot seem to stop entering a value in the textboxes and hitting the Enter key to select the desired value from the autocomplete list.
When they hit Enter, the first imagebutton in the form fires, doing something completely different. So to them, the form is broken.
What I need to do is to prevent the Enter key from firing these imagebuttons (there are 10 of them in the form).
I have tried the following code in both Page_Load and Page_LoadComplete, neither of which work:
imgbtn1.Attributes.Add("onkeydown", "return (event.keyCode!=13);")
Any advice that saves me a few hairs is appreciated.
One good solution can be found here:
Disable Button click, ImageButton click and/or form submit on Enter Keypress
Adding Markup from Link
<form id="form1" runat="server">
<input type="submit" style="position:absolute;left:-100px;top:-100px;width:0px;height:0px;" onclick="javascript:return false;" />
<!-- other form controls below this line -->
</form>
Did you check these two references
http://www.bloggingdeveloper.com/post/Disable-Form-Submit-on-Enter-Key-Press.aspx
http://www.webcheatsheet.com/javascript/disable_enter_key.php
They are essentially doing the same thing you are trying, just that they are hooking it up to a different event. Also make sure that your Javascript is foolproof i.e. if javascript has some errors, then your end result may not be as expected.
The second link Subhash Dike posted (Disable Enter Key) worked for me. I have two ImageButtons and they both don't fire a postback when using this function (bit modified from the original) which is great.
document.onkeypress = function (evt) {
return ((evt) ? evt : ((event) ? event : null)).keyCode != 13;
};
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.Page.Form.DefaultButton = BtSearch.UniqueID
If Not IsPostBack Then
' ...............
End If
End Sub
I had a similar problem.
Listview1.ImageButton was responding to ENTER.
We really want a SAVE to happen (or nothing, but the bad behaviour was reloading the page and that made them grumpy)
Set up a handler for the window to catch events. I do this in docReady()
function docReady() {
$(document).keydown(mapKeyCode);
};
In that handler, find the keycode you want to capture ( enter is 13)
https://css-tricks.com/snippets/javascript/javascript-keycodes/
function mapKeyCode(event) {
{
if (event.keyCode == 13) {
//event.stopPropagation();
//event.preventDefault();
__doPostBack('ctl00$cp1$InventoryPieces$btnSubmit', '');
}
}
event.StopPropogation will cause nothing to happen.The keystroke is simply eaten. That may be what you want. You are still free to call an ajax method below, that's not part of the event.
event.PreventDefault is supposed to stop the event from doing what it normally does. I had troubles seeing a difference w/ this line commented out or not. There is in depth discussion on preventDefault and ENTER here on SO.
This 3rd line is what the people who pay me want to have happen when they hit the ENTER key even though they probably should be hitting tab. I tried (#).trigger() and didn't have a lot of luck. Inspecting the element, I saw that it was calling __postback, so I pasted that in. I'm reasonably certain ().Trigger would work if i figured out what i was doing wrong, I just took another route.
This is hackish to me, but it accomplishes the objective.
Hope it helps.
What is this keyword how can use it?
If Page.IsPostBack = False Then
IsPostBack
Here is an overview of IsPostBack from MSDN:
http://msdn.microsoft.com/en-us/library/system.web.ui.page.ispostback.aspx
It quotes:
true if the page is being loaded in
response to a client postback;
otherwise, false.
The postback is useful, say for example you have a Literal control on the page, and the code on page load sets the Literal.text += "hello"; If you have a button on that page, and press it, the text of the literal will get longer and longer, hellohellowhello, if you wrap the code in (c# example):
if(!Page.IsPostBack){
Literal.text += "hello";
}
The Literal text now wont expand when the button is pressed.
Other Notes
Instead of:
If(Page.IsPostBack = False)
Do:
If(!Page.IsPostBack)
This is logically the same and is generally accepted to be a better way of writing the statement.
Also you marked the question C#, but the If syntax you used indicates you are writing it in VB.net, not C#.
Gets a value indicating whether the page is being loaded in response to a client postback, or if it is being loaded and accessed for the first time.
Return Values:
true if the page is being loaded in response to a client postback; otherwise, false.
http://msdn.microsoft.com/en-us/library/system.web.ui.page.ispostback.aspx
The IsPostBack tells you whether or not the page has been Posted Back, meaning "server side" button has been clicked.
You can "use" it by reading its value and acting upon it.
It's useful for example when you add controls dynamically to your page, so you don't have to add them when it's a PostBack.
Official documentation already been posted by others, look there for any further or technical details.
I have a situation where I need to ignore parts of page load sub inside a isPostback = true. Basically inside the isPostBack I want something like if button1 caused postback.... do this else do this...
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = True Then
If TextBox1.Text <> String.Empty Then
CheckDate()
End If
End If
End Sub
I think what you need is the reference to the control name which triggered the postback.
http://geekswithblogs.net/mahesh/archive/2006/06/27/83264.aspx
Implement the solution which is there in the above link (Got it from here.... How to Get Source of postback)
If the control name is your button then do not do what needs to be done upon postback.
HTH
You should probably not have all this going on inside the Page_Load event. Instead, you should be handling events for each control that can cause a postback. This helps with code clarity, and ease of maintenance, not to mention better control in the first place.
Here's a nice brief blog entry I found on the subject: http://www.sitepoint.com/blogs/2007/01/21/page_load-is-evil/
Incidentally, handling events is much different in ASP.NET than in other environments, My guess, just based on the fact that you're trying to accomplish this in the Page_Load event is that you're not yet "getting" the event-driven programming model. (If I'm wrong, I apologize, I don't mean to be insulting).
If I'm right, however, once you get used to it, it's going to be a lot simpler for you than things were in the classic ASP days, for example, where you had to do things like try to figure out which button was clicked. Here's another nice article to explain this further: http://articles.sitepoint.com/article/driven-asp-net-development-c
It's hard to see this as a good idea. From the short snippet you posted, it looks like what you really need is a Validation control attached to your textbox.
Have a look at the POSTed items. You should see some sort of reference to that button in there. IIRC, if it was clicked, you will see some sort of reference in there, and if it wasn't it wouldn't be in there.
I had this same problem a while a ago and that's how I circumvented loading some stuff.
My asp.net page dynamically displays 207 questions (I can't control this). Each question have 10 validators. When ASP renders the page it creates following three lines for each validator:
var qsnQuestionSet_adult_qcQuestion_1_vldMaxAnswersValidator = document.all ? document.all["qsnQuestionSet_adult_qcQuestion_1_vldMaxAnswersValidator"] : document.getElementById("qsnQuestionSet_adult_qcQuestion_1_vldMaxAnswersValidator");
qsnQuestionSet_adult_qcQuestion_1_vldMaxAnswersValidator.display = "Dynamic";
qsnQuestionSet_adult_qcQuestion_1_vldMaxAnswersValidator.evaluationfunction = "CustomValidatorEvaluateIsValid";
Althrough these three lines are just 4kb you can imagine that 4*10*207 is quite a lot. How can I mark all validators as dynamic and set evaluationfunction to same value without asp generating the line for me?
This code is generated automatically by ASP.NET when the EnableClientScript option is set to true. As far as I'm aware the only way to get rid of it would be to set this to false however the obvious drawback is the validation will only happen on the server side during a postback.
To get around this you could tie the custom javascript validation function to the related control event such as a textbox onBlur event but without knowing more detail about what values you are trying to validate it is difficult to speculate further as to whether this could be a solution.
This javascript is rendered to the client by the AddAttributesToRender() method of the BaseValidator & CustomValidator classes from the System.Web.UI.WebControls namespace. Take a look at them in Reflector.
Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)
...
If (enumValue <> ValidatorDisplay.Static) Then
Me.AddExpandoAttribute(writer2, clientID, "display", PropertyConverter.EnumToString(GetType(ValidatorDisplay), enumValue), False)
End If
...
MyBase.AddExpandoAttribute(writer2, clientID, "evaluationfunction", "CustomValidatorEvaluateIsValid", False)
End Sub
You could write your own class to replace CustomValidator and change the way that it renders.
But, in this case I think it would be better to write your own javascript to handle validation and not use the validator controls.
P.S. If you're worried about the size of the HTML the first thing you should do is enable gzip compression on your IIS server.