Why I cannot open a CSV file using JQuery and FileContentResult - javascript

I'm trying to make an ajax call (I specifically don't want to do it using ActionLink).
I'm having a controller that is like this:
public IActionResult ExportUsers(List<string> listOfEmails)
{
/*some data processing*/
return File(result, "text/csv", "ExportCandidates.csv");
}
On the other side with ajax I do this simple call:
$.ajax({
url: '/Admin/Testcenter/GenerateInvitationPreview',
type: 'post',
data: {
//some input data to send to the controller ​
​},
​success: function (response) {
​)
​}
​});
I know there exists something for pdf files where you return a base64 file and with the response in the ajax call you just write something like pdfWindow.document.write(...) and this will open a new window with a pdf file.
Is there a way to extract the response for my CSV file and generate it so the user downloads it ?

USE NPOI Library for Excel Sheet Generation
//Generate Excel Sheet
try
{
Guid gid = Guid.NewGuid();
string ext = ".xls";
string[] Headers = { "Appointments Id", "Date of Appointment", "Doctor Name", "Patient Name", "Visit Type", "Status" };
string fileName = "AppointmentsExcelSheet_" + gid.ToString() + ext;
var serverpath = _env.ContentRootPath;
string rootpath = serverpath + "/wwwroot/ExcelSheets/" + fileName;
FileInfo file = new FileInfo(Path.Combine(rootpath, fileName));
var memorystream = new MemoryStream();
using (var fs = new FileStream(rootpath, FileMode.Create, FileAccess.Write))
{
IWorkbook workbook = new XSSFWorkbook();
ISheet excelSheet = workbook.CreateSheet("Appointments List");
IRow row = excelSheet.CreateRow(0);
var font = workbook.CreateFont();
font.FontHeightInPoints = 11;
font.FontName = "Calibri";
font.Boldweight = (short)FontBoldWeight.Bold;
for (var i = 0; i < Headers.Length; i++)
{
var cell = row.CreateCell(i);
cell.SetCellValue(Headers[i]);
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(font);
}
var result = _Appointment.GetAppoinmentsPDf();
int index = 1;
foreach (var app in result.Items)
{
//var PatientDob = Convert.ToDouble(app.PatientDOB);
row = excelSheet.CreateRow(index);
row.CreateCell(0).SetCellValue(app.AppointmentId);
row.CreateCell(1).SetCellValue(app.DateofAppointment+" "+app.TimeofAppointment);
row.CreateCell(2).SetCellValue(app.DoctorFullName);
row.CreateCell(3).SetCellValue(app.SelectedPatientName);
row.CreateCell(4).SetCellValue(app.PurposeofVisit);
if (app.IsActive == false)
{
row.CreateCell(5).SetCellValue("Inactive");
}
else
{
row.CreateCell(5).SetCellValue("Active");
}
index++;
}
workbook.Write(fs);
}
using (var filestream = new FileStream(rootpath, FileMode.Open))
{
filestream.CopyToAsync(memorystream);
}
memorystream.Position = 0;
//send filepath to JQuery function
response.Msg = "/ExcelSheets/" + fileName;
}
catch (Exception Ex)
{
//exception code
}
return Ok(reponse.Msg)
//JavaScript
function AppointmentsExcelSheet() {
//var token = Token;
//var link = path;
debugger
$.ajax({
//'Content-Type': 'application/pdf.',
type: "GET",
url: "/api/Appointments/GetAppointmentsExcelSheet",
beforeSend: function () {
$.blockUI({
message: ('<img src="/images/FadingLines.gif"/>'),
css: {
backgroundColor: 'none',
border: '0',
'z-index': 'auto'
}
});
},
complete: function () {
$.unblockUI();
},
success: function (data) {
debugger
//downloads your Excel sheet
window.location.href = data.msg;
}
});
}

The best way to do what you want to do is to not use AJAX, but use either a link click that opens a new window (since you are passing in parameters) If you could use a
<form target="_blank">
to open a form response. Inside the form can be a field or fields that contains the list of emails (it can be one field, or multiple input fields with the same name). Your action handler can accept that list, parse it, and return a File response, and the natural result of opening the new window from the form post operation is a file that opens up.

Related

How do I send a django model to javascipt?

