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.