function to get image from database is not working - javascript

I'm new to Javascript. I want to add an icon to all my project's web pages. This icon changes accordingly to whoever logs in in my page. What i'm trying now is, in master page load (when i have all of its data in codebehind, including his chosen icon), i introduced a js function to change icon:
(function icon(image) {
var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.hre = image;
document.getElementsByTagName('head')[0].appendChild(link);
})();
(adapted from here: Changing website favicon dynamically)
im trying to call this function with Page.ClientScript.RegisterStartupScript() method:
(protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//...
UserModel usuario = (UserModel)Session["usuario"];
//...
Page.ClientScript.RegisterStartupScript(this.GetType(), "icone", $"icone({(Bitmap)new ImageConverter().ConvertFrom(usuario.imagem)});", true);
}
}
The method is simply not executing(its not returning error either, it just "jump it"), and i sincerely have no idea why.
OOOOR, there may be a better way to do it, but i just cant figure it.
For the record, i DONT have the icons/images on a folder. I MUST get them form the database.
(I will later add validation for when user has no image in database. Assume for now it will never be null).

A few things need to be edited:
First, think you got the parameters for RegisterStartupScript not set as required. The 3rd value should be the javascript code to run. You can add the entire script as a variable (as indicated here: https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.clientscriptmanager.registerstartupscript?view=netframework-4.7.2), or you can add your function in <script>...</script> tags to the HTML page, and then just call the function from within RegisterStartupScript (as the 3rd parameter value)
Secondly, there's a typo in your JavaScript function:
link.hre = image; should be link.href = image;
Thirdly, (this part might require some work) the image has to be a URL (string) to the actual image (Not the binary Bitmap)... you might first have to save the image to the web server as a .jpg or .png and use its URL to there, or you have to convert the image to Base64 and add the image via Data URLs https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
Finally, you modified the JavaScript from the original example (you mentioned) In this case, you want to send the image URL as a parameter to the function icon However, the icon function is encapsulated. So the function is basically in a Private scope. Remove the encapsulation around the function if needed to be called from another function on the page... hope this make sense.

Instead of using Javascript, you could simply link your shortcut-icon to a handler, that immediately returns the image. (The following code is not tested, it's there to describe the basic process!)
In your page:
<link rel="shortcut icon" type="image/x-icon" href="/userimage.ashx">
userimage.ashx:
<%# WebHandler Language="C#" Class="UserImageHandler" %>
userimage.ashx.cs:
using System;
using System.Web;
public class UserImageHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "image/png"; // or image/jpg, image/bmp, ...
var image = FetchImageFromDatabase(context.User.Identity.Name); // your logic for fetching the image from the database
// You could also return a default image here, if the user has not selected one.
context.Response.Write(image); // Write the binary data to the response stream.
}
public bool IsReusable {
get {
return false;
}
}
}

Related

Make page reload after file download

