Possible solution to UpdatePanel and ClientIDMode="Static" - asp.net

I've been looking everywhere for a solution to the static ClientIDMode + UpdatePanel in Asp.NET, as seen in http://connect.microsoft.com/VisualStudio/feedback/details/584991/clientidmode-static-in-updatepanel-fails-to-do-async-postback
The problem is in the Sys.WebForms.PageRequestManager.uniqueIDToClientID function, that converts names to id by replacing "$" characters to "".
I made a fix that seems to work but I want you guys to tell me what you think and if I'm missing something. Thanks a lot!
var old_uniqueIDToClientID = Sys.WebForms.PageRequestManager.prototype._uniqueIDToClientID;
Sys.WebForms.PageRequestManager.prototype._uniqueIDToClientID = function (arg) {
var element = this._form.elements[arg];
return (element) ? element.id : old_uniqueIDToClientID(arg)
}

We made a similar fix, but we changed another function that was involved in the search for the element that caused the postback.
We have placed the following code at the bottom of our master page to make sure that it is included after the scriptmanager has loaded its scripts. Essentially it keeps modifying the id until it finds the element that caused the postback. The original code searched for the element by removing tokens from the right hand side of the name delimited by the dollar sign. So "$ctl00$ddl001" would become "$ctl00". If you are using static ids then that suffix might never exist. We modified the function to start from the left and remove the container names until an element is found.
It seems to work for us for now. :)
if (Sys.WebForms.PageRequestManager) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm._findNearestElement = function (uniqueID) {
while (uniqueID.length > 0) {
var clientID = this._uniqueIDToClientID(uniqueID);
var element = document.getElementById(clientID);
if (element) {
return element;
}
var indexOfFirstDollar = uniqueID.indexOf('$', 1);
if (indexOfFirstDollar === -1) {
return null;
}
uniqueID = uniqueID.substring(indexOfFirstDollar + 1, uniqueID.length);
}
return null;
};
}

An updatepanel to work in asychronous mode you need to add a scriptmanager tag in the form.
<asp:ScriptManager EnablePartialRendering="true"
ID="ScriptManager1" runat="server"></asp:ScriptManager>
or you can add triggers
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ddl_Manufacturer" EventName="SelectedIndexChanged" />
</Triggers>

Related

Control in UpdatePanel not found using $find

I have a complicated page but I created a simple ASP.NET page with the issue. I have telerik RadAsyncUpload control and a button inside an UpdatePanel as shown:
<asp:UpdatePanel ID="_updatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
...
<telerik:RadAsyncUpload ID="fileUpload" runat="server" MaxFileInputsCount="1" OnClientFilesSelected="fileUpload_ClientFilesSelected" /><br />
<asp:Button ID="_saveNewFileButton" runat="server" OnClick="_saveNewFileButton_Click"
Text="Save"/>
</ContentTemplate>
</asp:UpdatePanel>
When a file is selected I want to disable the _saveNewFileButton and change the text to "Please Wait for Attachment Upload..." but I can't seem to get hold of the button reference in javascript:
var FilesUpdateInterval = null;
//Handles client side FilesSelected event for _newFileUploadButton.
function fileUpload_ClientFilesSelected(sender, args) {
//disable the click event for submit button during upload
var submitButton = $find('<%= _saveNewFileButton.ClientID %>');
submitButton.set_text('Please Wait for Attachment Upload...')
submitButton.set_readOnly(true);
if (FilesUpdateInterval == null) {
FilesUpdateInterval = setInterval(function () { FileCheckForUploadCompletion(); }, 500);
}
}
I am getting submitButton is null error. I tried putting this javascript code outside the updatepanel and inside ContentTemplate with same result. Obviously whatever I am doing is wrong. How do I get hold of the control that is in updatepanel in javascript?
EDIT: I find out that $find works with only telerik controls. So, I have to either use document.getElementById function or JQuery with something like Steve specified. Also, I have to use RegisterClientScriptBlock. I will test with Steve suggestion and then accept the answer.
short version - use $get() or document.getElementById(), as regular HTML elements are not IScriptControls, so $find() will not give you anything, and they don't have the rich client API you are trying to use.
For example
var submitButton = $get('<%= _saveNewFileButton.ClientID %>');
submitButton.setAttribute("value", "Please Wait for Attachment Upload...");
Option 2 - use RadButton.
Using jQuery and vb with ASP.Net, I've done something similar to this, which has worked well, even if it isn't that pretty. The [Whatever] I have was a FormView that didn't always have the control. Also, I didn't use it with a button, but I think that's the syntax for changing the button text. Either way, it might give you some ideas:
$('#<%=GetButtonClientID("_saveNewFileButton")%>').attr('value', 'Please Wait for Attachment Upload...');
And then I have a function like this:
Public Function GetButtonClientID(ByVal argFieldName As String) As String
Dim tmpID As String = "0"
Dim tmpButton As Button = [Whatever].FindControl(argFieldName)
If Not tmpButton Is Nothing Then Return tmpButton.ClientID.ToString Else Return "0"
End Function