How do I pass a django model to javascript?
Specifically, I want to pass a django Movie model to javascript.
In javascript, I would like to display the id something in the movie model at the time of score with an if statement.
def index(request):
if Movie.objects.order_by('-stars').exists():
movie = list(Movie.objects.order_by('-stars'))
if TV.objects.order_by('-stars').exists():
tv = TV.objects.order_by('-stars')
print(tv)
context = {
'movie':movie,
}
return render(request, 'Movie/index.html',context)
fetchTrendingResults("all", "week")
var mediaType = document.getElementById("media_type")
mediaType.addEventListener("change", function(event) {
fetchTrendingResults(mediaType.options[mediaType.selectedIndex].value, "day")
})
function fetchTrendingResults(media_type, time_window) {
var trendingDiv = document.getElementById("trendings")
trendingDiv.innerHTML = ""
if (media_type == "score"){
var js_list = {{movie}};
}
else{
fetch(`/api/trendings?media_type=${media_type}&time_window=${time_window}`, {
method: "GET",
headers: {
"Content-Type": "application/json"
}}
// todo:movieとTVのIDをもらってこれをURLにFethして映画とTVの情報をそれぞれでスターが高い順に表示する。
)
.then(res => res.json())
.then(data => {
for (let i=0; i<data.results.length; i++) {
var mainDiv = document.createElement("div");
mainDiv.setAttribute("class", "card");
mainDiv.setAttribute("style", "width: 18rem;");
var img = document.createElement("img");
img.setAttribute("src", "https://image.tmdb.org/t/p/w200" + data.results[i].poster_path);
img.setAttribute("class", "card-img-top");
img.setAttribute("alt", "...");
var body = document.createElement("div");
body.setAttribute("class", "card-body");
var title = document.createElement("h5");
title.setAttribute("class", "card-title");
if (data.results[i].name) {
title.innerHTML = data.results[i].name;
} else {
title.innerHTML = data.results[i].title;
}
//var text = document.createElement("p");
//text.setAttribute("class", "card-text");
//text.innerHTML = data.results[i].overview;
var link = document.createElement("a");
link.setAttribute("href", "/" + data.results[i].media_type + "/" + data.results[i].id + "/");
link.setAttribute("class", "btn btn-primary");
link.innerHTML = "View Details";
body.appendChild(title);
//body.appendChild(text);
body.appendChild(link);
mainDiv.appendChild(img);
mainDiv.appendChild(body);
document.getElementById("trendings").appendChild(mainDiv);
}
})
}
}
How do I pass a django model to javascript?
Specifically, I want to pass a django Movie model to javascript.
In javascript, I would like to display the id something in the movie model at the time of score with an if statement.
You can send model data by just returning JsonResponse from the view (and for example creating JSON dict by forlooping QuerySet, or using model_to_dict Django built-in method) or by preserving your logic and sending html you need to override - even better - you can do both ways at the same time.
So, basically you write view like this:
from django.forms import model_to_dict
from django.http import Http404
def custom_ajax_view(request):
if request.method != 'POST':
raise Http404
movies = Movie.objects.order_by('-stars')
movie_dict = {}
if movies.exists():
movie_dict = {obj.id: model_to_dict(obj) for obj in movies}
tv = TV.objects.order_by('-stars')
tv_dict = {}
if tv.exists():
tv_dict = {obj.id: model_to_dict(obj) for obj in tv}
context = {
'movie': movie,
}
html = render_to_string(
'Movie/index.html', context=context)
return JsonResponse({
'movies': movie_dict,
'tvs': tv_dict,
'html': html,
})
And then you retrieve data via Ajax method (I prefer using jQuery for that) by writing:
$.ajax({
url: CUSTOM_AJAX_URL,
type: 'post',
dataType: 'json',
success: function (data) {
// Here you retrieve your data and you can do something with it.
console.log(data)
}
});
You also can resolve your CUSTOM_AJAX_URL using template logic (post it at the end of template)
<script>
const CUSTOM_AJAX_URL = "{% url 'custom_ajax_view' %}";
</script>
<script src="{% static 'your_script_name.js' %}"></script>
Then your script should see the CUSTOM_AJAX_URL (if you use script not directly by using inline method, but including script via script tag and placing it with static method in the code). If you place it directly, you can pass URL directly to the AJAX method.

Excel file not being downloaded when function is called via ajax method