I am delivering a jasper report as a PDF for download. But when I do it I become unable to make the page to reload or redirect.
The page that causes the download to take place uses a form submission to start the file download. The answer provided by Govinda Sakhare was posted before I made this clarification. However his answer could be implemented with little work as the form only has one choice (big or small).
The function that handles the server response is below:
private void generateReportPDF(JasperReport jasperReport, List<? extends Object> data, Map<String, Object> parameters, HttpServletResponse resp) throws Exception {
byte[] bytes = null;
if( data == null ) {
bytes = JasperRunManager.runReportToPdf(jasperReport, parameters, reportDao.getConnection());
}
else {
bytes = JasperRunManager.runReportToPdf(jasperReport, parameters, new JRBeanCollectionDataSource(data));
}
resp.reset();
resp.resetBuffer();
resp.setContentType("application/pdf");
resp.addHeader("Content-Disposition", "attachment; filename=" + jasperReport.getName() + ".pdf");
resp.setContentLength(bytes.length);
ServletOutputStream ouputStream = resp.getOutputStream();
ouputStream.write(bytes, 0, bytes.length);
ouputStream.flush();
ouputStream.close();
return;
}
Because of this function, my controller is unable to redirect the page and I get the following error when I try to.
SEVERE: Servlet.service() for servlet [myapp-dispatcher] in context with path [/myapp] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed] with root cause
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
I want to reload the page. This is on a label printing screen and after the file download, I want the page to reload/redirect to itself so that labels which were printed are displayed in their new spot. Since the controller is unable to redirect, I have to modify the original process which is handling the response or implement JavaScript to occur after the file has been dealt with.
This question asks about catching downloads and responding to them, but does not involve spring so the answers would require more changes than I want to make.
Using one of the answers from the question I managed to make a workaround but its not satisfactory to me.
$(document).ready(function() {
$('#printBtn').click(function() {
if(confirm('<spring:message code="print.alert.confirm"/>') ? true : false)
{
window.addEventListener('focus', window_focus, false);
function window_focus(){
//remove buttons
var elem1 = document.getElementById('printBtn');
elem1.parentNode.removeChild(elem1);
//elem1.parentNode.replaceChild(newbutton);
var elem2 = document.getElementById('clearBtn');
elem2.parentNode.removeChild(elem2);
var elem3 = document.getElementById('restoreBtn');
elem3.parentNode.removeChild(elem3);
document.getElementById('button_spot').innerHTML = "The page will reload after you get the file.";
//watch for page to lose focus due to download dialog box
window.addEventListener('focusout', pageNoFocus);
function pageNoFocus(){
//watch for page to resume focus
window.removeEventListener('focusout', pageNoFocus);
window.addEventListener('focus', pageFocus);
function pageFocus(){
window.removeEventListener('focus', pageFocus);
location.reload();
}
}
}
return true;
}
return false;
});
$('#clearBtn').click(function() {
return confirm('<spring:message code="print.alert.clear"/>') ? true : false;
});
$('#restoreBtn').click(function() {
return confirm('<spring:message code="print.alert.restore"/>') ? true : false;
});
});
You can use the following snippet to download the file and redirect to some URL.
Download
<a href="downloadfileURL" target="_blank" id="downloadFile" />
<!-- change href with Spring mapping which will download the file -->
On click of Download link, it will click anchor which points to the actual
URL.
The file will be downloaded, followed by that it will redirect to the window.location.href
$("#download").click(function () {
$("#downloadFile")[0].click();
window.location.href = "/abc.html"; // change to the desired URL
});
If you download the file via form submission use below snippet.
$("#formId").click(function (e) {
e.preventDefault();
$("#downloadFile")[0].click();
window.location.href = "/abc.html"; // change to the desired URL
});

Execute javascript after loading generic handler asp.net

I have a gridview with a list of pdf files. When the user clicks a pdf, it displays the file inline on the page. I want to execute some javascript after the pdf has been loaded but I cannot get this to work. The issue is that the pdf loads after everything else, so the load event fires before the pdf begins to load.
My first approach was to use an iframe. The inner page would retrieve the file and write the data to the response. As mentioned previously, the load event occurred before loading the pdf and I need it to trigger after. The current code uses a generic handler ashx to load the pdf inline. How do I trigger an event to execute javascript, after the pdf data is loaded server side from the ashx generic handler?
Aspx page:
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "View")
{
int index = Convert.ToInt32(e.CommandArgument.ToString());
string Id = GridView1.DataKeys[index].Value.ToString();
HtmlGenericControl myObject = new HtmlGenericControl();
myObject.TagName = "object";
Panel1.Controls.Add(myObject);
myObject.Attributes.Add("data", "GetPdf.ashx?Id=" + Id);
}
}
Generic handler ashx:
public void ProcessRequest(HttpContext context)
{
System.Diagnostics.Debug.WriteLine("GetPdf.ashx started");
string Id = context.Request.QueryString["Id"];
byte[] data = GetPdf(Id);
context.Response.ClearContent();
context.Response.ContentType = "application/pdf";
context.Response.AppendHeader("Content-disposition", "inline");
context.Response.AddHeader("Content-Length", data.Length.ToString());
context.Response.BinaryWrite(data);
System.Diagnostics.Debug.WriteLine("GetPdf.ashx is done");
context.Response.End();
}
Have you tried setting an event handler for the object tag's onload event? I'm not sure if that will work across all browsers, but I also don't know which browsers you require it to work on.
Worst-case scenario you could use setTimeout to rapidly poll for the PDF's existence.
Here's a previous answer that may help you with both aspects.

How to make a popup display a message and then present a download after 5 seconds and then close the popup

