I have the following simple aspx code:
WebForm1.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication3.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript">
function myFunction() {
document.getElementById("Label1").className = "clientAssignedClass";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label runat="server" Text="Label" ID="Label1"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Update" />
<asp:Button ID="Button2" runat="server" Text="Change at server" OnClick="Button2_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdatePanel2" runat="server">
<ContentTemplate>
<asp:Button ID="Button3" runat="server" Text="Change at client" OnClientClick="myFunction()" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
with the following cs code:
WebForm1.aspx.cs
using System;
namespace WebApplication3
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button2_Click(object sender, EventArgs e)
{
Label1.CssClass = "serverAssignedClass";
}
}
}
When I click Change at server (Button2) button and then Update button, the class attribute is retained across postbacks, but when I click Change at client (Button3) and then Update button, the class attribute is not retained across postbacks (after Update postback any changes made at client are lost).
How can I maintain changes made at client (such as a class change made by Bootstrap, i.e. active) across postbacks ?
Well I suppose it is doing what it is designed for. The view state on page is spitted into hidden field named __VIEWSTATE. As it at server side, it cannot take changes done on client side. It is a mechanism to carry back and forth information that you have on server. For more detailed introduction have a look at this article.
Your best bet to take css class set on client side is to put it into some field like hidden field so that it is posted back to server.
ViewState is used to store the state of a page and its controls as set on the server so that state gets preserved between postbacks. It doesn't "know" about changes made to the page on the client.
ASP.NET webforms wants to manage the state of your page its way - everything is done on the server and changes to the state of the page are stored in ViewState.
If you've gotten used to more client-side code, as has become much more common, then working with webforms can be a little bit frustrating for reasons like this. You're trying to maintain your page state on the client, but the page contains server controls that post back to the server. The server then re-renders the page, destroying that client-side state, because it only knows about the state that it maintains.
If possible, your life will be easier if you don't try to mix to two. If you're stuck working on an existing webforms project, try to do everything on the server. If you're creating new content and you want to manage state on the client, avoid using server controls. Just use ASP.NET as an engine to render the initial view.
If you really, really wanted to do this, you could store values in cookies or local storage, and on page load check those values to see if you need to restore some CSS class when the page loads. You could even do something really weird like put details in hidden input, and then on the server side reflect that back somehow so that when the page reloads the client-side script knows what state to (re)set.
Related
I have one registration form which contains 3 to 4 dropdown controls and 2 datepickers and now when dropdown controls value are selected(selectedindex change are fired)
then i dont want my page to postback.
I have use update panel to stop this behaviour of post like below:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<%--Update Panel for date picker%>
<asp:UpdatePanel ID="UpdatePanelDatepicker" runat="server">
<ContentTemplate>
<telerik:RadDatePicker ID="rdpDate1" runat="server">
</telerik:RadDatePicker>
</ContentTemplate>
</asp:UpdatePanel>
<%--Update Panel for Dropdown--%>
<asp:UpdatePanel ID="updatepaneldata" runat="server">
<ContentTemplate>
<telerik:RadComboBox ID="ddlCountry" runat="server">
</telerik:RadComboBox>
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</asp:UpdatePanel>
So i just wanted to ask that is this correct way to put multiple controls under update panels??
Subscribe to ajax event of initializeRequest on client-side. In this event we can cancel an ajax postback if we need to.
The initializeRequest method is raised before processing of the asynchronous request starts. You can use this event to cancel a postback.
In this event, we will check if an async postback is being initiated due to ddlCountry, and if yes then we cancel the ajax post back so no post back occurs.
To solve your problem just do the following : Add following JavaScript to your aspx page. In code below, the pageLoad method is automatically called by ASP.Net Framework on client-side when browser loads the page and after all scripts have been loaded as well as all client-side objects created.
JavaScript to cancel combobox post back
<script type="text/javascript">
function pageLoad()
{
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(CancelComboBoxPostback);
}
function CancelComboBoxPostback(sender, args)
{
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'ddlCountry') {
args.set_cancel(true);
}
}
</script>
The following is only a recommendation and not a part of the solution to your specific problem: Also, I would recommend to stay away from nested update panels as this can cause unexpected results if developer is not aware of how nested update panels work. In your situation, a single update panel should suffice as in markup below instead of nested update panels that you have used in your original markup.
Markup without nested update panels
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<telerik:RadDatePicker ID="rdpDate1" runat="server">
</telerik:RadDatePicker>
<telerik:RadComboBox ID="ddlCountry" runat="server">
</telerik:RadComboBox>
</ContentTemplate>
</asp:UpdatePanel>
Honestly, the UpdatePanel I find is more trouble than it is worth.
UpdatePanel controls are a central part of Ajax functionality in
ASP.NET. They are used with the ScriptManager control to enable
partial-page rendering. Partial-page rendering reduces the need for
synchronous postbacks and complete page updates when only part of the
page has to be updated. Partial-page rendering improves the user
experience because it reduces the screen flicker that occurs during a
full-page postback and improves Web page interactivity.
I often find the controls implementation causes more problems then it is worth. So I often implement my own Ajax services, to handle such logic. You can do this the old school way, quite easy.
// Create .aspx page, to be our service.
public class ControlUpdateService
{
protected void Page_Load(object sender, EventArgs e)
{
// Use an approach to determine which control type, and model to build.
// You would build your object, then use Newtonsoft.Json, to serialize, then
// return the object, via Response.End(object).
}
}
Then your page would Ajax the data, hit the service, then build your control via the .success in the Ajax call. If you do this approach, you commit to saving your data via Ajax as well. Keep that in mind. As I was answering this question, I can't help but feel your problem actually stems from the control doing an AutoPostback. Which you can actually disable.
AutoPostBack = "false";
Telerik may be different, but the documentation should clearly indicate how to disable this feature. Which would eleminate your need for an UpdatePanel all together. Allowing you to save your data, on PostBack correctly.
Use telerik Ajaxloadingpanel except UpdatePanel this is good for your code try this Example
<telerik:RadAjaxLoadingPanel ID="rlp" runat="server" Skin="Metro">
</telerik:RadAjaxLoadingPanel>
<telerik:RadAjaxPanel runat="server" LoadingPanelID="rlp" skin="Metro">
<telerik:RadDatePicker ID="rdpDate1" runat="server">
</telerik:RadDatePicker>
<telerik:RadComboBox ID="ddlCountry" runat="server">
</telerik:RadComboBox>
</telerik:RadAjaxPanel>
i would like to create OnClick event for my panel. So far now the most of the google results look more or less like this: adding onclick event to aspnet label. Is there any way, to call codebehind function from javascript or panel attributes? Because I would like to Redirect user to a new page and before that save some information in ViewSTate or Sessionstate. Any suggestions?
In your java script method raise a __dopostback call to a Server side method.
<script type="text/javascript">
function YourFunction()
{
__doPostBack('btnTemp', '')
}
</script>
Where btnTemp is a server side button, so write a onClick event of this button on server side, where you can do the processing and then redirect to other page.
You can have a good understanding of dopostback at DoPostBack Understanding
My aspx page is like:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<script type="text/javascript">
function CallMe() { __doPostBack('btnTemp', '') }
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:Button ID="btnTemp" runat="server" Text="Test" onclick="btnTemp_Click" />
<div> <asp:Label ID="Label1" runat="server" Text="Label1"></asp:Label>
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label></div>
</form>
</body>
And my Server Side code is as:
protected void Page_Load(object sender, EventArgs e)
{
Label1.Attributes.Add("onClick", "CallMe();");
}
protected void btnTemp_Click(object sender, EventArgs e)
{
}
Thats the code that I have written, I haven;t included the using statement, Page directive etc in above code.
There is a PostBackUrl property on a ASP.NET Button, you could render the button as normal then postback to a different page - this is where your OnClick method would need to be declared.
I would strongly recommend against posting back to the same page then doing a Response.Redirect(), consider the traffic. The browser requests the page, posts back then is sent a HttpRedirect and then navigates to the new page. With the method I have outlined above this is not required and the browser has to make one request less (meaning the message doesn't have to be sent or the page rebuilt on the server) and is a significant performance benefit.
I know this must sound really basic but I'm really stumped here. What I'm trying to do is to show a Hyperlink once a process has completed. And this process is the AsyncFileUpload. In the ASPX page, I want to create an but have it hidden on the initial page load. If I set the Style="display: none;" seems to work but after the file upload, nothing I do, will make the control visible again. When the file is uploaded, it calls a function called FileUploadComplete. It's in here that no matter what I do, the Hyperlink won't display.
Any help is greatly appreciated :)
Thank you,
dave
Here is the ASPX Code (with recently added javascript)
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="OptionsPlaceHolder" runat="server">
<script language="javascript" type="text/javascript">
function ShowLink() {
$("#openFile").show();
}
</script>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolderBody" runat="server">
<asp:UpdatePanel ID="updImportFile" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<div class="pageHeader">
<asp:Literal runat="server" ID="pageTitle" Text="<%$ Resources:Resources, ImportFile %>" />
</div>
<ajaxToolkit:AsyncFileUpload ID="FileUpload1" runat="server" Width="600px"
UploaderStyle="Traditional" OnUploadedComplete="FileUploadComplete" ThrobberID="throbber"
CompleteBackColor="#E9F2FD" OnClientUploadComplete="ShowLink" />
<asp:Image runat="server" ID="throbber" ImageUrl="images/loading.gif" />
<br />
<asp:Hyperlink runat="server" ID="openFile" NavigateUrl="~/OpenFile.aspx" Text="Open"
style="display:none;"/>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
And here is the code behind:
protected void FileUploadComplete(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
string importName = Server.MapPath(#"Uploads\") + FileUpload1.FileName;
FileUpload1.SaveAs(importName);
// Import the JSA
JSA jsa = new JSA();
jsa.Import(importName);
// Show the Hyperlink
ShowLink();
}
}
private void ShowLink()
{
openFile.Attributes["Style"] = string.Empty;
}
I didn't include the master page code. It has the ToolkitScriptManager in it.
Are you trying to show on client-side or server-side? Is the link a client-side, or server-side object? Javascript would be the standard way.
If the control is a client-side object:
document.getElementById("hyperlink_name").style.display = "block";
Or if it is a server-side object:
document.getElementById("<%= hyperlink_name.ClientID %>").style.display = "block";
I would recommend getting jQuery and using the following though:
$('#hyperlink_name').show();
Or you can use an ASP.Net Link Button and do it server-side:
linkButton.Visible = true;
It would be more helpful if you would post some of the code you have tried already so that we can get a better idea of where you are.
{first answer deleted}
[EDIT :I didn't catch that you are using AsyncFileUpload when I first read the question]
Using AsyncFileUpload inside an update panel the server is being accessed via a partial postback, as a result other controls (the hyperlink) cannot be affected on the server. This will require that you make use of javascript (or preferably jquery) to make the change on the client.
You can do it on OnClientUploadComplete function, but you have to reference the hyperlink like this: <%= hyperLink.ClientID %>.style.display = 'block';
Another more asp.net way is to use update panels. Put the hyperlink into an UpdatePanel and set a trigger on the UpdatePanel when the file is uploaded. then change the visibility on the server at UploadedComplete event.
In a simple ASP page, TextBox AutoPostBack events will prevent Button click events (except where button is tapped very quickly) and AutoPostBack events for other controls (like ListBox).
There's a similar question here, but I wasn't happy with being forced to use client side or AJAX solutions: Have to click button twice in asp.net (after autopostback textbox)
Example ASPX page:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="temp.aspx.cs" Inherits="temp" %>
<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True" OnTextChanged="PostBack"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="PostBack" Text="Button" /><br />
<asp:ListBox ID="ListBox1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="PostBack">
<asp:ListItem>value1</asp:ListItem>
<asp:ListItem>value2</asp:ListItem>
</asp:ListBox><br />
<br />
Events Fired:<br />
<asp:TextBox ID="TextBox2" runat="server" Height="159px" TextMode="MultiLine" Width="338px"></asp:TextBox></div>
</form>
</body>
</html>
C# code behind:
public partial class temp : System.Web.UI.Page
{
protected void PostBack(object sender, System.EventArgs e)
{
this.TextBox2.Text += string.Format("PostBack for - {0}\n", ((System.Web.UI.Control)sender).ID);
}
}
I've been able to partially solve this problem for buttons by using mousedown instead of click events to submit the form (I also blocked extra AutoPostBack events client-side and handled any extra field changes during button click events server side)
However, this means my buttons aren't quite behaving in the standard (click on release) way.
Is there a better solution to this problem that doesn't require trying to do everything in javascript client-side? (I'm writing a lot of code that reads server data during these postbacks, so javascript isn't an ideal solution.)
I'm also trying to avoid switching to an AJAX library for these pages since every new library I add has to go through security auditing etc.
Note: I'm currently working with ASP.Net 2.0/VS 2005, but if this type of problem is fixed in a later release that would be a compelling argument to upgrade. (As far as I understand it, the same problem seems to happen in ASP.Net 4/VS 2010)
The reason to set AutoPostBack="true" on a field (or other input control) is because you want the page to postback when that control's data changes - without requiring that the user click a button. It sounds like that is exactly what is happening: when the field loses focus, the page does a postback.
Perhaps I'm misunderstanding the question? Can you provide some more information about how you need the page/form to behave?
Edit: more info, based on comment from OP.
I think I understand: the "normal" case is they select something from a DropDownList1, and you autopostback to set the values of DropDownList2, based on the selected item in DropDownList1. However, the user may not care about the second list; if they click "search", you want the button-click to essentially abort the autopostback (already in progress), and initiate a new postback.
Unfortunately, I don't think there's any functionality in any version of ASP.NET to "abort" a postback already in progress (not from the client-side code, anyway). Therefore, in order to implement the above behavior, you're going to have to do something outside the standard ASP.NET postback behavior. Here's a few ideas, though by no means is it an exhaustive list:
Use AJAX and JS to retrieve the contents of DropDownList2. If the user clicks search while that ajax call is in progress, the page should postback right away.
Store all possible DropDownList2 data in JSON format in your page; use purely client-side JS to populate List2 when List1 changes. Again, if the user clicks "search", the page will postback right away. Depending on how big the pool of possible List2 entries is, this may bloat the page size too much to be workable.
Use client-side JS to disable your search button when List1 changes selection. The user won't be able to click "search" until the autopostback (to fill List2) completes.
Hope this helps!
To make the client side be more interactive and reduce sending all that viewstate and redrawing the page, I add a little jquery into the mix. It makes things like what you are proposing possible. jquery even ships with the asp.net MVC framework so there is no shame in using it with asp.net.
Here is a simple example that uses jquery that demonstrates what I think you want.
First, in the aspx file, add in a reference to the jquery library. I use the
Google content delivery network so you don't even have add this file to your VS project.
Then take the auto postback references out of all your server controls except the button. I left that one to continue doing a postback because I suspect at some point you want a regular post back, all the other controls use ajax to get your server side response.
I started by using your example page with these modifications:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="temp.aspx.cs" Inherits="temp" %>
<!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>Untitled Page</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
$(document).ready(function () {
// Establish where the output goes.
var outputObject = $("#<%=TextBox2.ClientID %>");
// create a function to do an ajax postback
function doAjaxPostback(sender, value) {
$.ajax({
type: "POST",
url: "temp2.aspx",
data: "id=" + sender.attr("id") + "&value=" + value,
success: function (data) { outputObject.append("<br />" + data) }
});
}
// Use jquery to wire up the event handler. We use the ClientID property in case these
// elements get embeded in some other server control container later.
$("#<%=TextBox1.ClientID %>").keyup(function (event) { doAjaxPostback($(this), $(this).val()); });
$("#<%=TextBox1.ClientID %>").change(function (event) { doAjaxPostback($(this), $(this).val()); });
$("#<%=ListBox1.ClientID %>").change(function (event) { doAjaxPostback($(this), $(this).val()); });
// Use a plain html button tag for ajax only. The server control button gets rendered as
// a submit button which requires it to be handled a little differently.
$("#PlainButton").click(function (event) { doAjaxPostback($(this), $(this).attr("value")); event.preventDefault(); });
});
</script>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="PostBack" Text="Button" /><br />
<button id="PlainButton" value="Plain Old Button">Ajax Only, No postback</button>
<br />
<asp:ListBox ID="ListBox1" runat="server" >
<asp:ListItem>value1</asp:ListItem>
<asp:ListItem>value2</asp:ListItem>
</asp:ListBox>
<br />
<br />
Events Fired:<br />
<asp:TextBox ID="TextBox2" runat="server" Height="159px" TextMode="MultiLine" Width="438px"></asp:TextBox>
</div>
</form>
</body>
</html>
Then for the code behind I just made a tiny change so we can report when we get a regular postback versus the ajax kind:
protected void PostBack(object sender, System.EventArgs e)
{
this.TextBox2.Text += "\n\nGot an asp.net postback\n\n"
+ string.Format("PostBack for - {0}\n", ((System.Web.UI.Control)sender).ID);
}
Okay, so I was trying not to get too fancy but I wanted to demonstrate how easy this is so I made a second page, temp2.aspx but left the aspx file alone as i only needed what is in the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class temp2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string id = string.Empty;
string value = string.Empty;
Response.Clear();
if (Request.Form == null || Request.Form.Count < 1)
{
Response.Write("I got nothin'");
Response.Flush();
Response.End();
return;
}
id = Request.Form["id"];
value = Request.Form["value"];
Response.Write(string.Format("\nevent from: {0}; value={1}",id,value));
Response.Flush();
Response.End();
}
}
}
Notice that what I did was clear, write, flush and end the response so only the text we want is sent back to the caller. We could have done some fancy stuff in the page_load of the original temp page to check if it is a call from the ajax function that will not clear or flush the response if the incoming Request.Form does not contain a certain field, etc. But by doing it as a separate page, I hoped to simplify the code. This also opens up possibilities.
Say you have a country drop down that has Canada and USA in it and when it changes, you want to sent back data to populate a State/Province dropdown with the appropriate values. By putting the lookup code on its own page the way I did with temp2.aspx, you can then call it from all the pages in your app that have a need for such a service.
Good luck, let me know if you have any trouble understanding my code.
I was wondering if it is possible to have a modalpopup show up on page load, saying that the page is loading. I have a page that gets a lot of data from an external source which means it takes a bit before any of the controls are actually filled.
I would like to have a popup or something similar that tells the user the page is loading.
I tried this:
<ajax:ModalPopupExtender ID="mpeLoader" runat="server" TargetControlID="btnLoader"
PopupControlID="pnlLoading" BackgroundCssClass="modalBackground" />
<asp:Panel ID="pnlLoading" runat="server" Width="100px" Style="display: none;">
<div class="detailspopup">
<table>
<tr>
<td><asp:Image ID="imgLoader" runat="server" ImageUrl="~/App_Themes/Main/img/loading.gif" /></td>
</tr>
<tr>
<td>Loading...</td>
</tr>
</table>
</div>
</asp:Panel>
with a dummy button btnLoader to allow me to access the show and hide from code behind. I've been toying with the .show method in the page lifecycle but I can't seem to find a way to have the poopup show when the page is loading (and disappear when loading is done). This would also be needed upon filtering the data, thus getting new data based on filter data.
Hard to say what the best solution is without more information, but one possible way to go is to make the first page just act as a "loader" containing the dialog and some javascript that will load the actual page with ajax.
Like I wrote before it depends very much on what you are trying to accomplish :-) !
But one way to do it with jQuery, if the page you are trying to load is very simple like a list without any state / postback controls is to create a "Loader"-page like the code belov and use the UrlToLoad query param for what page to load dynamically.
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(function()
{
$("form").load("<%= this.Request["UrlToLoad"] %> form");
});
</script>
</head>
<body>
<form runat="server">
Loading...
</form>
</body>
Have you considered using jQuery? There are some excellent modal dialog plugins available. I've used Eric Martin's SimpleModal extensively in the past, and have been very happy with it. It has hooks for callbacks both before and after displaying the dialog, so you could perform any checks you need to using functions.
Using the jQuery route - you could have a div that surrounds all the content that is still loading, and have is dimmed out/disabled with a modal dialog showing your 'page loading' message. Then you could make use of the $document.ready() functionality in jQuery to determine when the page is done loading. At this point, you could remove the dialog and fade the page in.
What I did is make a PreLoader.aspx page that will "hold" untill the page we want is loaded:
<script type="text/javascript" language="javascript">
window.onload=function()
{
$get("ctl00_ContentPlaceHolder1_btnNav",document).click();
setTimeout('document.images["Loader"].src="App_Themes/Main/img/loading.gif"', 200);
}
</script>
the button actually makes the transfer
<asp:Label ID="lblLoading" runat="server" Text="Loading the requested page. Please wait ..." />
<asp:Button ID="btnNav" Style="display: none;" runat="server" OnClick="NavTo" />
protected void NavTo(object sender, EventArgs e)
{
Response.Redirect(Request.QueryString["url"].ToString());
}
I like this as it can be reused for every heavy data page ...