Is it possible to add logic to influence the way RequiredFieldValidator behaves?

I have added textbox on the page that Jquery to create a datepicker. The problem is that, the textbox doesn't hold the value after a postback. After researching, I found the following solution which works perfectly, i.e. the textbox keeps its value after a postback.
<th>
<asp:CustomValidator ID="customStartDate" runat="server"
ErrorMessage="Start Date" Display = "None" ControlToValidate = "txtStartDate"
ValidationGroup ="HireGroup" ClientValidationFunction ="StartDate_Validate"/>
Start Date:
</th>
<td>
<asp:TextBox ID="txtStartDate" runat="server" Width = "140" ReadOnly = "true"
TabIndex = "5" CssClass = "datepicker" ></asp:TextBox>
<asp:HiddenField ID="hfDatePicker" runat="server"/>
</td>
And this is the Jquery code
//Set datePicker
function SetUpDatePicker() {
var $allDatepickers = $('.datepicker');
$.each($allDatepickers, function () {
$(this).datepicker({
showOn: "button",
buttonImage: "Images/calendar.gif",
buttonImageOnly: true,
minDate: 1,
altField: '[id*="hfDatePicker"]'
});
var $hfDatePicker = $('[id*="hfDatePicker"]');
var val = $($hfDatePicker).attr('Value');
$(this).val(val);
var len = $($hfDatePicker).attr('Value').length;
if (len > 0) {
$(this).datepicker("setDate", new Date($($hfDatePicker).attr("Value")));
}
});
}
Now I have a different type of problem. I can't use a RequiredFieldValidator for a HiddenField as I am getting an error "Hidden Field cannot be validate".
I'm tryind a CustomValidator, but the problem is that this control does acts only when the ControlToValidate is not empty.
I've checked all the property for RequiredFieldValidator and don't see something like ClientValidationFunction property.
Any suggestion on how to solve that problem?
(Based on the comment by #Richard77, I will make this an actual answer.)
You have a several options...
Instead of using a <asp:Hidden>, use a normal <asp:TextBox> but hide it using style='display:none; attribute. This will allow you to use the <asp:RequiredFieldValidator> as per your needs.
Another way to do it is using the <asp:CustomValidator> and add the ValidateEmptyText='true' attribute. This will force the validator to run the code even when the TextBox is empty.
Update - after thinking about this, I would NOT recommend the following, because it's not possible (that I can think of) to override the server-side version of the function, and therefore will leave you open to vulnerabilities. It's fine to do if you're purely using it for say visual reasons, and don't need the actual data to be checked on the server - however, this is an unusual situation.
A final option (but not one that I would necessarily recommend) is to override the function generated by ASP.NET. This would need to be placed on your page somewhere after the script link generated by ASP.NET, something like...
function RequiredFieldValidatorEvaluateIsValid(val) {
if(val.controltovalidate=="myValidatorId"){
// your coding here
} else {
return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) != ValidatorTrim(val.initialvalue))
}
}

Making ASP label visible in Javascript?

