Конвертировать Razor HTML в загружаемый PDF - PullRequest
0 голосов
/ 30 августа 2018

У меня есть динамически отфильтрованная таблица элементов, и у каждого есть группа кнопок для работы с ними. Один из них показывает частичный HTML, сгенерированный с помощью Razor с данными элемента.

Запись в таблице:

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.##")&nbsp;&euro;</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> }

Элемент, с которым я хочу работать, генерируется в строке

@Html.Partial("_PresupuestoFinal", item)

Итак, с помощью jQuery я предоставляю функции этим кнопкам. Код кнопки PDF:

$(".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,
    });
};

Но каждый раз, когда я нажимаю кнопку, я попадаю на консоль:

TypeError: can't convert undefined to object

Обращаясь к строке, когда я вызываю функцию Pdf. Что я хочу сделать, это выбрать этот конкретный HTML (тот, который соответствует элементу) и преобразовать его в файл PDF. Так как я не могу получить достаточно информации, чтобы узнать, где ошибка, что я делаю не так?

Кстати, строка url: 'DescargarPDF указывает на метод в моем контроллере.

EDIT

Вот мой метод контроллера по запросу:

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();
    }

Скрипт не срабатывает.

2-е РЕДАКТИРОВАНИЕ

Итак, я получил больше информации об ошибке:

presupuestoHTML[toArray]

Это причина ошибки. Не знаю где или как.

3-е РЕДАКТИРОВАНИЕ

Хорошо, теперь я знаю, что проблема в скрипте, получающем нужный мне HTML. Я изменил эту строку:

$(".convertirPDF").on("click", function (id) {
    itemId = $(this).data('itemid');
    presupuesto = document.documentElement.getElementsByTagName('vistaDetalles' + itemId);
    Pdf(presupuesto);
});

А теперь ошибка в консоли:

TypeError: 'item' called on an object that does not implement interface HTMLCollection.

Я буду продолжать изучать это, надеюсь, это прояснит проблему.

2-е ОБНОВЛЕНИЕ

Я работал над этим, у меня все работает, кроме загрузки файла. Я объясню:

Вот скрипт, он попадает в метод контроллера с правильными данными.

$(".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,
    });
};

Так что это работает. Вот мой метод контроллера, где я подозреваю, что проблема вызвана:

 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");
    }

Это моя последняя попытка. Я также попробовал Rotativa ActionAsPdf и получил в консоли браузера поток данных (который, я должен догадаться, это файл PDF), а не загружаемый файл. Я также пробовал другие варианты, такие как преобразование файла в байтовый массив и его потоковую передачу, но поскольку я не хочу сохранять файл, эта опция отбрасывается (функции требуют путь к файлу, который я не могу предоставить, поскольку файл не сохраняется, все еще в памяти). Все еще работаю над этим.

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Я задал еще один вопрос , чтобы попытаться решить проблему, связанную с отсутствием загрузки файла, и получил его.

Прежде всего, я делал запрос через ajax, потому что я думал, что это хороший способ сделать это, но, как оказалось, есть гораздо более простой способ: не использовать ajax.

Итак, я удалил скрипт для кнопки и самой кнопки, поэтому теперь выглядит так:

<a href="DescargarPDF/?itemId=@item.Id" target="_blank" class="btn btn-secondary btn-info">PDF</a>

Он выглядит так же, как и раньше, но на самом деле это ссылка на метод моего контроллера, который сейчас выглядит так:

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);           
    }

Я знаю, что в большинстве случаев это не будет правильным решением, так как я просто оставил ajax позади, но есть много других вопросов, ответ на которые работал для них, и они все еще используют ajax для управления запросом.

Тем не менее, я надеюсь, что это поможет. Спасибо всем. Удачного кодирования.

UPDATE

Я только что узнал, почему мой PDF-файл был сброшен в консоль, отметьте другой вопрос , я оставил небольшое объяснение этой конкретной проблемы. Спасибо всем.

0 голосов
/ 30 августа 2018

Вы можете использовать только JavaScript:

  • Сверните содержимое HTML в div и установите для него идентификатор
  • Скачать jsPDF
  • Следуйте этому примеру: https://rawgit.com/MrRio/jsPDF/master/ (HTML Renderer)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...