django_plotly_dash: error exporting to pdf with html2pdf.js - javascript

I am trying to export a django_plotly_dash dashboard to pdf and can't quite get it. I am stuck with the following error in console when clicking on the button to trigger the export:
ReferenceError: html2pdf is not defined
at Object.nClicksToPDF [as n_clicks]
which is telling me that html2pdf cannot be found. I have tried importing in assets folder as well as cdn directly in the app layout but nothing seems to do the trick and I am out of things to try:
here is how I import it in the app:
html.Script(src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"),
here is my callback where it is called:
app.clientside_callback(
"""
function nClicksToPDF(n_clicks){
if(n_clicks > 0){
document.querySelector('.chkremove').style.display = 'none';
const opt = {
margin: 2,
filename: 'myfile.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 1},
jsPDF: { unit: 'cm', format: 'a2', orientation: 'p' },
pagebreak: { mode: ['avoid-all'] }
};
console.log('ok')
html2pdf().from(document.getElementById("print")).set(opt).save();
setTimeout(function(){
document.querySelector('.chkremove').style.display = 'block';
}, 2000);
}
}
""",
Output('js','n_clicks'),
Input('js','n_clicks')
)
Don't know what else to do, any help would be highly welcome!

The problem comes from the html.Script component, which does not work as one might expect : in short, the <script> tag is created, but never executed.
It is part of a larger issue : Several components have limited or no functionality in current browsers :
[...] browsers don't execute <script>s inserted in the way react does it (via innerHTML). Including html.Script in the documentation only leads folks
down dead ends. Either it should use a different insertion mechanism,
or it should have a bright big warning in the docs, or it should be
removed entirely.
The alternative is to add html2pdf as an external script, ie :
scripts = [{
'src': 'https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js'
}]
app = DjangoDash(__name__, external_scripts=scripts)

Related

JavaScript / TypeScript issue with HTML [duplicate]

utility.ts
let books = [
{ id: 1, title: "the dark window", author: "krishna", available: true },
{ id: 2, title: "naked eye", author: "sydney", available: false },
{ id: 3, title: "half girlfriend", author: "chetan", available: true },
{ id: 4, title: "make my dreams", author: "salam", available: false }
];
export { books };
main- app.ts
import {books} from './utility';
let getAllBooks = (): void => {
books.filter((val) => {
console.log(val.author);
})
}
How can I access the getAllBooks functiion in a Html page?
If I don't use export and import it works perfectly fine but I have to use it instead of writing everything into one file.
Please advice [using amd module] to generate one JS file as output [main.js].
Getting the below error in the chrome console.
[(index):13 Uncaught ReferenceError: getAllBooks is not defined
at HTMLInputElement.onclick ((index):13)]
My html page
<html>
<title>Welcome</title>
<head>
<script data-main="./js/main" src="./js/require.js"></script>
<script src="./js/main.js"></script>
<body>
<div id="mytest"></div>
<input type="button" value="Click!" id="btnClick" onclick="getAllBooks();" />
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</body>
</head>
</html>
main.js
define("utility", ["require", "exports"], function (require, exports) {
"use strict";
let books = [
{ id: 1, title: "the dark window", author: "krishna", available: true },
{ id: 2, title: "naked eye", author: "sydney", available: false },
{ id: 3, title: "half girlfriend", author: "chetan", available: true },
{ id: 4, title: "make my dreams", author: "salam", available: false }
];
exports.books = books;
});
define("app", ["require", "exports", "utility"], function (require, exports, utility_1) {
"use strict";
let getAllBooks = () => {
utility_1.books.filter((val) => {
console.log(val.author);
});
};
});
//# sourceMappingURL=main.js.map
Update browser to recent one (recent enough to support ES2015 module)
Change tsconfig.json target to es2015
Change tsconfig.json module to es2015
Always add .js extension to your import statements
Use an http server like live-server to avoir CORS concerns with file:// protocol
BONUS: Explicitly set tsconfig.json moduleResolution to node. This is not necessary if you don’t use external libraries or #types/* packages.
See it altogether at : https://github.com/SalathielGenese/ts-web
Disclosure : I'm its author.
Browsers do not yet support javascript modules. Until they do you will need to include browserify into your development workflow. Browserify concatenates your modules into a browser friendly bundle.
Browserify is very simple to get working in a typescript workflow. If you are feeling adventurous you can look at other bundlers like WebPack, Rollup or SystemJs.
Note, this is not specific to TypeScript. When developing any modern javascript (es6 or CommonJS modukes) you will need to bundle modules for the browser.
Im new to AMD but it looks like you only define the modules, never invoke/import them to the sites scope.
In this tutorial the author has a bootstrapping file that acts as entry point for an app which seems to be what you're missing: http://www.codebelt.com/typescript/typescript-amd-with-requirejs-tutorial/
I think the title is incorrect and what you really trying to do is running TypeScript applications in te browser which is totally different yo "Run TypeScript in the browser, right?
In that case to get started with TypeScript I recommend you to not use require.js add instead a bundler-like tool like a tool like parcel, webpack, browserify, rollup. parcel is super easy : For your example, 1) remove ALL script tags and add only the following: <script src="my/app.ts"> then "compile" that html with parcel theFile.html or build for production : parcel build theFile.html
if I was right, could you please change the title of this question since is confusing and misleading ? thanks.
Now, on the other side, If you really want to run TypeScript as the title say, typescript is fully compatible with the browser (the .js file library is node_modules/typescript/lib/typescript.js ). just import it as another module or load the file in a script tag and use the Compiler API..
This project contains my research on the topic with several working examples and demo apps and some tools: https://github.com/cancerberoSgx/typescript-in-the-browser

