JSPDF html() Method callback not Fired - PCF

1.8k Views Asked by At

JSPDF html() method, Callback never gets fired nor able to Catch any Error. what could be the possible issue for callback not fire.

I also tried with plain html and js script via CDN. callback works perfectly from same Browser and PDF download Starts

import { IInputs, IOutputs } from "./generated/ManifestTypes";
import { jsPDF } from "jspdf";

export class pcf implements ComponentFramework.StandardControl<IInputs, IOutputs> {
    private _value: number;

    private _notifyOutputChanged: () => void;
    // private labelElement: HTMLLabelElement;
    // private inputElement: HTMLInputElement;
    private container: HTMLDivElement;
    private _context: ComponentFramework.Context<IInputs>;
    private _refreshData: EventListenerOrEventListenerObject;
    private _edtorplaceholder: HTMLDivElement;
    private isrendered: boolean;
    //private editor : editorJS;


    public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement): void {
        this._context = context;
        this.container = container;
        this._notifyOutputChanged = notifyOutputChanged;
        this._refreshData = this.refreshData.bind(this);
        //this._value = context.parameters.controlValue.raw!;


        const gridHTML = `
<div id="dashboard">

 <button id="save-button">Download</button>
 `
        let ele = document.createElement("div");
        this.container = document.createElement("div");
        this.container.id = 'GridContainer';
        this.container.innerHTML = gridHTML;

        //ReactDOM.render(React.createElement(new editorJS(), null), this.container);
        this.exportToPDF("");
        container.appendChild(this.container);
    }

    public refreshData(evt: Event): void {
        //  this._value = (this.inputElement.value as any) as number;
        //  this.labelElement.innerHTML = this.inputElement.value;
        this._notifyOutputChanged();
    }

    public updateView(context: ComponentFramework.Context<IInputs>): void {
        // storing the latest context from the control.
        //this._value = context.parameters.controlValue.raw!;
        this._context = context;
        var params = context.parameters;


        if (params.fileName.raw?.startsWith('yes') && (this.isrendered !== true)) {
            console.log("pcf fired");
            this.isrendered = true;
            return;


        }
    }


    public getOutputs(): IOutputs {
        return {
            //controlValue: this._value
        };
    }
    public pdfReady(doc: any): void {

    }
    public destroy(): void {
        //  this.inputElement.removeEventListener("input", this._refreshData);
    }

    public delay(ms: number) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    public exportToPDF(data: string) {
        try {
            //window["html2canvas"] = html2canvas;
            const doc = new jsPDF();
            var width = doc.internal.pageSize.getWidth();
            var height = doc.internal.pageSize.getHeight();
            doc.setFontSize(40);
            doc.text("Sample Header", 10, 10);
            doc.line(width / 4, height / 4, width, height / 4);
            console.log("html method called!");
            doc.html(`<!DOCTYPE html>
            <html>
            <body>
            <h2>Text input fields</h2>
            <p>Note that the form itself is not visible.</p>
            <p>Also note that the default width of text input fields is 20 characters.</p>
            </body>
            </html>
            `, {
                callback: (doc) => {
                    console.log("html is getting Called Back..!");
                    doc.save();
                }
            }

            );
        } catch (error) {
            console.log(error);
        }
    }

}

package.json


{ "name": "pcf-project", "version": "1.0.0", "description": "Project containing your PowerApps Component Framework (PCF) control.", "scripts": { "build": "pcf-scripts build", "clean": "pcf-scripts clean", "rebuild": "pcf-scripts rebuild", "start": "pcf-scripts start", "refreshTypes": "pcf-scripts refreshTypes" }, "dependencies": { "@types/react": "^17.0.38", "@types/react-dom": "^17.0.11", "clean": "^4.0.2", "html2canvas": "1.0.0-rc.1", "jspdf": "^2.5.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, "devDependencies": { "@types/node": "^16.4", "@types/powerapps-component-framework": "^1.3.0", "@typescript-eslint/eslint-plugin": "^4.29.0", "@typescript-eslint/parser": "^4.29.0", "eslint": "^7.32.0", "eslint-config-standard": "^16.0.2", "eslint-plugin-import": "^2.23.4", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", "pcf-scripts": "^1", "pcf-start": "^1", "typescript": "^4.3" } }


2

There are 2 best solutions below

2
On

I just realized Microsoft has implemented this functionality. You can enalbe PDF function in experimental options.

It is not exactly the same buy you can create an Screen with html Text and just use this function

1
On

jsPDF callback never gets fired because it depends on core-js to handle Promise.

If you import 'core-js/features/promise' callback is called but it breaks powerapss because powerapps uses bluebird to handle Promise

I make it work using

import jsPDF from "jspdf/dist/jspdf.es.min";
const myPromise = global.Promise;
var pp = require('core-js/features/promise');

Object.defineProperty(global, 'Promise', {
    value: myPromise
});

And then when generating pdf

public generatePdf() {

    const element = document.getElementById("input-html2pdf") as HTMLInputElement;
    Object.defineProperty(global, 'Promise', {
        value: pp
    });

    const doc = new jsPDF("p", "pt", "a4", true);

    try {
        doc.html(element.value, {
            html2canvas: {
                allowTaint: true,
                useCORS: true,
            },
            callback: async (doc) => {
                doc.save(`doc.pdf`);
                Object.defineProperty(global, 'Promise', {
                    value: myPromise
                });
            }
        });
    } catch (error) {
        console.error(error);
    }
}

Using this aprox works witch npm build watch and imported to powerapps as code component.