I have an asyncfileupload control inside an update panel. The file succesfully upload and fires the correct server side code. The code on the server is exected as expected however, one line in the server code changes the text on a label. I step through the code in debug mode and the line is executed but no change is made to the page.
Here's some of the code:
<asp:UpdatePanel runat="server" ID="updater" >
<ContentTemplate>
<asp:AsyncFileUpload ID="fileUpload" runat="server" OnUploadedComplete="FileUploadComplete" />
<asp:Label ID="AsyncText" runat="server" Text="File Type not checked" />
</ContentTemplate>
</asp:UpdatePanel>
public void FileUploadComplete(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
System.Threading.Thread.Sleep(500);
if(fileUpload.HasFile) { AsyncText.Text = "file of correct format: "; }
}
Can anyone help me with solving this problem or offering annother solution??
Thanks
I think you are going to have to move toward a different solution. From your label message, it looks like you are trying to check the file type, correct? Basically, the AsyncUplaod control, although posting back to get the uploaded file to the browser, is not actually updating the page's viewstate, thus the label never gets updated. Boo! I was able to visualize this using this code in the page load event.
if (Page.IsPostBack)
{
if (Request.Files.Count > 0)
{
AsyncText.Text = "file of correct format";
ListItem item = new ListItem("item to add");
lb.Items.Add(item);
}
}
This was allowing me to set the label text but still nothing changed until I clicked on a random button that I added to the page. This button didnt even have an event in the code behind, but it was enough to cause a normal postback, and the label text and list item were successfully updated/added to the list. With that said, I would wait to update any labels until the user clicks upload by using a seperate upload button. (ie use the AsyFileUplaod to get it to the browser, but another button to save the file to the server). You can always do file evaluations in the button click event by referencing the posted files to the webpage as I did in the code above.
Some other examples I found online were using javascript to change the label text which works well also. Somthing like this:
string message = "";
if (e.StatusMessage == "Success")
{
message = "File upload successful;";
}
else
{
message = "File did not upload successfully;";
}
ClientScript.RegisterStartupScript(this.GetType(), "akey", "document.getElementByID('label').value =" + message, true);
Another example: here
I think in this case it's just the nature of the control and the only way to achieve what you want is though some creative thinking. If you have any other questions about anything I listed here feel free to ask.
Good luck!
Where is the label positioned, inside or outside the update panel? Seems like the partial page update may not be including the update to the label text. I would say move the label around as the simplest suggestion, but you could also try something like RegisterStartupScript which will change the lable text via javascript. This should still give you server side control over what text to display based on what happens during the upload.
If you could post some code that would be great.
Related
I have a WebForm ASP label and button. I am setting the label's value on page load. For example, the label text on page load is 2 items selected. This comes from the database. Then if the user changes the selection then it counts the selected values by jQuery and sets the text as 5 items selected.
When I click on the submit button to save changes, again it resets to 2 items selected. I didn't use an update panel. I don't know what is going on here. Can anyone please explain this scenario?
$("#lblCount").text($('#grdProducts').find('input#chkSelect:checked').length + ' Complementary Products added');
C# on page load:
lblCount.Text = ComplementaryproductCount.ToString() + " Complementary Products added";
I do not understand why the label text is changed on button click. I couldn't find anything while debugging too.
Thanks
When you set lblCount.Text in your code, that value is set into the ViewState of the page... that means when your page is posted back to the server (to handle an event, etc) ASP.Net knows what lblCount.Text was originally and can re-render the HTML with the same value.
As part of that post-back to the server, the browser will send back that ViewState along with any input control values (things like textboxes, dropdowns, hidden field).
What it does NOT do is post-back any changes you might have made to the elements on the page via things like jQuery (other than input controls I mentioned above).
The result is that although you've changed the element on the screen, the server knows absolutely nothing about that change, and it will re-send the original HTML for the label back to the browser.
Your only option is to do something as suggested by #John in his comment... you need to store the fact the element has changed in an input, and then use that.
For instance...
<asp:Label runat="server" id="lblCount" />
<asp:HiddenField runat="server" id="hdnCount" />
function updateCount(newCount) {
$("#<%=lblCount.ClientID%>").text("Count: " + newCount.toString());
$("#<%=hdnCount.ClientID%>").val(newCount.toString());
}
Then in your code-behind you can have...
if (!Page.IsPostBack)
{
var count = 1;
lblCount.Text = String.Format("Count: {0}", count);
hdnCount.Value = count.ToString();
}
else
{
lblCount.Text = String.Format("Count: {0}", hdnCount.Value);
}
I'm developing an asp.net application and I need to call a confirm dialog box on the code behind. And after that, I need to get the user's click (if he clicked at OK or Cancel).
If he clicked the OK button of the dialog, I must continue to running the code where I stopped before call the dialog.
To solve this problem I thought in put at the aspx an input of type button, and set it's style to visibility:hide. So, when the users click on the OK button the programm will call this hidden button which calls a method that will continue the job stopped.
I'll post my code, I expect it might help.
The code below is on my code behind, and it calls the confirm dialog.
System.Web.UI.
ScriptManager.RegisterClientScriptBlock(this, GetType(), "__Mensagem", "if (confirm('" + CustomMessage + "')){document.getElementById(\'<%=btnSave.ClientID%>\').click();}", true);
The code below is on my aspx, it's the "hidden" button.
<input style="visibility:hidden;" id="btnSave" runat="server" onclick="btnSave_Click"/>
I don't know why isn't working. The error that I receive after click on the button OK of the confirm dialog box is the following: Erro em tempo de execução do Microsoft JScript: 'document.getElementByID(...)' é nulo ou não é um objeto
I'm from Brazil so the error is in portuguese, a translation to english it's something like this:
"A runtime error occurred on Microsoft JScript 'document.getElementByID(...)' is null or is not an object"
I give a look at the html code of the page and I notice that the button isn't there.
Maybe it's because I'm using an UpdatePanel, but when I removed it (just for tests, I must use the Update Panel), the same error is showed, and in this time the button were on the page's html code.
A stab in the dark.
In your code-behind have you set btnSave.visible = false;? If so, this would prevent the button from being rendered to the HTML.
Also, is there any reason you're not using the ASP:Button control, rather than a mix of HTML with runat="server"?
Finally, it may help to have type='button' on your <input....
UPDATE
The problem is you're trying to apply an inline tag
document.getElementById(\'<%=btnSave.ClientID%>\')
in your code be <%=btnSave.ClientID%> does not exist yet.
your code will break the moment you put your button inside another server control, as the clientId will become different.
Change the code to this:
document.getElementById('" + btnSave.ClientID + "')
and it will work, regardless of where you have the button.
Once your page is rendered in browser, right click on it, and say "view Source". check the HTML and try to find your hidden button, if you find it, use its id in your statement getElementById(\'<%=btnSave.ClientID%>\') . If you dont find your button, then probably you have set its visibility to false from your code-behind somewhere, remove that, follow the above process again and you should be ok.
I solved the problem replacing the part
document.getElementById(\'<%=btnSave.ClientID%>\').click();
by
$(\"#ctl00_body_btnSave\").click();
I also replace the input element by an asp:Button.
Give a look how my code is on my code behind now:
System.Web.UI.
ScriptManager.RegisterClientScriptBlock(this, GetType(), "__Mensagem", "if (confirm('" + CustomMessage+ "')){$(\"#" + btnSave.ClientID + "\").click();}", true);
And on my aspx:
<asp:Button id="btnSave" Width="0px" Text="" runat="server" onclick="btnSave_Click"/>
The use of Widht="0px" and Text="" to hidden the button isn't recommended, but I used because it won't cause me problems. It's recommended the use of a CssClass which make it hide.
So, if the user confirm the operation, the even btnSave_Click is called.
Thanks for all the answers.
I am using Ajax File Upload control in ASP.NET 4 using c#. The same page has an update panel too but the upload control is not inside the update panel. The upload control is outside of the update panel.
The update panel has a captcha image and submit button which is described here too. The submit button inside contains code for saving the file from upload control.
The problem is that when user has browsed the fife to be uploaded using upload control and then enters a wrong captcha value and submits, then a new captcha image is given asynchronously to the user for entry. Now the upload control still shows the path in the upload bar for the file, but on the programming side it does not detects the file.
The submit button code:
if (AsyncFileUpload.HasFile)
{
// upload logic and other stuff
}
else
{
// lblShow.Text = "There is no file to be uploaded";
}
The above code for example executes the else part to say "There is no file to be uploaded". The page still hasn't refreshed totally and the file upload control has the path of the file displayed. Kindly help me with this problem.
If your code:
if (AsyncFileUpload.HasFile)
{
// upload logic and other stuff
}
else
{
// lblShow.Text = "There is no file to be uploaded";
}
is in the Page_Load event, it will still execute in the context of a partial post-back, e.g. the UpdatePanel refresh. If a full form submit has not been performed from the browser (you mentioned your File Upload is outside of the UpdatePanel) then the page will not detect the file upload.
What I am confused about is why you have called it AsyncFileUpload when it is outside the UpdatePanel?
EDIT:
Based on your answer, I don't think your Captcha implementation is workable with async file upload as you have it now.
The UpdatePanel does an async POST to evaluate captcha result, but you will not POST the file contents yet because its not inside the UpdatePanel. Then your server-side code evaluates the captcha result and will either return html or a redirect in the async-response back to the browser... somewhere you need to eventually submit the form to get the file.
Unless you're prepared to write code to send some javascript back to your page in the async-response to trigger a full form submit, AND re-evaluate CAPTCHA again on the form submit, you're probably better off taking out the UpdatePanel, in my opinion.
If you are using Ajax update panel with file upload control then you have to add postback trigger into update panel triggers. Like:
<Triggers>
<asp:PostBackTrigger ControlID="btnContactSubmit"/>
</Triggers>
My web forms inherits a class called MyPageMain, which inhertis System.Web.UI.Page and is located on the App_Code folder.
In this MyPageMain class I created this method, to record and output Exceptions (error messages):
public string Error(Exception pException, string pFriendlyMessage)
{
using (BusError erro = new BusError())
{
int? errorId = //HERE Routine to log the error;
StringWriter stringWriter = new StringWriter();
using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "erroMain");
writer.RenderBeginTag(HtmlTextWriterTag.Div); //<div>
writer.RenderBeginTag(HtmlTextWriterTag.P); //<p>
writer.Write(pFriendlyMessage);
writer.RenderEndTag(); // </p>
writer.RenderBeginTag(HtmlTextWriterTag.Small);
writer.Write("Event tracker:");
writer.Write(errorId);
writer.RenderEndTag();
writer.RenderEndTag(); // </div>
Console.WriteLine(stringWriter.ToString());
}
}
}
Then, when there is some exception on the page, I call it, like this:
Protected void btnLoad_Click(object sender, EventArgs e)
{
LoadData();
}
private void LoadData()
{
try
{
//Loading some data here.
}
catch (Exception ex)
{
Error(ex, "Unexpected error trying to load data.");
}
}
This is bulding OK, but doesn't work... I think that one of the reasons may be the fact that the whole thing is inside an UpdatePanel. Any suggestions on how to make this work?
Is this Console.Writeline suitable for what i'm trying to do? Is this going to work on UpdatePanels?
Already Tried with Response.Write(...) and it does work. But not inside an UpdatePanel
When you use an UpdatePanel, you can only update content within the panel during an async postback triggered from that panel, so your error message will have to appear somewhere within the UpdatePanel. (That is, unless you set UpdateMode="Always" on one of your UpdatePanels, then its content is updated on every async and full postback. But that doesn't help you here unless you put your error message in its own UpdatePanel with UpdateMode="Always", which would require you to add said UpdatePanel to every page. I understand this is not what you want to do.)
The following example will work to add the error message at the top of the UpdatePanel.
You will need to add a Control errorParent parameter to your Error method, so it can add the error message as child control to that parent control.
In your catch block, just pass in whatever container control where you want the error message to appear. That control must be a container to accept child controls, so it has to be something that renders as a <div> or <span> tag, like an asp:Panel or asp:UpdatePanel.
In the example below, you could use errorParent.Controls.Add(errorControl) to show the error message at the bottom of the UpdatePanel, or use AddAt() with a different index. Just be sure that index will always work on every page.
Take a parent control and add a new Literal child control:
public string Error(Exception pException, string pFriendlyMessage, Control errorParent)
{
using (BusError erro = new BusError())
{
int? errorId = //HERE Routine to log the error;
Literal errorControl = new Literal();
errorControl.Text = String.Format("<div class=\"errorMain\"><p>{0}</p><small>Event Tracker: {1}</small></div>", pFriendlyMessage, errorId);
errorParent.Controls.AddAt(0, errorControl);
}
}
Pass in the parent control:
private void LoadData()
{
try
{
//Loading some data here.
}
catch (Exception ex)
{
Error(ex, "Unexpected error trying to load data.", MyUpdatePanel.ContentTemplateContainer);
}
}
Since your Error method returns string, you can return error message and display it.
Place Literal in your UpdatePanel (maybe in MasterPage, so you do not have to write it for all 40 or more pages). When exception is thrown, handle it with your Error method and set returned message to Literal.
Console.WriteLine is not usable in ASP.NET. Use Debug.WriteLine instead. It will write to Output window in VisualStudio.
Many of the answers are dancing around the issue. Console.WriteLine is a command used to output a line of text for a Console application (command-line). This is a Web app. So, you either use Response.Write to spit a string out to the Response stream or set the text of a Literal control that is already on the page and set it to be visible (default hidden).
Since I myself completely missed the UpdatePanel detail, here's an alternate solution to make up for it. My example uses a hidden div and some jQuery through the usage of the ScriptManager control to inject text into a div that is outside the UpdatePanel. Based on the conditions of the go_Click handler method of the button, it'll show or hide an error message using jQuery that gets injected into the Page server-side at the time of the UpdatePanel's update.
Note that it is critically important to use the ScriptManager's functions to register JavaScript rather than Page.ClientScript when using AJAX. Using the latter won't add the JS to the page.
Page markup
<div id="errorMessagePlaceHolder" class="error" style="display:none;">
</div>
<asp:UpdatePanel ID="myPanel" runat="server">
<ContentTemplate>
<asp:TextBox ID="myText" runat="server" />
<asp:Button ID="go" Text="GO" runat="server" OnClick="go_Click" />
</ContentTemplate>
</asp:UpdatePanel>
Page code-behind
public partial class _Default : Page {
protected void go_Click(object sender, EventArgs e) {
try {
// Do something that can throw an exception
// Hide the error if we reach the end as we may have triggered
// it in a prior update and no longer want it to display.
HideError();
} catch (Exception) {
ShowError("myText is empty!");
}
}
#region Move to a base page or a helper class if it helps reduce duplication
private void HideError() {
ScriptManager.RegisterStartupScript(Page, GetType(), "HideErrorMessageScript", HideErrorMessageScript(), true);
}
private void ShowError(string errorMessage) {
ScriptManager.RegisterStartupScript(Page, GetType(), "ErrorMessageScript", ErrorMessageScript(errorMessage), true);
}
private static string HideErrorMessageScript() {
return #"
$(document).ready(function() {
$('#errorMessagePlaceHolder').hide();
});
";
}
private static string ErrorMessageScript(string errorMessage) {
return
string.Format(
#"
$(document).ready(function() {{
$('#errorMessagePlaceHolder').html('{0}');
$('#errorMessagePlaceHolder').show();
}});
",
errorMessage);
}
#endregion
}
I feel like nobody has actually answered the entire question yet, so let me try.
Is this Console.Writeline suitable for what i'm trying to do?
Probably not, unless you just want debug information to appear in the output window while debugging. Some people like to keep outputting info to the Console, even in a release build and so if you want to do that with your errors, it's a valid choice, but you should also be showing a friendly error message to the user and/or logging the error to some kind of persistence (eg. log file). All of the answers above are suggesting ways for you to show some notification of the error to the user.
Is this going to work on UpdatePanels?
There is NO reason why it shouldn't if your triggers and the like are set up properly (and we know they are because you said that you're able to hit the Console.WriteLine breakpoint). I wonder if your Console output is working fine but you're looking for it in the wrong place? In the typical configuration for a web application, it should appear in the Output window of the Visual Studio instance you're using to Debug.
As to a suggestion for what I think you're asking, which is "how do I get my error message to appear in the update panel if there's an error loading the content for that update panel?"...
I would suggest an approach similar to nekno's proposal above. You can either dynamically add a control whose text you can set to be the error string during update panel request processing or you can even have an initially hidden/collapsed control on the page, which is only set to be visible in the case of an error. I'd prefer the latter approach because it's more maintainable. You can completely control the look and feel of the error label from the markup/display views of your ASPX page.
Are you calling .update() on your UpdatePanel after your LoadData() method runs? I think the UpdatePanel won't automatically fire unless the postback originates from inside it.
Ex:
Protected void btnLoad_Click(object sender, EventArgs e)
{
LoadData();
MyUpdatePanel.Update();
}
Update: I was able to get Response.Write() to work in an UpdatePanel by registering a trigger like this <Triggers><asp:PostBackTrigger ControlID="btn1" /></Triggers> for the button that will create the error.
Are you trying to log errors or display them? If you are trying to display them, you should:
On your masterpage, create a spot where your errors will be displayed (maybe below your navigation bar or near the bottom:
<asp:ContentPlaceHolder id='cphError'></asp:ContentPlaceHolder>
Everytime you get an error, you can call your error function as is, but instead of writing out the text with Response.Write() or Console.WriteLine(), you can add a label in there:
Label lError = new Label();
lError.CssClass = '..';
lError.Text = '..';
cphError.Controls.Add(lError);
This will help you out with displaying the error, but AJAX will still be a problem. At this point, you have two options:
Since update panels update other update panels, you can wrap an update panel around cphError, this way your AJAX calls will still update that area
OR: You can can use ClientScript.RegisterStartupScript to create the error label. (This method is only preferable if you do not have a static error message spot)
Place a Panel on the master, extend it with the modalpopupextender in the AjaxToolKit. When the error is raised, write the contents of string writer to a label in the panel E.g. Label lbl = (Label)Master.FindControl()
lbl.text = StringWriter.ToString();
// Now access the modal popup
AjaxControlToolkit.ModalPopupExtender MPE = (AjaxControlToolkit.ModalPopupExtender)Master.findControl("");
// and show it
MPE.Show();
The Modal will need a hidden button to use as it's target control, but it will not require a user's input. I accomplish this on the page with the following code:
<asp:Button ID="btnDummyOK" runat="server" Style="display: none;" />
<asp:ModalPopupExtender ID="mpePnlErrors" runat="server" TargetControlID="btnDummyButton" PopupControlID="pnlErrirs" BackgroundCssClass="modalBackground" CancelControlID="btnCancel" OkControlID="btnOK" />
Good luck
I think Console.WriteLine don''t work on asp.net application and i think inside an update panel you can simple fire the throw New Exception( the friendly error message) and it will appear in an alert box.
In summary:
I have an ASP.NET web page that causes an AJAX postback to the server. When this event handler runs (in the code behind) it will generate some JavaScript that I then want to run in the client. Not sure how to achieve this.
In Detail:
I have an ASP.NET web page with multiple items displayed on the page.
As a "nice to have", I want to display either a green circle or a red cross next to each item (these differ depending upon each item). Since it isn't vital for the User to see these icons and also because it takes several seconds to work out which icon should be shown for each item, I want to perform this after the page has loaded, so in an AJAX callback.
My thought therefore was this. When creating the page, I would create both icons next to each object and create them with the style of "hidden". I would also make a note of each one's client ID.
Then, when the callback occurs, I fetch the necessary data from the database and then create a JavaScript function that changes the display for each of the icons I want to show from "hidden" to "visible".
I thought I could achieve this using the ScriptManager object.
Here's a very trivial version of my server side code (C#)
void AjaxHandler(object sender, EventArgs e)
{
// call to database
string jscript = "alert('wibble');";
ScriptManager.RegisterStartupScript(this, this.GetType(), "uniqueKey", jscript);
}
Obviously, here I'm just trying to get an alert to fire after the postback has occurred...in real life I'd have my JavaScript function to change the display of all the icons I want to display.
When I run this, the serverside code runs and yet nothing happens in the server.
I have also tried:
ScriptManager.RegisterClientScriptBlock()
Page.RegisterStartupScript()
Page.RegisterClientScriptBlock()
Page.ClientScript.RegisterStartupScript()
Page.ClientScript.RegisterClientScriptBlock()
but none of them work....
FireFox shows the following JavaScript error:
Error: uncaught exception: [Exception... "Node cannot be inserted at the specified point in the hierarchy" code: "3" nsresult: "0x80530003 (NS_ERROR_DOM_HIERARCHY_REQUEST_ERR)" location: "http://localhost/MyWebSiteName/Telerik.Web.UI.WebResource.axd?_TSM_HiddenField_=ctl00_RadScriptManager1_TSM&compress=1&_TSM_CombinedScripts_=%3b%3bSystem.Web.Extensions%2c+Version%3d3.5.0.0%2c+Culture%3dneutral%2c+PublicKeyToken%3d31bf3856ad364e35%3aen-US%3a3de828f0-5e0d-4c7d-a36b-56a9773c0def%3aea597d4b%3ab25378d2%3bTelerik.Web.UI%2c+Version%3d2009.3.1314.20%2c+Culture%3dneutral%2c+PublicKeyToken%3d121fae78165ba3d4%3aen-US%3aec1048f9-7413-49ac-913a-b3b534cde186%3a16e4e7cd%3aed16cbdc%3a874f8ea2%3af7645509%3a24ee1bba%3a19620875%3a39040b5c%3af85f9819 Line: 1075"]
Does anyone know if what I am trying to do is even allowed?
If not - what's my alternative?
Thank you
Since your script doesn't have enclosing <script> tags, you need to use this form of RegisterStartupScript:
ScriptManager.RegisterStartupScript(this, this.GetType(), "uniqueKey", jscript, true);
You said your initial goal was:
The idea was that the page would load, data would be sent (AJAX) to the server. The server would then generate some JavaScript based upon this data and send that back to the page. That JavaScript would then run updating the page in a specific way.
Here's a way you can do that:
given:
<asp:ScriptManager runat="server" ID="scriptManager">
</asp:ScriptManager>
<script type="text/javascript">
function endRequestHandler(sender, args) {
var dataItems = args.get_dataItems();
for(var key in dataItems){
if(/^javascript:/.test(dataItems[key])){
eval(dataItems[key].substring("javascript:".length));
}
}
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler);
</script>
<asp:UpdatePanel runat="server" ID="pnl">
<ContentTemplate>
<asp:Button runat="server" ID="btnClick" Text="Click me!" OnClick="btnClick_Click" />
</ContentTemplate>
</asp:UpdatePanel>
You can create a click handler that does this:
protected void btnClick_Click(object sender, EventArgs e)
{
ScriptManager.GetCurrent(Page).RegisterDataItem(this, "javascript:alert('hello world!');");
}
What's happening is during the postback, the page request manager is sent a data item your code-behind. That data-item happens to be a javascript command. After the postback, the client side script manager's endRequest handler is checking for data items. Normally you'd want to see who those items are for, which is apparent by the key of the item (it's the client ID of the control that is the target of the data being sent). In your case, you could load this up with the javascript that you want to fire, tell yourself that it's a javascript because it's prepended, then dynamically evaluate the script.
So in this example, clicking the "Click Me!" button will generate a Hello World prompt whose script was actually created by the code-behind during the postback.
You'll have to be very cautious with this approach until you're comfy - I'd avoid references to "this"...
Happy coding.
B
Okay
The idea was that the page would load, data would be sent (AJAX) to the server. The server would then generate some JavaScript based upon this data and send that back to the page. That JavaScript would then run updating the page in a specific way.
Couldn't get that to work....
I got around this in the following way:
When the page loads, data is sent (AJAX) to the server. This processes the data and serialises the results updating a hidden text element, which goes back to the browser. Meanwhile, I have a JavaScript timer on the page that runs a JavaScript function that was generated when the page first loads. This function looks at the hidden text element. If that element has text (the result of the postback) then it shuts down the timer, deserialises the data and then works out how to update the page.