This is my label I want to display if the user have left out field before clicking the button. What am I doing wrong because nothing is happening when I click the button.
<asp:Label ID="lblError" runat="server"
Text="* Please complete all mandatory fields" style="display: none;" >
</asp:Label>
This is the function I call when I click on the button:
function valSubmit(){
varName = document.form1.txtName.value;
varSurname = document.form1.txtSurname.value;
if (varName == "" || varSurname == "")
{
document.getElementById('lblError').style.display = 'inherit';
}
else
{
.................other code go here...........................
return true;
}
}
Why not use the Validation controls? These will give you client and server side validation out of the box - not that I'm lazy or anything... ;-)
Edit for comment:
The RequiredFieldValidator can be set to display a single red asterisk by the side of each control, and a validation summary control could be used BUT that would take up space.
So, it's possible that ASP.Net is renaming your control, so your JS should read:
document.getElementById('<%= lblError.ClientID %>').style.display = 'inherit';
Give that a go...
Personally, I'd still use the Validator controls ;-)
You shouldn't be using lblError as an ID in JavaScript code. Instead you should use:
'<%= lblError.ClientID %>'
Of course this is only possible if you are generating the JavaScript code in the ASP.NET file.
on your desired event use this
document.getElementById('<%= lblError.ClientID %>').style.display = ""; or
document.getElementById('<%= lblError.ClientID %>').style.display = "block"
ok then try this, instead of client side, make it serverside. First set it invisible like , on formload event set invisible using lblEror.visible = false and remove style ="display:none" from html.
Then on the desired event/s make it visible and after processing again invisible.
If you want it strictly thorugh js.try this workaround. remove style from asp label. on body onload make it disable from some js function. now on the btn click event make it visible using the method something like this
function Validate()
{
var objLbl = $get('<%=lblError.ClientID%>');
if (validations fails)
{
objLbl.style.display = ""; //displays label
return false;
}
else
{
objLbl.style.display="none" //hides label
return true;
}
}
<asp:button id="btnValidate" runat="server" onclientclick="return validate();"/>
Hope this will work
Take a look at jquery, you can select by classes instead of id's which will never be altered when rendered onto the page (unlike id's)

hidden field value lost after postback

I have two hidden controls:
<asp:HiddenField runat="server" id="pageHeader" />
<asp:HiddenField runat="server" id="pageInformation" />
I am calling following function from master page:
show_tip(this, document.getElementById('ctl00_pageInformation').value, document.getElementById('ctl00_pageHeader').value);
and i am passing values in hidden field on .cs page in page load as follows:
string message = Request.Form["pageInformation"];
if (string.IsNullOrEmpty(message))
{
((HiddenField)Master.FindControl("pageHeader")).Value = pageHeading;
((HiddenField)Master.FindControl("pageInformation")).Value = pageInformation;
}
This is working fine, but on page POSTBACK, hidden fields lose their value. How can I retain the values after postback?
OK this is what you do.
Two functions and a hidden field. The first functions in JS adds a handler which gets the values from the hidden fields and stores them in variables. The second function in JS adds a handler which gets the values from the variables and puts them back into the hidden fields.
<script type="text/javascript">
var txt1;
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_beginRequest(BeginRequestHandler);
prm.add_endRequest(EndRequestHandler);
function BeginRequestHandler(sender, args) {
txt1 = $get('<%= hdntxt1.ClientID%>').value;
}
function EndRequestHandler(sender, args) {
$get('<%= hdntxt1.ClientID%>').value = txt1;
}
</script>
<asp:HiddenField runat="server" ID="hdntxt1" Value="" />
You don't actually need to use hidden fields however if other parts of the form need to obtain the values then those values will be handy at any time regardless of postbacks!
I guess your hidden field value is getting reset on post back.
Try keeping your code inside if block cheking for postback
if(!ispostback)
{
string message = Request.Form["pageInformation"];
if (string.IsNullOrEmpty(message))
{
((HiddenField)Master.FindControl("pageHeader")).Value = pageHeading;
((HiddenField)Master.FindControl("pageInformation")).Value = pageInformation;
}
}