In my project, I have a file that I want the user to download. When they click on the link, I want a popup window to display "Your download will shortly, if it doesn't start click here". After a few seconds, it will then close and the actual file download will then display.
I know to achieve the window closing you'll use:
window.setTimeout(function(){window.close()}, 5000);
But I'm not sure how you would call the download once the window has closed?
Cheers for any help!
In simple way, use window.open() to start download file.
Direct link
<script type="text/javascript">
setTimeout(function() {
window.open("myfile.doc");
},3000);
</script>
Okay so I don't know your platform so will give an ASP.NET version. If you are using something else then I have commented so you should be able to adapt to your platform.
EDIT: Now know user is using PHP so added code snippet for PHP (not robust but I'm no PHP dev)...
1) SAME FOR PHP/ASP Are you getting a file that will not be displayed by the browser automatically? i.e. .js will be shown as is but an exe will probably trigger a file download dialog (someone correct me if wrong please and I'll update)
If your files are always going to be i.e. .exe then you could probably just get away with:
$("body").append("<iframe src='http://www.targetsite.com/files/thefilename.exe'></iframe>");
but more likely you will be using a parameter to find the right file (and hide direct download
$("body").append("<iframe src='http://www.targetsite.com/downloader/?file=1234-1234-1234'></iframe>");
in some setTimeout function.
If the filetypes are unknown then I suggest pointing the above code at a script file (.ashx, php, etc) that writes the file byte stream to the http response.
FOR PHP:
<?php // Demo - send a (binary) file
$file = "ireland.jpg";//here you would use the query string parameter of the above
//ajax/iframe request eg file=1234-1234-1234 to find image in db
$fp = fopen($file,"r") ;
header("Content-Type: image/jpeg");//this would need to be modified to either show right content type or you could
//set it to Application/force-download
while (! feof($fp)) {
$buff = fread($fp,4096);
print $buff;
}
?>
WARNING Be careful with the above code. It occurred to me you might pass in filename directly which I'm pretty sure someone could use to get files in other places in your app without careful attention
FOR ASP:
I have included an example ashx (generic handler) solution:
aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Wardle.PdfGenerator;
using System.IO;
public partial class user_account_iframedownloader : System.Web.UI.Page
{
private IInformixRepository _rep;
//this page gets loaded into an iframe so we can do downloads while using ajax
protected void Page_Load(object sender, EventArgs e)
{
//write bytes out here i.e. see after for methods
}
}
Example byte output methods (you just need to do File.getBytes or something - my code is quite complicated so 'excercise for reader'
public static void PdfOutput(byte[] pdfData, string filename)
{
HttpContext.Current.Response.ContentType = "Application/pdf";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename);
HttpContext.Current.Response.BinaryWrite(pdfData);
}
public static void PdfZipOutput(byte[] zipData, string filename)
{
HttpContext.Current.Response.ContentType = "Application/zip";
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename);
HttpContext.Current.Response.BinaryWrite(zipData);
}

Hiding loading image on asp.net postback for file download

I have a button on my asp.net page that does a postback, creates an Excel file, clears the response stream and writes the file. The user can then open or save the file user the brower's standard dialog.
This works great, I based the code on this:
http://www.adventuresindevelopment.com/2009/05/27/how-to-export-data-to-excel-in-aspnet/
As the file to be created takes quite a long time I have created a loading panel, just a hidden DIV, and set this to visible when the button is clicked.
But my problem is how to hide this DIV when the export has finished? I just cannot find a way of doing it. I need something like an event that fires when the file has been completely transfered to the browser.
Is this possible? Any help most appreciated.
Thanks,
AJ
What I'd do, long story short :
When the user clicks the "Download" button, use AJAX to call a
processing page asynchronously. This page will generate your Excel
document and store it in a temporary location
When the AJAX request is done, hide the "Loading" panel, and
redirect the user to a download page. Ideally, you should redirect
to a generic (.ashx) handler that opens the file, sets some headers,
streams the temporary file to the user, and deletes the file
afterwards.
Now in more details :
For step one, you should have some temporary folder where you have read and write access. Using the system temp folder is fine, so you could use Path.GetTempFileName. Here is an example of what you could write in an ashx handler :
public class Handler1 : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
string fName = Path.GetTempFileName();
context.Response.ContentType = "text/plain";
try
{
// Generate the Excel document
GenerateExcelInFile(fName);
// Store the file name in session for later use
context.Session["ExcelGeneratorFileName"] = fName;
// Send confirmation to the client
context.Response.Write("ok");
}
catch (Exception e)
{
context.Response.Write("error");
// TODO : Do some logging
}
}
// SNIP : IsReusable
}
After that, use your favorite JS framework to request that handler, and test the returned string. If it is "ok", you call the part two handler :
public class Handler2 : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/excel";
// Make sure the browser will show a "save as" dialog to the user
context.Response.AddHeader("content-disposition", "attachment; filename=Export.pdf");
string fName = context.Session["ExcelGeneratorFileName"] as String;
if (fName != null && File.Exists(fName))
{
// Stream the excel file to the response
context.Response.WriteFile(fName);
// Remove the file
File.Delete(fName);
}
}
// SNIP : IsReusable
}
You can call this page in javascript simply using a window.location = url. The content-disposition header will tell the browser that this URL should not be displayed, only downloaded, so your user should stay on the download page.