CSS in PDF not loading on server

I am using html2pdf library to generate PDF of my HTML. On my local machine below code is working fine but when I deployed the same on the server the PDf is generating without CSS styles. Below is my Code. Kindly help me to resolve this issue.
window.onload = function () {
document.getElementById("generatePdf").addEventListener("click", () => {
const cvitae = this.document.getElementById("configuration-area-c");
var opt = {
filename: "morsewatchment-configurator.pdf",
image: { type: "jpeg", quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: "in", format: [12, 6], orientation: "portrait" },
};
//html2pdf().from(cvitae).set(opt).save();
});
};
This is a known issue when working with html2pdf.js, you can read more here, also issue on github.
The obvious approach to fix this is to include all your needed css rules in a style tag directly in the html page.
Also you can go to this branch on Github look into the /dist/ directory and pull out whichever files your project relies on and use it.
Or if you are using npm run :
npm install eKoopmans/html2pdf.js#bugfix/clone-nodes-BUILD

nuxt.config.js not loading .css files

I am attempting to include my meta information (mostly visible in the static .css and .js files) to my Nuxt application by adding them into nuxt.config.js. I am expecting all of my global meta tags (charset, keywords, etc) as well as my CSS to be loaded when I reload the project on the page I'm testing on, however only using the local vue-meta section gives these desired results. I would like to be able to have most of my meta in the configuration file, so while leaving everything in each page is an option,it is not the one I would like to take.
I get no warnings or errors when loading the page, which makes me believe that it's not a problem, but I have just started using this file and would like to know if it is something trivial
The head I am trying to implement in nuxt.config.js is below. All file paths are valid (since they are what I use in the individual pages and they work just fine.
module.export = {
head:{
meta: [
{charset: 'utf-8'},
{
name: 'keywords', content: '~some keywords~'
},
],
link: [
{ rel: 'stylesheet', href: '/css/style.css' },
{ rel:'stylesheet', href:'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css'},
{ rel:'canonical', href:'https://www.self.com' }
],
script: [
{src: 'https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js'},
{src: 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js'},
{src: 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js'},
]
},
//...
}
I also have a similar body in my css: section, however that produced no results as well.
I believe you are missing a period ( . ) in your CSS link href, try:
href: './css/style.css'
Also you can try adding CSS as a property of your head object:
head {
link: [...],
css: ["./css/style.css"],
script: [...]
}/*end of head*/
If you try the second option then remove the CSS ref from your link array.
Good luck!

Using the AWS SDK for Javascript with Vue.js 2.0

I'm accessing API's hosted by AWS API Gateway with Vue.Js.
There's some pretty good instructions here http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk-javascript.html.
I have a bunch of different components, each of which will get data from a different API GET call. Initially I tried adding all the script files to my index.html and doing the following:
RetailerDetails.vue:
<script>
export default {
name: 'RetailerDetails',
mounted() {
var apigClient = apigClientFactory.newClient({
accessKey: 'blah',
secretKey: 'blah',
});
apigClient.businessGet = function (params, body, additionalParams) {
if (additionalParams === undefined) { additionalParams = {}; }
apiGateway.core.utils.assertParametersDefined(params, [], ['body']);
var businessGetRequest = {
verb: 'get'.toUpperCase(),
path: pathComponent + uritemplate('/business').expand(apiGateway.core.utils.parseParametersToObject(params, [])),
headers: apiGateway.core.utils.parseParametersToObject(params, []),
queryParams: apiGateway.core.utils.parseParametersToObject(params, []),
body: body
};
return apiGatewayClient.makeRequest(businessGetRequest, authType, additionalParams, config.apiKey);
};
},
}
That didn't work, I got ReferenceError: apigClientFactory is not defined.
So then I tried taking the script tags out of my index.html and adding the following lines to my component:
require('../assets/js/lib/axios/dist/axios.standalone.js');
require('../assets/js/lib/CryptoJS/rollups/hmac-sha256.js');
require('../assets/js/lib/CryptoJS/rollups/sha256.js');
require('../assets/js/lib/CryptoJS/components/hmac.js');
require('../assets/js/lib/CryptoJS/components/enc-base64.js');
require('../assets/js/lib/url-template/url-template.js');
require('../assets/js/lib/apiGatewayCore/sigV4Client.js');
require('../assets/js/lib/apiGatewayCore/apiGatewayClient.js');
require('../assets/js/lib/apiGatewayCore/simpleHttpClient.js');
require('../assets/js/lib/apiGatewayCore/utils.js');
require('../assets/js/custom/apigClient.js');
This don't work either, now I get ReferenceError: Can't find variable: CryptoJS
which from what I understand is because I haven't referenced the flles properly?
What do I need to do?
Don't put javascript files in the assets folder. Put them in the static folder instead. If you are using the CLI install, Webpack sorts through the assets and takes care of things like image and fonts, but not javascript files.
When I put the files in the /static/ or something like /static/js/ and then bring them in with:
<script type="text/javascript" src="/static/apigClient.js"></script>
the functions are available to my Vue components. Maybe there's a nicer way that doesn't pollute the global namespace, but this is a pretty easy solution (assuming it also works for you).

dojo 1.9 config with custom package paths

So I can see that the file was loaded properly from the dojoConfig reference but, when I attempt to use the module its 'undefined' any suggestions:
Updated: This will load the file, but when I throw the variable into a console nothing comes out. When inspecting it, I see a lot of text instead of the array of objs I placed inside.
index.html:
<script>
dojoConfig = {
tlmSiblingOfDojo: true,
async: true,
parseOnLoad: false,
packages: [
{ name: "main", location: "/components/3.6compact/js/dojo/dojo/main"},
{ name: "jquery", location: "/scripts/libs", main: "jquery"},
{name: "jam", location: "/scripts/mylibs", main: "lod"}
]
};
</script>
<script src="/components/3.6compact/js/dojo/dojo/dojo.js"></script>
<script src="/scripts/app.js"></script>
lod.js:
define([], function(){
var lod = [{
'level': 0,
'resolution': 156543.033928,
'scale': 591657527.591555
}, {
'level': 1,
'resolution': 78271.5169639999,
'scale': 295828763.795777
}
];
return lod;
});
app.js:*
require(['jam'], function(jam){
console.log(lod);
});
It's hard to provide an example on something like jsfiddle where we can't specify resources by file path, but I think the problem is with the module id in your javascript. In your dojoConfig, the location property defines the path to the directory where modules in that package can be located.
If your lod module is located at in /scripts/mylibs/lod.js, then you'd need to require lod/lod:
require(['lod/lod'], function(lod) {
console.log("lod module:", lod);
});
Here's the documentation for dojo config. I would look at the "Loader Configuration" section.
I attempted a jsfiddle anyway, which could be useful: http://jsfiddle.net/tupton/ftN6h/
Note the errors in the console:
'lod':
GET http://fiddle.jshell.net/scripts/mylibs/LOD.js 404 (Not Found)
and 'lod/lod':
GET http://fiddle.jshell.net/scripts/mylibs/lod.js 404 (Not Found)
I'm not familiar with the "main" property of the package config, but it looks like that's what it's using when you try to require an entire package. Maybe try changing that to "lod" so it looks for ".../lod.js"?

Categories