TextBox causes Button Postback in ASP.NET

ASP.NET 2.0, testing in FF3 and IE7.
When I hit the 'enter' button from a text box the corresponding "OnClick" event for the first ImageButton in the page is fired. If I remove that image button, it fires the next ImageButton OnClick event on the page.
From the FireBug console, if I use JavaScript to submit the Form, this does not happen. But for whatever reason hitting enter from the textbox triggers the unrelated ImageButton event.
I found this question which had a similar problem, however the proposed answer to that solution doesn't work since ImageButtons do not have a "UseSubmitBehavior" property on them.
I don't understand why this event is firing. If I look at Request.Form, I can see that __EVENTTARGET is empty, and it is in fact posting the entire form contents (all of my textboxes), but also includes imageButton.x and imageButton.y key/value pairs.
Why is this? I suppose I could detect "enter" key presses from these text boxes with javascript, but my experience in the past is this behavior is highly variable between browsers. Any suggestions?
here's a more elegant solution
<asp:TextBox ID="TextBox1" runat="server"
onkeydown = "return (event.keyCode!=13);" >
</asp:TextBox>
read the entire post here
You could try setting a default button in an asp panel or on your form. This will let you control what happens when a user hits the enter key.
I'm having the same issue on my project.
This issue is caused because ASP.NET always will assume that the first element that inherits from IButton interface (Button and ImageButton) is the default button from the page.
Hipoteticaly, if you use an LinkButton instead of Button or ImageButton, this issue is solved.
You can find more information here on MSDN.
You can disable the Enter key from being pressed, so the user will have to click on of your ImageButtons. Just paste this javascript block onto your page:
<script type="text/javascript">
function stopRKey(evt) {
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
}
document.onkeypress = stopRKey;
</script>
Recently, I've been doing more on the client with web services and fewer postbacks. By moving my controls outside of the form element (or eliminating it altogether), the problem goes away. It's inserted by default on aspx pages, but it didn't occur to me until recently that I don't need it for much of what I do.
Its the default behaviour for an enter button press in a non text area to post back a form. You would have to handle it in a javascript method to stop the postback.
You'd just need to check the window.event.keyCode property to see if its equal to 13. If it is, reset it to 0.
function KeyPress()
{
if (window.event.keyCode == 13)
{
window.event.keyCode = 0;
}
}
I suppose I could detect "enter" key presses from these text boxes with javascript
That's what I did to get around that behaviour and it works great in IE7 and FF3. It's just a little unnatural.
Here is a generic exemple:
function TextBox1_KeyDown(sender, e)
{
var key;
if(window.event)
key = window.event.keyCode; //IE
else
key = e.which; //firefox
if(key == 13 && $("#TextBox1").val() != "")
{
WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("TextBox1", "", true, "", "", false, true));
}
return (key != 13);
}
I used WebForm_DoPostBackWithOptions because I needed validators to trigger. Otherwise, you might want to use __DoPostBack.
Here are the "prototypes":
function __doPostBack(eventTarget, eventArgument)
function WebForm_PostBackOptions(eventTarget, eventArgument, validation, validationGroup, actionUrl, trackFocus, clientSubmit)
{
this.eventTarget = eventTarget;
this.eventArgument = eventArgument;
this.validation = validation;
this.validationGroup = validationGroup;
this.actionUrl = actionUrl;
this.trackFocus = trackFocus;
this.clientSubmit = clientSubmit;
}
function WebForm_DoPostBackWithOptions(options)
Hope it helps.
P.S.: I used JQuery here but $get would be the same.
Here's an elegant solution I have found, in case anybody else has this problem (in case all other solution don't work for you, as they didn't work for me):
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Panel runat="server" DefaultButton="doNothingButton">
<ul id="shopping-list-ul">
</ul>
<asp:Button CssClass="invisible" runat="server" ID="doNothingButton" OnClientClick="return false;" />
</asp:Panel>
</ContentTemplate>
The textbox iself was inside the ul (generated by javascript).
Pressing enter will trigger the "doNothingButton", which will return false on client side, causing no postback at all!

Resources