Reputation: 151
I have a dynamic filtered table of elements, and each one have a group of buttons to operate with them. One of them shows a partial HTML generated with Razor with the element's data.
Table entry:
foreach (var item in listado.Where(x => x.Raw != null)) {
<tr>
<td>@item.Id</td>
<td>@item.Usuario</td>
<td>@item.NIF_CIF</td>
<td>
@if (!(String.IsNullOrEmpty(item.Telefono)) && !(String.IsNullOrWhiteSpace(item.Telefono))) {
@item.Telefono
} else {
@Html.Raw("No disponible")}
</td>
<td>@Math.Round(item.Raw.PrecioTotal).ToString("0.##") €</td>
<td>@item.FechaCreacion.ToShortDateString()</td>
<td class="btn-group-sm" role="group">
<button class="eliminar btn btn-secondary btn-danger" data-itemid="@item.Id">Eliminar</button>
<button class="convertirPDF btn btn-secondary btn-info" data-itemid="@item.Id">PDF</button>
<button class="detalles btn brn-secondary btn-info" data-itemid="@item.Id">Detalles</button></td>
</tr>
<tr id="vistaDetalles@(item.Id)" hidden>
<td colspan="7">
@Html.Partial("_PresupuestoFinal", item)
</td>
</tr> }
The element I want to work with is generated in the line
@Html.Partial("_PresupuestoFinal", item)
So then, with jQuery, I provide function to those buttons. The PDF button code is:
$(".convertirPDF").on("click", function (id) {
var itemId = $(this).data('itemid');
var presupuesto = $('#content').html($(this).find('#vistaDetalles' + itemId).html());
Pdf(presupuesto);
});
function Pdf(presupuesto) {
presupuestoHTML = presupuesto;
$.ajax({
method: "GET",
url: 'DescargarPDF',
data: { presupuestoHTML: presupuesto },
cache: false,
async: true,
});
};
But every tim I press the button, I get on console:
TypeError: can't convert undefined to object
Referring to the line when I invoke the function Pdf. What I want to do is to pick that particular html (the one corresponding to the element) and convert it to a PDF file. Since I can't get enough info to know where the error is, what am I doing wrong?
BTW that url: 'DescargarPDF
line is pointing to the method in my controller.
EDIT
Here's my controller method as requested:
public void DescargarPDF (string presupuestoHTML) {
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=" + "PDF.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
MemoryStream ms = new MemoryStream();
TextReader txtReader = new StringReader(presupuestoHTML);
// Creamos un objeto de clase itextsharp document
Document doc = new Document(PageSize.A4, 25, 25, 30, 30);
// Creamos un pdfwriter de itextsharp que lee el documento y dirige un stream XML a un archivo
PdfWriter oPdfWriter = PdfWriter.GetInstance(doc, ms);
// Creamos un trabajador para parsear el documento
HTMLWorker htmlWorker = new HTMLWorker(doc);
// Abrimos el documento y se lo pasamos al trabajador
doc.Open();
htmlWorker.StartDocument();
// Parseamos el presupuesto en html al documento
htmlWorker.Parse(txtReader);
// Cerramos el documento y el trabajador
htmlWorker.EndDocument();
htmlWorker.Close();
doc.Close();
var bPDF = ms.ToArray();
Response.BinaryWrite(bPDF);
Response.End();
}
The script doesn't hit it.
2nd EDIT
So I got more info on the error:
presupuestoHTML[toArray]
Is what's causing the error. Don't know where, or how.
3rd EDIT
Ok so I know now the issue is on the script retrieving the html I want. I changed that line:
$(".convertirPDF").on("click", function (id) {
itemId = $(this).data('itemid');
presupuesto = document.documentElement.getElementsByTagName('vistaDetalles' + itemId);
Pdf(presupuesto);
});
And now the error in console is:
TypeError: 'item' called on an object that does not implement interface HTMLCollection.
I'll keep looking into it, hope this gets the issue clearer.
2nd UPDATE
I've been working on this, I got everything working except for the file download. I'll explain:
Here's the script, it hits the controller method with the proper data.
$(".convertirPDF").on("click", function (id) {
var itemId = $(this).data('itemid');
// var presupuesto = $('#vistaDetalles' + itemId).html();
Pdf(itemId);
});
function Pdf(itemid) {
var id = itemid;
$.ajax({
method: "POST",
url: 'DescargarPDF',
data: { itemId: id },
cache: false,
async: true,
});
};
So that works. Here's my controller method, where I suspect the trouble is caused:
public FileResult DescargarPDF (int itemId) {
var presupuesto = ReglasNegocio.Fachada.Consultas.ObtenerPresupuesto(itemId);
var archivo = new Rotativa.PartialViewAsPdf("_PresupuestoFinal", presupuesto) { FileName = "Presupuesto_" + itemId + ".pdf" };
return File(archivo.FileName, "application/pdf");
}
That's my last try so far. I've tried Rotativa's ActionAsPdf
as well and I got on the browser console a stream of data (which I have to guess it's the pdf file) not the downloadable file. I've also tried other options like converting the file to a byte array and stream it but since I don't want to save the file, that option is discarded (functions require a file path, which I'm not able to provide because the file is not saved, still on memory). Still working on it.
Upvotes: 1
Views: 1058
Reputation: 151
I asked another question to try to solve the not downloading file issue, and I got it.
Before anything, I was doing the request through ajax because I thought to be a good way to do so, but as it turns out, there's a much simpler way: not using ajax.
So, I removed the script for the button and the button itself, so now looks like this:
<a href="DescargarPDF/[email protected]" target="_blank" class="btn btn-secondary btn-info">PDF</a>
It has the same appearance than before, but it's actually a link to my controller's method, which right now looks like this:
public FileResult DescargarPDF (int itemId) {
var presupuesto = ReglasNegocio.Fachada.Consultas.ObtenerPresupuesto(itemId);
var archivo = new Rotativa.PartialViewAsPdf("_PresupuestoFinal", presupuesto) { FileName = "Presupuesto_" + itemId + ".pdf", PageSize = Rotativa.Options.Size.A4 };
var binario = archivo.BuildFile(this.ControllerContext);
return File(binario, "application/pdf", archivo.FileName);
}
I know in most cases this wouldn't be a valid solution since I just left ajax behind, but there are many other questions where the answer worked for them and they still use ajax to manage the request.
Still, I hope this helps. Thanks to everyone. Happy coding.
UPDATE
I just found out why my PDF file was dropped into console, check the other question, I left a little explanation for that particular issue. Thanks everyone.
Upvotes: 1
Reputation: 128
You could use only javascript:
Upvotes: 0