Situation
I am working on an application where I can have a grid with X items, and each item has a print button. Clicking this print button allows me to call an ajax function which passes the ID of the grid item to a controller. I retrieve the relevant data based on that ID and then download it in an excel file. (The retrieving of the specific item is not yet done)
What I have so far
So far, I have the basic code that downloads an excel file, along with my grid .
Problem
The problem I am facing is, if I click the "Print" button...nothing happens, even with a breakpoint in my exporttoexcel functions shows me that the function is entered and I can step thru it and despite no errors, nothing occurs. However, I added random button that called the same function and when i clicked that button, the excel file was downloaded. As a result, I believe the issue has something to do with aJax.
Code
<input type="button" value="Test" onclick="location.href='#Url.Action("ExportToExcel", "Profile")'" />
This is the code which downloads the file. It was a simple button I added.
function ExportToExcel(id) {
$.ajax({
type: "POST",
url: "#Url.Action("ExportToExcel", "Profile")",
data: { "id": id },
dataType: "json"
});
}
This is the function that I want to work, but it does not work and I cannot see what i've got wrong.
Export to Excel Code
public void ExportToExcelx()
{
var products = new System.Data.DataTable("teste");
products.Columns.Add("col1", typeof(int));
products.Columns.Add("col2", typeof(string));
products.Rows.Add(1, "product 1");
products.Rows.Add(2, "product 2");
products.Rows.Add(3, "product 3");
products.Rows.Add(4, "product 4");
products.Rows.Add(5, "product 5");
products.Rows.Add(6, "product 6");
products.Rows.Add(7, "product 7");
var grid = new GridView();
grid.DataSource = products;
grid.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=MyExcelFile.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
grid.RenderControl(htw);
//Response.Output.Write(sw.ToString());
//Response.Flush();
//Response.End();
// =============
//Open a memory stream that you can use to write back to the response
byte[] byteArray = Encoding.ASCII.GetBytes(sw.ToString());
MemoryStream s = new MemoryStream(byteArray);
StreamReader sr = new StreamReader(s, Encoding.ASCII);
//Write the stream back to the response
Response.Write(sr.ReadToEnd());
Response.End();
// return View("MyView");
}
Theory
I believe the error is somehow tied in to aJax, I am also creating the button in the controller like this.
"<button type='button' class='btn btn-warning' onclick='ExportToExcel(" + c.id + ");'>Print</button>",
Since location.href='#Url.Action works, I was wondering if attempting to redo my dynamic button would solve my issue.
Appreciate any insight that could be offered.
Yes you are right you have problem with ajax, Basically you have to call the controller action again from you ajax call when your first ajax call return success. Add below code snippet to your ajax call.
success: function () {
window.location = '#Url.Action("ExportExcel", "Profile")?id='+id;
}
And you have to change your controller method to return the file, as below
public FileResult ExportToExcelx()
{
...............
byte[] byteArray = Encoding.ASCII.GetBytes(sw.ToString());
return File(byteArray, System.Net.Mime.MediaTypeNames.Application.Octet, "FileName.xlsx");
}
File cannot be downloaded until full post back is triggered. Here is how you can do it:
Your ExportToExcelx function will hold file in TempData object as following:
TempData["fileHandle"] = s.ToArray();
Rather than returning view return temp data identifier "fileHandle" and file name as shown below:
return Json(new { fileHandle = "fileHandle", FileName = "file.xls" }, JsonRequestBehavior.AllowGet);
So your modified function will be like this:
public JsonResult ExportToExcelx()
{
var products = new System.Data.DataTable("teste");
products.Columns.Add("col1", typeof(int));
products.Columns.Add("col2", typeof(string));
products.Rows.Add(1, "product 1");
products.Rows.Add(2, "product 2");
products.Rows.Add(3, "product 3");
products.Rows.Add(4, "product 4");
products.Rows.Add(5, "product 5");
products.Rows.Add(6, "product 6");
products.Rows.Add(7, "product 7");
var grid = new GridView();
grid.DataSource = products;
grid.DataBind();
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=MyExcelFile.xls");
Response.ContentType = "application/ms-excel";
Response.Charset = "";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
grid.RenderControl(htw);
//Response.Output.Write(sw.ToString());
//Response.Flush();
//Response.End();
// =============
//Open a memory stream that you can use to write back to the response
byte[] byteArray = Encoding.ASCII.GetBytes(sw.ToString());
MemoryStream s = new MemoryStream(byteArray);
TempData["fileHandle"] = s.ToArray();
//StreamReader sr = new StreamReader(s, Encoding.ASCII);
//Write the stream back to the response
Response.Write(sr.ReadToEnd());
Response.End();
return Json(new { fileHandle = "fileHandle", FileName = "file.xls" }, JsonRequestBehavior.AllowGet);
// return View("MyView");
}
Now you need another function in your controller to download file like following:
[HttpGet]
public virtual ActionResult Download(string fileHandle, string fileName)
{
if (TempData[fileHandle] != null)
{
byte[] data = TempData[fileHandle] as byte[];
return File(data, "application/vnd.ms-excel", fileName);
}
else
{
return new EmptyResult();
}
}
On successful call to ExportToExcelx function your ajax call will call download function as following:
$.ajax({
type: 'GET',
cache: false,
url: '/url',
success: function (data) {
window.location = '/url/Download?fileHandle=' + data.fileHandle
+ '&filename=' + data.FileName; //call download function
},
error: function (e) {
//handle error
}
Download function then will return the file.
Hope this helps.
I've had a similar problem here, and it did solve with a dynamic button as well. I just had to include a responseType:'blob' in my request.
And get the response to the button:
var link = document.createElement('a');
link.href = window.URL.createObjectURL(response.data);
link.download='filename.xlsx';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
And my Controller writes to a output stream and produces a "application/xls"
response.setContentType("application/xls");
response.setHeader("Content-disposition", "attachment;");
response.getOutputStream().write(content);
First of all, I would not use GridView to generate excel. Despite being "easy", it won't generate an actual excel file, but rather a html file with xls extension:
<div>
<table cellspacing="0" rules="all" border="1" style="border-collapse:collapse;">
<tr>
<th scope="col">col1</th><th scope="col">col2</th>
</tr><tr>
<td>1</td><td>product 1</td>
</tr><tr>
<td>2</td><td>product 2</td>
</tr><tr>
<td>3</td><td>product 3</td>
</tr><tr>
<td>4</td><td>product 4</td>
</tr><tr>
<td>5</td><td>product 5</td>
</tr><tr>
<td>6</td><td>product 6</td>
</tr><tr>
<td>7</td><td>product 7</td>
</tr>
</table>
</div>
This results in a file that when opened will cause this:
that is pretty annoying (and unprofessional).
If you're not bounded to old excel version - xls - but can use most recent file format xlsx, I'd rather use DocumentFormat.OpenXml nuget package or other packages/libraries for excel generation.
Honestly, DocumentFormat.OpenXml is powerful but a little boring to use, when you have many columns and you just have a flat list of objects to report.
If you are using .NET Framework (not Dotnet Core), you can try
CsvHelper.Excel nuget package. Usage is pretty straight forward. Your ExportToExcel method will become something like:
public ActionResult ExportToExcel(string id)
{
// TODO: Replace with correct products retrieving logic using id input
var products = new [] {
{ col1 = 1, col2 = "product 1" },
{ col1 = 2, col2 = "product 2" },
{ col1 = 3, col2 = "product 3" },
{ col1 = 4, col2 = "product 4" },
{ col1 = 5, col2 = "product 5" },
{ col1 = 6, col2 = "product 6" },
{ col1 = 7, col2 = "product 7" },
{ col1 = 1, col2 = "product 1" },
{ col1 = 1, col2 = "product 1" },
};
var ms = new MemoryStream();
var workbook = new XLWorkbook();
using (var writer = new CsvWriter(new ExcelSerializer(workbook)))
{
writer.WriteRecords(products);
}
workbook.SaveAs(ms);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
return File(ms, MimeMapping.GetMimeMapping("file.xlsx"), $"MyExcelFile.xlsx");
}
Another package pretty powerful is EPPlus, that allows you to load a DataTable (see this: https://stackoverflow.com/a/53957999/582792).
Coming to the AJAX part, well... I do not think you need it at all: once you set the location to the new ExportToExcel action, it should just download the file.
Assuming you are using Bootstrap 3, for each of your item in the collection you can just:
<a href="#Url.Action("ExportToExcel", "Profile", new {id=item.Id})" class="btn btn-info">
<i class="glyphicon glyphicon-download-alt" />
</a>
There are multiple solutions to this problem:
Solution 1
Let's imagine you have a Product model like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
In you controller:
[HttpPost]
public JsonResult ReportExcel(string id)
{
// Your Logic Here: <DB operation> on input id
// or whatsoever ...
List<Product> list = new List<Product>() {
new Product{ Id = 1, Name = "A"},
new Product{ Id = 2, Name = "B"},
new Product{ Id = 3, Name = "C"},
};
return Json(new { records = list }, JsonRequestBehavior.AllowGet);
}
Then inside your View (.cshtml), use the JSONToCSVConvertor as a utility function and just Don't touch it as it converts the array of json objects received into Excel and prompts for download.
#{
ViewBag.Title = "View export to Excel";
}
<h2>....</h2>
#* All Your View Content goes here *#
#* This is a sample form *#
<form>
<div class="form-group">
<label>Product ID</label>
<div class="col-md-10">
<input id="productID" name="productID" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input id="submit" type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</form>
#section scripts{
<script>
$('#submit').click(function (e) {
e.preventDefault();
var ID = $('#productID').val();
$.ajax({
cache: false,
type: 'POST',
url: '/YourControllerName/ReportExcel',
data: {id: ID},
success: function (data) {
console.log(data);
JSONToCSVConvertor(data.records, "Sample Report", true);
}
})
});
function JSONToCSVConvertor(JSONData, ReportTitle, ShowLabel) {
//If JSONData is not an object then JSON.parse will parse the JSON string in an Object
var arrData = typeof JSONData != 'object' ? JSON.parse(JSONData) : JSONData;
var CSV = 'sep=,' + '\r\n\n';
//This condition will generate the Label/Header
if (ShowLabel) {
var row = "";
//This loop will extract the label from 1st index of on array
for (var index in arrData[0]) {
//Now convert each value to string and comma-seprated
row += index + ',';
}
row = row.slice(0, -1);
//append Label row with line break
CSV += row + '\r\n';
}
//1st loop is to extract each row
for (var i = 0; i < arrData.length; i++) {
var row = "";
//2nd loop will extract each column and convert it in string comma-seprated
for (var index in arrData[i]) {
row += '"' + arrData[i][index] + '",';
}
row.slice(0, row.length - 1);
//add a line break after each row
CSV += row + '\r\n';
}
if (CSV == '') {
alert("Invalid data");
return;
}
//Generate a file name
var fileName = "MyReport_";
//this will remove the blank-spaces from the title and replace it with an underscore
fileName += ReportTitle.replace(/ /g, "_");
//Initialize file format you want csv or xls
var uri = 'data:text/csv;charset=utf-8,' + escape(CSV);
// Now the little tricky part.
// you can use either>> window.open(uri);
// but this will not work in some browsers
// or you will not get the correct file extension
//this trick will generate a temp <a /> tag
var link = document.createElement("a");
link.href = uri;
//set the visibility hidden so it will not effect on your web-layout
link.style = "visibility:hidden";
link.download = fileName + ".csv";
//this part will append the anchor tag and remove it after automatic click
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
}
I ran and built the above code successfully, so feel free to grab and tweak it as you wish.
Also here is the jsFiddle link, thanks to its developer: https://jsfiddle.net/1ecj1rtz/
Solution 2
Call this action method through $.ajax and get the file downloaded:
public FileResult Export(int id)
{
//......... create the physical file ....//
byte[] fileBytes = File.ReadAllBytes(filePath);
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Along with Solution 2, this thread gives you a good idea: https://stackoverflow.com/a/16670517/4687359
Hope this helped. :)
ANSWER:
You need to include success in your ajax call.
function ExportToExcel(id) {
$.ajax({
type: "POST",
url: "#Url.Action("ExportToExcel", "Profile")",
data: { "id": id },
dataType: "json"
success: function () {
window.location = '#Url.Action("ExportExcel", "Profile")?id='+id;
}
});
}
For Duplicate headers received from the server
Duplicate headers received from server
The data will be transformed to a query string on an AJAX GET request; just do that yourself using the jQuery param function:
$('#excel').on('click',function(){
var query = {
location: $('#location').val(),
area: $('#area').val(),
booth: $('#booth').val()
}
var url = "{{URL::to('downloadExcel_location_details')}}?" + $.param(query)
window.location = url;
});
Here is how I got this working for PDF. Excel download should be similar
$.ajax({
url: '<URL_TO_FILE>',
success: function(data) {
var blob=new Blob([data]);
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
link.click();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
OR using download.js
$.ajax({
url: '<URL_TO_FILE>',
success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});

A complete example using excel-builder.js

I need to use excel-builder.js to export excel file with stylings(header background color blue, freezing top row, column filtering), but the website with all documentation is not accessible anymore, I even contacted the author but without response.
If anyone can help create a small example with all these formattings, I will appreciate it a lot!
I know the following code will build an excel file:
var jsonData = [
['sample', 'data', 'for'],
['generating', 'excel', 'in'],
['java', 'script', ' ']
];
require(['excel-builder.js/excel-builder', 'download'], function (EB, downloader) {
var JSworkBook = EB.createWorkbook();
var JSworkSheet = JSworkBook.createWorksheet({name: 'Sheet'});
JSworkSheet.setData(jsonData);
JSworkBook.addWorksheet(JSworkSheet);
var data = EB.createFile(JSworkBook);
downloader('Artist WB.xlsx', data);
});
You can access a cached version of the documentation via the web archive . Keep in mind though that you'll need to navigate between the pages of the documentation using the cached-url-syntax, instead of just clicking on the links.
I'm only adding this because the project is now declared dead (https://github.com/stephenliberty/excel-builder.js), and the website documentation is offline(http://excelbuilderjs.com/). So best we can do is find someone willing to take control of it with a fork, or share our code.
The server-side script..
<cfscript>
path="/app/uploads/temp/";
full_path=ExpandPath(path) & FORM.filename;
if (!DirectoryExists(ExpandPath(path))) DirectoryCreate(ExpandPath(path));
FileWrite(full_path,(BinaryDecode(FORM.contents,"Base64")));
json=StructNew();
json.file=path & FORM.filename;
WriteJSON(json);
</cfscript>
you could use PHP..
<?php
header("Content-type: ".$_POST['contentType']);
header("Content-disposition: attachment; filename=\"{$_POST['fileName']}\"");
echo base64_decode($_POST['contents']);
?>
or asp..
[Authorize]
[System.Web.Mvc.SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class SystemController : ApiController {
private ILog log = LogManager.GetLogger(typeof(SystemController));
public class ExcelResponse {
public String FILE = "";
}
public class ExcelRequest {
public String filename;
public String contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
public String contents;
}
[HttpPost]
public ExcelResponse Excel(ExcelRequest request) {
ExcelResponse response = new ExcelResponse();
String the_path = "/_assets/temp/";
String path=System.Web.HttpContext.Current.Server.MapPath("~"+the_path);
log.Info("Generating excel file from data: "+path+request.filename);
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
byte[] file_data=(Convert.FromBase64String(request.contents));
File.WriteAllBytes(path + request.filename, file_data);
response.FILE = the_path+request.filename;
return response;
}
}
And the include script...
require.config({
baseUrl: '/app/assets/',
paths: {
underscore: '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min',
JSZip: './excel-builder/jszip',
EB: './excel-builder.dist.min',
spin: '//cdnjs.cloudflare.com/ajax/libs/spin.js/1.2.7/spin.min',
image: '/3rdparty/requirejs/image',
text: '/3rdparty/requirejs/text',
util: '/excel-builder/Excel/util'
},
shim: {
'underscore': {
exports: '_'
},
'JSZip': {
exports: 'JSZip'
},
'swfobject': {
exports: 'swfObject'
}
}
});
goes into ./excel-builder/download.js
define(function () {
return function (fileName, content) {
var form = $("<form id='download'>").attr({
target: '_BLANK',
action: '/app/assets/excel-builder/excel.cfm',
method: 'post'
}).css({display: 'none'});
form.append($("<input>").attr({name: 'fileName', value: fileName}));
form.append($("<input>").attr({name: 'contentType', value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}));
var ta=$("<textarea>").attr({name: 'contents', value: content});
ta.val(content);
form.append(ta);
form.appendTo($("body"));
form.submit();
window.setTimeout(function () {form.remove();}, 30000);
}
});
The bootstrap (for tablesorter)...
$(document).ready(function() {
$("table.sort").on("filterEnd",ts_onTableFiltered);
});
The meat of it...
function ts_onTableFiltered(event,tblsorter) {
$(tblsorter.table).data('ts_sorter',tblsorter);/*legacy :: */ window.ts_currentSorter=tblsorter;
console.log(event.type);
$(tblsorter.table).data('ts_isFiltered',false); /*legacy. remove me after verification :: */ window.ts_isFiltered=false;
for (var i=0;i<tblsorter.lastSearch.length;i++) {
var currentItemFilter=((tblsorter.lastSearch[i]!="")?true:false);
if (currentItemFilter) {
$(tblsorter.table).data('ts_isFiltered',true);/* legacy:: */ts_isFiltered=true;
break;
}
}
var rows=[];
if ($.isEmptyObject( tblsorter.cache )) {
rows=tblsorter.$tbodies.eq( 0 ).children( 'tr' );
} else {
for(i=0;i<tblsorter.cache[0].normalized.length;i++) {
var row=tblsorter.cache[0].normalized[i][tblsorter.columns].$row[0];
if (!ts_isFiltered) {rows.push($(row));continue;}
var result=tblsorter.pager.regexRows.test(row.className);
if (!result) { // skip 'filtered' className
rows.push($(row));
}
}
}
$(tblsorter.table).data('ts_currentRowsInTable',rows); /*legacy :: */window.ts_currentRowsInTable=rows;
console.log(rows.length);
}
function downloadExcelFromTable(tableObj,filename,props) {
var button=$('a:contains("Excel")');
if (button.length > 1) {
var temp=0;
button.each(function() {
if ($(this).attr('onclick').indexOf(tableObj.attr('id'))>=0) {
temp=$(this);
}
});
//button=temp;
}
console.log("Generating document...");
var orig_data = [];
var headers=[];
var headers_text_len_max=0;
var excel_wait_html='<i class="fa fa-spinner fa-pulse"></i> Please wait...';
button.data('orig-html',button.html());button.html(excel_wait_html);
if (tableObj.data('ts_currentRowsInTable').length<1 || (tableObj.data('ts_currentRowsInTable').length==1 && tableObj.find('tr:contains("No known")').length>0)) {
return BootstrapMessage("Cannot download Excel document","Sorry but there aren't any result rows to populate an excel document. Please refine your report/resultant listing.",function() {
button.html(button.data('orig-html'));
});
}
var doSetupProperties=false;
if (typeof(props)==='undefined') {props={};}
if (typeof(props.column_widths)==='undefined') {
doSetupProperties=true;
props.column_widths=[];
props.column_widths_auto=[];
props.maxWidthPerRow=[];
}
var filterChosen=false;
if (tableObj.hasClass("selectable")) filterChosen=true;
var ignoreCols=[];
var i=0;
tableObj.find('th').each(function() {
if ($(this).text().length<1) ignoreCols.push(i);
else {
headers.push($(this).text());
props.maxWidthPerRow.push(0);
headers_text_len_max+=$(this).text().length;
}
i++;
});
orig_data.push(headers);
console.log("Headers done.");
var handleRow=function(row,ignoreCols) {
var col_i=0;
row.find('td').each(function() {
if ($.inArray(col_i,ignoreCols)<0) {
var text=$(this).text().split('\n').join('').trim();
if ($(this).hasClass('sorter-select')) {
text=$(this).find('select:first').val();
}
var contents=text;
if (tableObj.hasClass('attachTotalsRow')) {
if ((''+tableObj.data('totals_columns')).indexOf(col_i+1)!=-1) {
text=(text.replace('$',''));
contents=parseFloat(text);
}
//row_data.push({value: text,metadata: {style: }});
//row_data.push(parseFloat(text));
}
row_data.push(contents);
var href=$(this).find('a');
if (href.length>0) {
var url=href.attr('href');
row_data[row_data.length-1]={value: 'HYPERLINK("'+url+'","'+text+'")', metadata: { type: 'formula' }};
}
if (text.length > props.maxWidthPerRow[col_i]) props.maxWidthPerRow[col_i]=text.length;
}
col_i++;
});
return (row_data);
}
if (tableObj.hasClass('tablesorter')) {
/*its tablesorter, so we need to obtain all of the hidden filtered data too. */
var rows=tableObj.data('ts_currentRowsInTable');
for (i=0;i<rows.length;i++) {
var row_data=[];
var row = $(rows[i]);
/*if (filterChosen && !isNaN(tableObj.data('chosen'))) {
var target=row.find('td:nth-child('+tableObj.data('chosen')+' input[type=checkbox]');
if (target.length==1) {
if (!target.prop('checked')) continue;
}
}*/
orig_data.push(handleRow(row,ignoreCols));
}
} else {
tableObj.find('tbody tr').each(function() {
var row_data=[];
var row=$(this);
orig_data.push(handleRow(row,ignoreCols));
});
}
if (tableObj.hasClass('attachTotalsRow')) {
var list_cols=tableObj.data('totals_columns');
if (isNaN(list_cols)) {
var av_cols=list_cols.split(',');
} else {
var av_cols=[list_cols];
}
av_cols=av_cols.sort();
var max=orig_data.length;
var min=2; // skip header row
var new_totals_row=[];
for (var ii=0;ii<headers.length;ii++) {
new_totals_row[ii]="";
}
for (var i=0;i<av_cols.length;i++) {
var colIdent=String.fromCharCode(64+av_cols[i]);
new_totals_row[0]="Totals:"
new_totals_row[av_cols[i]-1]={value: 'SUM('+((colIdent+min)+':'+(colIdent+max))+')',metadata: {type: 'formula'}};
}
orig_data.push(new_totals_row);
}
// adjust column widths to fit their text.
if (doSetupProperties) {
var maxDigitWidth=8;
var padding=22;
var fn_truncate=function(num) {return Math.round(num*100)/100;};
var fn_calcWidth=function(numchars,maxdigit,pad) {return fn_truncate(((numchars * maxdigit + pad)/maxdigit*256)/256 );};
var fn_calcPixels=function(p_width,maxdigit){return fn_truncate(((256 * p_width + fn_truncate(128/maxdigit))/256)*maxdigit);};
for (var i=0;i<headers.length;i++) {
var perc_size_of_whole=(100/headers_text_len_max)*headers[i].length;
//props.column_widths.push({width: perc_size_of_whole*1.5});
//props.column_widths_auto.push({bestFit: true,width: maxWidthPerRow[i]});
props.column_widths.push({width: (fn_calcWidth(props.maxWidthPerRow[i],maxDigitWidth,padding)) });
}
}
console.log(props);
console.log("Row data done.");
require(['excel-builder/excel-builder', 'excel-builder/Excel/Table','excel-builder/download'], function (EB, Table, downloader) {
console.log("Beginning excel creation.");
var workbook = EB.createWorkbook();
var worksheet = workbook.createWorksheet({name: filename});
var stylesheet = workbook.getStyleSheet();
var currency = stylesheet.createFormat({
format: '$#,##0.00'
});
var boldDXF = stylesheet.createDifferentialStyle({
font: {
italic: true,
size: 12
}
});
var sheetStyle=stylesheet.createTableStyle({
name: 'SlightlyOffColorBlue',
wholeTable: boldDXF.id,
headerRow: stylesheet.createDifferentialStyle({
alignment: {horizontal: 'center'},
font: {
size: 13,
bold: true
}
}).id
});
console.log("Styles applied.");
var table = new Table();
table.styleInfo.themeStyle = "SlightlyOffColorBlue"; //"TableStyleDark2"; //This is a predefined table style
table.setReferenceRange([1, 1], [headers.length, orig_data.length]); //X/Y position where the table starts and stops.
//Table columns are required, even if headerRowCount is zero. The name of the column also must match the
//data in the column cell that is the header - keep this in mind for localization
table.setTableColumns(headers);
console.log("headers configured.");
worksheet.setData(orig_data);
worksheet.setColumns(props.column_widths)
//worksheet.setColumnFormats(props.column_widths_auto);
workbook.addWorksheet(worksheet);
worksheet.addTable(table);
workbook.addTable(table);
console.log("tables configured.");
var dt=new Date();
var file= replaceAll(filename," ","_") +"_"+ (dt.getFullYear()+"-"+dt.getMonth()+"-"+dt.getDate()+"_"+dt.getMilliseconds())+'.xlsx';
file=replaceAll(file,"/","_"); file=replaceAll(file,"\\","_");
var data = EB.createFile(workbook);
console.log("workbook generated. File generation commensing: ");
//downloader(file, data); // this uses the downloader.js file. Disabled as I am customizing the ajax call completely... as follows..
/*legacy attempt.. var contents=''+
'<form method="POST" action="/app/assets/excel-builder/excel.cfm" enctype="application/x-www-form-urlencoded">'+
'<input type="hidden" name="filename" value="'+file+'" />'+
'<input type="hidden" name="contentType" value="'+('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')+'" />'+
'<input type="hidden" name="contents" value="'+data+'" />'+
'<input type="submit" value="Download Now" class="button print" />'+
'</form>';*/
var dat={
filename: file,
contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
contents: data
};
$.ajax({
url: '/app/assets/excel-builder/excel2.cfm',
type: "POST",
data: dat,
success: function(result) {
result=$.parseJSON(result);
console.log("Response received. File is located here: "+result.FILE);
if (typeof(onExcelDocGenerated)==='function') onExcelDocGenerated(); // optional callback (global)
contents='<a style="color: lightgreen;" href="'+result.FILE+'" class="button print" >Download Now</a>';
$.notice("Confirm Excel Download",contents,"Cancel",function() {
button.html(button.data('orig-html'));
if (typeof(excel_download_done)==='function') {
excel_download_done(); // optional callback (global)
}
},function() {
button.html(button.data('orig-html'));
if (typeof(excel_download_done)==='function') {
excel_download_done();
}
});
},
error: function(e) {
console.log("Fatal networking error: "+e);
}
});
});
}
And the implementation on the page..
<a href="#" id="exceldownload" onclick="try {downloadExcelFromTable($('table'),'My Report');}catch(e){alert('failed due to error: '+e);};return false;" class="button print table-excel">
<i class="fa fa-file-excel-o"></i> Excel
</a>
So that was a tablesorter full implementation supporting links inserted into the excel sheet and even a row for summation (totals) by simply adding the class(.attachTotalsRow) to the table class attr.
Even supports filtering, so it only grabs the rows that are filtered by tablesorter for the excel, and auto-column sizing based on text width.
There's several pieces that you can see were being developed, and lots of sparse comments and console logs thrown about, but it works.
The above is designed for the ajax call which provides a path to a file in JSON response. That way you can use the browser native click, which is supported on all devices. Opening a new window through javascript is unsafe, so that is the reason for that approach. Therefore the php script at the top would need updated to mimic the coldfusion one.
The part you wanted is at the bottom just before the ajax call.
Good luck!
var workbook = ExcelBuilder.Builder.createWorkbook();
var stylesheet = workbook.getStyleSheet();
var sheet1 = workbook.createWorksheet({
name: 'Data1'
});
var headings = stylesheet.createFormat({
"fill": {
"type": 'pattern',
"patternType": 'solid',
"fgColor": '4BACC6'
}
});
var jsonData = [
[{value:'sample', metadata: {style: headings.id}}, {value:'data', metadata: {style: headings.id}}, {value:'for', metadata: {style: headings.id}}],
['generating', 'excel', 'in'],
['java', 'script', ' ']
];
sheet1.setData(jsonData);
workbook.addWorksheet(sheet1);
ExcelBuilder.Builder.createFile(workbook, {
type: "blob"
}).then(function(data) {
saveAs(new Blob([data], {
type: "base64"
}), "Demo.xlsx");
});

How to add the image file from the form to the jQuery ajax request

I am working a jQuery file upload helper and I need to understand how can I append the File from the form or the Form data as a whole to the request.
I have worked with the ASP.NET code to accept image from the Request and handle the further code, but when I try to use it using jQuery $.ajax() I can't get it to work.
I have been though Stack Overflow questions, and I have tried using FormData appending the data from the input[type="file"] (input for the file element). But each time (on the server) the block that is executed that tells me there is no file with the request.
Here is the ASP.NET code (UploadFile page)
#{
var fileName = "Not running!";
if(IsPost) {
if(Request.Files.Count > 0) {
var image = WebImage.GetImageFromRequest();
fileName = Path.GetFileName(image.FileName) + " From server";
} else {
fileName = "No file attached! From Server";
}
}
Response.Write(fileName);
}
The jQuery code is as
$(document).ready(function () {
$('form input[type=submit]').click(function () {
event.preventDefault();
$.ajax({
url: '/UploadFile',
data: new FormData().append('file',
document.getElementById("image").files[0]),
type: 'POST',
success: function (data) {
$('#result').html('Image uploaded was: ' + data);
}
});
});
});
I am already scratching my head since I can't get the file content on the serverside.
How can I send the file to the server, or the entire form data to the server, anything would be welcome!
Try using handler for this and Newtonsoft.json.dll for these purpose.
For jQuery
(document).ready(function () {
$('form input[type=submit]').click(function () {
event.preventDefault();
$.ajax({
url: 'handler.ashx', // put a handler instead of direct path
data: new FormData().append('file',
document.getElementById("image").files[0]),
type: 'POST',
success: function (data) {
$('#result').html('Image uploaded was: ' + data);
}
});
});
});
In asp.net
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Web;
using Newtonsoft.Json;
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpPostedFile up = context.Request.Files[0];
System.IO.FileInfo upinfo = new System.IO.FileInfo(up.FileName);
System.Drawing.Image upimg = System.Drawing.Image.FromStream(up.InputStream);
string path = context.Server.MapPath("~/temp"); // this is the server path where you'll be saving your image
if (!System.IO.Directory.Exists(path))
System.IO.Directory.CreateDirectory(path);
string fileName;
fileName = up.FileName;
string newFilename = Guid.NewGuid().ToString();
System.IO.FileInfo fInfo = new System.IO.FileInfo(fileName);
newFilename = string.Format("{0}{1}", newFilename, fInfo.Extension);
string strFileName = newFilename;
fileName = System.IO.Path.Combine(path, newFilename);
up.SaveAs(fileName);
successmsg1 s = new successmsg1
{
status = "success",
url = "temp/" + newFilename,
width = upimg.Width,
height = upimg.Height
};
context.Response.Write(JsonConvert.SerializeObject(s));
}

Telerik auto complete box text changed event using Java script

My requirement is I have 2 controls Code and description, when I select the code description will automatically displays and I want to select multiple codes automatically display multiple descriptions in description control and vice versa.
For this scenario I am supposed to use "auto complete box" using page methods, for the first time I am using Telerik controls.
Now I am able to get Codes in code auto complete box and able to select multiple codes.
Now my question is how to select the description after selecting multiple codes using Java script/jQuery?
My code is like below
<telerik:RadAutoCompleteBox ID="RdAutoClassCode" runat="server" Width="150" DropDownHeight="150"
DropDownWidth="150" TokensSettings-AllowTokenEditing="True" OnClientTextChanged="OnClientChange" on>
<WebServiceSettings Method="GetISOCodesRadCombobox" Path="GetClassCodeAndDescription.aspx" />
</telerik:RadAutoCompleteBox>
function OnClientChange() {
debugger;
alert("Hi");
}
Text changed event is not firing using above code.
Please provide any sample for this?
Thanks in advance,
Srividya
I finally got the solution.
<telerik:RadAutoCompleteBox ID="RdAutoClassCode" runat="server" Width="150" DropDownHeight="70"
OnClientEntryRemoved="RemoveEntry" OnClientEntryAdded="addNewEntry" height="150" DropDownWidth="150"
TokensSettings-AllowTokenEditing="True">
<WebServiceSettings Method="GetISOCodesRadCombobox" Path="GetClassCodeAndDescription.aspx" />
</telerik:RadAutoCompleteBox>
<telerik:RadAutoCompleteBox ID="RdAutoClassDesc" runat="server" Width="150" DropDownHeight="70"
height="150" DropDownWidth="150" TokensSettings-AllowTokenEditing="True">
<WebServiceSettings Method="GetISOCodeDescriptionsRadCombobox" Path="GetClassCodeAndDescription.aspx" />
</telerik:RadAutoCompleteBox>
Web Methods:
[WebMethod]
public static AutoCompleteBoxData GetISOCodesRadCombobox(object context)
{
string searchString = ((Dictionary<string, object>)context)["Text"].ToString();
DataTable data = GetData(searchString, 0);
List<AutoCompleteBoxItemData> result = new List<AutoCompleteBoxItemData>();
foreach (DataRow row in data.Rows)
{
AutoCompleteBoxItemData childNode = new AutoCompleteBoxItemData();
childNode.Text = row["CodeNumber"].ToString();
childNode.Value = row["CodeNumber"].ToString();
result.Add(childNode);
}
AutoCompleteBoxData res = new AutoCompleteBoxData();
res.Items = result.ToArray();
return res;
}
[WebMethod]
public static AutoCompleteBoxData GetISOCodeDescriptionsRadCombobox(object context)
{
string searchString = ((Dictionary<string, object>)context)["Text"].ToString();
DataTable data = GetData(searchString, 1);
List<AutoCompleteBoxItemData> result = new List<AutoCompleteBoxItemData>();
foreach (DataRow row in data.Rows)
{
AutoCompleteBoxItemData childNode = new AutoCompleteBoxItemData();
childNode.Text = row["CodeDesc"].ToString();
childNode.Value = row["CodeDesc"].ToString();
result.Add(childNode);
}
AutoCompleteBoxData res = new AutoCompleteBoxData();
res.Items = result.ToArray();
return res;
}
private static DataTable GetData(string text, int Value)
{
SqlConnection con = new SqlConnection(ConfigurationManager.AppSettings["QMSDBCON"]);
DataSet ds = SqlHelper.ExecuteDataset(con, "usp_GetIsoCode", text, Value);
DataTable data = new DataTable();
// adapter.Fill(data);
data = ds.Tables[0];
return data;
}
JavaScript Calling for new entry:
function addNewEntry() {
debugger;
var autoCompleteBoxCode = $find("<%= RdAutoClassCode.ClientID %>");
var autoCompleteBoxDescription = $find("<%= RdAutoClassDesc.ClientID %>");
var entriesCount = autoCompleteBoxCode.get_entries().get_count();
var entry = new Telerik.Web.UI.AutoCompleteBoxEntry();
autoCompleteBoxDescription.get_entries().clear();
for (var i = 0; i < entriesCount; i++) {
var code = autoCompleteBoxCode.get_entries().getEntry(i).get_text();
_ClassCodeSelectedIndexChanged(code);
}
}
Calling server method using Json
function _ClassCodeSelectedIndexChanged(code) {
debugger;
var URL = window.location.protocol + "//" + window.location.host;
URL = URL + "/GetClassCodeAndDescription.aspx/GetISOCodesRadComboboxData";
$(document).ready(function () {
$.ajax({
type: "POST",
url: URL,
data: "{Code : '" + code + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
onsuccess(msg);
},
error: function (xhr) {
onerror(xhr);
}
});
});
}
jQuery("#textbox").blur(function() {
ajaxFunction(jQuery("#textbox").val());
});
function ajaxFunction(code){
// Your ajax call
}
Try this hopeFully this help.

Categories