Asp.net MVC Multiple (of the same) Partial Views on a page with <script> tags inside Partial View

Looking for an elegant way of having scripts added once on a page and that's it.
I have a partial view that requires 2 CSS files and 2 JS files. In most places, there is only need for 1 of the partial views. On a single page though, I need 3 of these same partial views, and each partial view has the 4 files, so I have 6 JS links and 6 CSS links. Quite ugly.
I original idea was to use jQuery to see if the tags (by id) are existant on the page yet or not. If they aren't, then add them in. Otherwise, do nothing. This was going to be an inline script like....
<script type="text/javascript" language="javascript">
function(){
var jQueryUICSS = $("#jQueryUICSS");
if(!jQueryUICSS){
document.write('link id="jQueryUICSS" href="/Content/smoothness/jquery-ui-1.8.5.custom.css" rel="stylesheet" type="text/css" />')
}
...And so on for the other 3 tags.
};
But, I'm not sure that will work (or will the lead dev accept it):P
Any other ideas?
David,
I use a couple of static htmlhelpers in my code for exactly this scenario. it works on the principle that the context.items collection gets populated per request and therefore if an item exists in the context.items collection then it doesn't get added twice. anyway, enough of the scottish words of wisdOOOm, 'yill jist be waantin the coade'...
for our Scripts:
public static MvcHtmlString Script(this HtmlHelper html, string path)
{
var filePath = VirtualPathUtility.ToAbsolute(path);
HttpContextBase context = html.ViewContext.HttpContext;
// don't add the file if it's already there
if (context.Items.Contains(filePath))
return MvcHtmlString.Create("");
// add the beast...
context.Items.Add(filePath, filePath);
return MvcHtmlString.Create(
string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", filePath));
}
for our cuddly css:
// standard method - renders as defined in as(cp)x file
public static MvcHtmlString Css(this HtmlHelper html, string path)
{
return html.Css(path, false);
}
// override - to allow javascript to put css in head
public static MvcHtmlString Css(this HtmlHelper html,
string path,
bool renderAsAjax)
{
var filePath = VirtualPathUtility.ToAbsolute(path);
HttpContextBase context = html.ViewContext.HttpContext;
// don't add the file if it's already there
if (context.Items.Contains(filePath))
return null;
// otherwise, add it to the context and put on page
// this of course only works for items going in via the current
// request and by this method
context.Items.Add(filePath, filePath);
// js and css function strings
const string jsHead = "<script type='text/javascript'>";
const string jsFoot = "</script>";
const string jsFunctionStt = "$(function(){";
const string jsFunctionEnd = "});";
string linkText = string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\"></link>", filePath);
string jsBody = string.Format("$('head').prepend('{0}');", linkText);
var sb = new StringBuilder();
if (renderAsAjax)
{
// join it all up now
sb.Append(jsHead);
sb.AppendFormat("\r\n\t");
sb.Append(jsFunctionStt);
sb.AppendFormat("\r\n\t\t");
sb.Append(jsBody);
sb.AppendFormat("\r\n\t");
sb.Append(jsFunctionEnd);
sb.AppendFormat("\r\n");
sb.Append(jsFoot);
}
else
{
sb.Append(linkText);
}
return MvcHtmlString.Create( sb.ToString());
}
usage in both cases:
<%=Html.Css("~/Content/Site.Css")%>
<%=Html.Script("~/Scripts/default.js")%>
have fun...
[edit] - pay particular attn to the comment line:
// this of course only works for items going in via the current
// request and by this method
Put them in your master. CSS and Javascript files are cached. Load once and don't worry about it.

Categories