jsPDF Error: autoTable is not a function in SAP UI5 - javascript

I am using the jsPDF library for converting a table into a PDF file.
The current code that I have used is giving off an error, that autoTable is not a function.
Here is the code.
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel",
"sap/ui/core/util/Export",
"sap/ui/core/util/ExportTypeCSV"
],
function (Controller, JSONModel, Export, ExportTypeCSV) {
"use strict";
return Controller.extend("c.g.modalproject1.controller.Root", {
onInit: function () {
var oModel1 = new JSONModel("./model/vegetableDataJSON.json");
this.getView().setModel(oModel1, "veg");
console.log("data : ", oModel1);
},
openDialog1: function () {
if (!this.pdialog1) {
this.pdialog1 = this.loadFragment({
name: "c.g.modalproject1.fragments.mTables"
});
}
this.pdialog1.then(function (oDialog) {
oDialog.open();
})
new sap.m.MessageToast.show("Table Loaded");
},
closeDialog: function () {
this.byId("newDialog1").close();
sap.m.MessageToast.show("Table closed ! ");
// var vegTable = this.getView().byId("vegiesMTable");
// vegTable.setGrowing(false);
// vegTable.setGrowingScrollToLoad(false);
},
downloadCSV: function () {
// Show a toast message to indicate that the file is downloading
sap.m.MessageToast.show("Downloading Excel..");
// Create a new Export object with the specified export type and options
var oExport = new Export({
exportType: new ExportTypeCSV({
separatorChar: ","
}),
models: this.getView().getModel("veg"),
rows: {
path: "/vegetablesRootNode"
},
columns: [{
name: "Title",
template: {
content: "{title}"
}
},
{
name: "Type",
template: {
content: "{type}"
}
},
{
name: "Description",
template: {
content: "{description}"
}
},
{
name: "Price",
template: {
content: "{price}"
}
},
{
name: "Rating",
template: {
content: "{rating}"
}
}]
});
// Save the file and handle any errors that may occur
oExport.saveFile().catch(function (oError) {
sap.m.MessageToast.show("Error when downloading data. Browser might not be supported!\n\n" + oError);
}).then(function () {
// Destroy the export object
oExport.destroy();
});
},
downloadPDF:function()
{
sap.m.MessageToast.show("Downloading into PDF started !");
var oModel2 = this.getView().getModel("veg");
console.log("check data = ", oModel2);
var oColumns = ["Title","Type","Description","Price","Rating"];
var oRows = [];
oRows = oModel2.oData.vegetablesRootNode;
console.log(oColumns);
console.log(oRows);
//var pdfDoc = new jsPDF('p', 'pt', 'letter');
var pdfDoc = new jsPDF();
pdfDoc.text(20, 20, "Vegetables Table");
pdfDoc.autoTable(oRows, oColumns);
pdfDoc.save("test.pdf");
//pdfDoc.output("save","t.pdf");
}
});
});
The last function is the code that runs to save the table data into PDF.
Can you please help.
These are the files that are included in my project folder.
Manifest.json
Adding just text, and most of the functionality that is available (via methods) from jsPDF works fine. I have created PDFs with just text from this app as well.
It works fine for adding text and downloads fine. But for Table data, it doesnt work.
I tried various ways but didn't get to solve it at all.

I tried to make a POC with this library and it works :-)
Configure the framework so that it can load the libraries
sap.ui.loader.config({
// activate real async loading and module definitions
async: true,
// load thirparty from cdn
paths: {
"thirdparty/jsPDF": "https://unpkg.com/jspdf#2.5.1/dist/jspdf.umd.min",
"thirdparty/jsPDFautoTable": "https://unpkg.com/jspdf-autotable#3.5.28/dist/jspdf.plugin.autotable"
},
// provide dependency and export metadata for non-UI5 modules
shim: {
"thirdparty/jsPDF": {
amd: true,
exports: "jspdf"
},
"thirdparty/jsPDFautoTable": {
amd: true,
exports: "jspdf",
deps: ["thirdparty/jsPDF"]
}
}
});
You can put that code on top on your Component.js file
Idea is to configure the framework to load libraries from CDN as AMD module with dependencies.
It's a bit tricky in your case and I'm not sure I understand the mechanism; what I imagine is that autoTable is a jsPDF plugin so we need jsPDF (dependency); the plugin overload jsPDF and returns jsPDF object
For sap.ui.loader here the official doc. :
https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.loader/methods/sap.ui.loader.config
Loads and consumes libraries
sap.ui.require(["thirdparty/jsPDFautoTable"], (jsPDFautoTable) => {
var doc = new jsPDFautoTable.jsPDF();
doc.autoTable({ html: '#my-table' });
doc.save('table.pdf');
});
Either with sap.ui.define or sap.ui.require to load the library on the fly when needed

Related

JHipster Blueprint - Generate files with a specific path using templates | Get default java package name

EDIT : the former question was "JHipster Blueprint - How to get default Java package name ?"
I am developing a blueprint with JHipster that overrides the entity-server sub-generator. The desired behaviour is to replace all files in /src/main/java/defaultpackageName/domain/ from the project generated by the blueprint with my generated files. This is my code (files.js):
const entityServerFiles = {
noHibernate: [
//domain files
{
path: 'src/main/java/XXX/domain/',
templates: [
{
file: 'Entity.java',
renameTo: generator => `${generator.persistClass}.java`
}
]
}
]
};
function writeFiles() {
return {
write() {
this.writeFilesToDisk(entityServerFiles, this, false);
}
}
}
module.exports = {
writeFiles
};
For now it just creates a folder XXX in /src/main/java/ with my generated files in it.
What would I need to write in the XXX in path: 'src/main/java/XXX/domain/' in order to generate the files at the right place?
I did some digging on github on the generator-jhipster project and the prompt asking the user for the default java package name is in /generator-jhipster/generators/java/index.cjs/. This is the whole code https://github.com/jhipster/generator-jhipster/blob/main/generators/java/index.cjs
But I just took the important part:
const {
PACKAGE_NAME,
PACKAGE_NAME_DEFAULT_VALUE,
PRETTIER_JAVA_INDENT,
PRETTIER_JAVA_INDENT_DEFAULT_VALUE,
BUILD_TOOL,
BUILD_TOOL_DEFAULT_VALUE,
BUILD_TOOL_PROMPT_CHOICES,
} = require('./constants.cjs');
get prompting() {
return {
async showPrompts() {
if (this.shouldSkipPrompts()) return;
await this.prompt(
[
{
name: PACKAGE_NAME,
type: 'input',
validate: input => this.validatePackageName(input),
message: 'What is your default Java package name?',
default: () => this.sharedData.getConfigDefaultValue(PACKAGE_NAME, PACKAGE_NAME_DEFAULT_VALUE),
},
],
this.config
);
},
};
}
From what I understand, I just need to access the PACKAGE_NAME constant from my blueprint and it should work. Any ideas?
I just found the solution...
const entityServerFiles = {
noHibernate: [
//domain files
{
path: 'src/main/java/',
templates: [
{
file: 'package/domain/Entity.java',
renameTo: generator => `${generator.entityAbsoluteFolder}/domain/${generator.persistClass}.java`
}
]
}
]
};
function writeFiles() {
return {
write() {
this.writeFilesToDisk(entityServerFiles, this, false);
}
}
}
module.exports = {
writeFiles
};
The path property specifies the path inside the templates folder. Meanwhile, you can specify the path you want your files to be generated inside the project in the renameTo property.
So the answer to my question is ${generator.entityAbsoluteFolder} which had nothing to do with my original hypothesis, but this question can also be useful for writing templates in general.

static import works from nuxt.config.js but not from component

I have a vanilla js jsencrypt package which i needed to use in my nuxt application, the package itself works fine when imported from Nuxt.config.js but i run into issues when imported using the head object from component, let me show you my code
nuxt.config.js //this works
head: {
title: 'App',
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
],
script: [
{
src: "/js/jsencrypt.min.js",
body: true
}
],
},
component call //this doesnt work
export default {
head() {
return {
script: [
{
src: "/js/jsencrypt.min.js",
body: true
}
],
}
},
}
i am using the head tag which in theory should work but it doesn't
mounted() function
mounted(){
var encrypt = new JSEncrypt();
}
I get an error back
JSEncrypt is not defined
since this class is going to be used in encrypting only one component , registering it globally doesnt seem like a smart move, does anyone know what the problem is?
Pulling in JSEnquiry in your head tag will work just fine, but you need to allow time for it to download and parse. Calling it in the mounted hook doesn’t allow for that.
Try this in your mounted hook.
const onAvailable = (variable, callback) => {
function checkVariableIsAvailable(variable, callback) {
if (typeof window[`${variable}`] === 'undefined') {
setTimeout(function() {
checkVariableIsAvailable(variable, callback)
}, 1)
} else {
callback()
}
}
checkVariableIsAvailable(variable, callback)
}
onAvailable('JSEncrypt', () => {
var encrypt = new JSEncrypt();
}

autoComplete.js - how to resolve autoComplete is not defined

I want to use autocomplete.js in my application.
I have installed the package using yarn add #tarekraafat/autocomplete.js. I am using webpack 4.28 to bundle the javascript files and have require("#tarekraafat/autocomplete.js/dist/js/autoComplete"); to import the package into the application and placed the bundled file at the bottom before the closing BODY tag.
In my custom.js file, I am creating a new instance of autoComplete as follows:
new autoComplete({
data: {
src: async () => {
document.querySelector("#autoComplete_results_list").style.display = "none";
document.querySelector("#autoComplete").setAttribute("placeholder", "Loading...");
const source = await fetch("/employee/search");
const data = await source.json();
return data;
},
key: "name"
},
selector: "#autoComplete",
placeHolder: "type employee name to search...",
threshold: 0,
searchEngine: "strict",
highlight: true,
dataAttribute: { tag: "value", value: "" },
maxResults: Infinity,
renderResults: {
destination: document.querySelector("#autoComplete"),
position: "afterend"
},
onSelection: feedback => {
document.querySelector(".selection").innerHTML = feedback.selection.food;
document
.querySelector("#autoComplete")
.setAttribute("placeholder", `${event.target.closest(".autoComplete_result").id}`);
console.log(feedback);
}
});
However, on running the application, I am getting an error Uncaught ReferenceError: autoComplete is not defined with a reference to the location where I am creating the new instance.
I have read the getting started documentation and looked at the demo code and I can't figure out what I am missing. How do I resolve the error?
Your problem is in your import, you are not import the autoComplete correctly, so when you using the new autoComplete you are having error.
Change the require("#tarekraafat/autocomplete.js/dist/js/autoComplete"); to import autoComplete from '#tarekraafat/autocomplete.js';, put this on top of your file, right after jquery or something
Write your code inside
$(document).ready(function(){
// Write your Code Here
});

Add new Uploader to Ckeditor5

How is this possible add new uploader functionality to ckeditor5 like upload audio or video?
I tried for using ckeditor5 doc but it is not clear at all.
I using this vue file for using ckeditor5. in this file, I use a customized uploadadapter for my project, but now I don't know how i can upload another type of file like audio and video in this attitude
<script>
import ClassicEditor from '#ckeditor/ckeditor5-build-classic/build/ckeditor';
import MyUploadAdapter from '../adapter/UploadAdapter';
export default {
data() {
return {
instance: null,
article: {
data: '',
},
}
},
mounted() {
this.initialize();
},
methods: {
// Initializing Editor
initialize: function () {
ClassicEditor
.create(document.querySelector("#editor"), this.config)
.then(editor => {
// get initial instance object of editor
this.instance = editor;
// set initial binder of editor on start
editor.model.document.on('change', () => {
this.valueBinder(editor.getData())
});
editor.plugins.get('FileDialogButtonView')
// This place loads the adapter.
editor.plugins.get('FileRepository').createUploadAdapter = (loader, article) => {
return new MyUploadAdapter(loader, this.article);
}
})
.catch(error => {
console.error(error);
});
},
}
},
}
</script>
For Upload file you can use CKFinder.
For the configuration of CKfinder, Please refer this link.
ClassicEditor
.create( editorElement, {
ckfinder: {
uploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files&responseType=json' // here you can set your own file path
}
} )
.then( ... )
.catch( ... );

page object: visit <page_url> in nightwatch.js

In Geb and WATIR there are certain keywords which we use to visit to the page_url which we have specified in page class. E.g. to keyword in Geb and visit keyword in WATIR.
What similar we can use in nightwatch.js. This is what I have tried but it gives error:
I have tried:
module.exports = {
url: function () {
return this.api.globals.launchUrl + "/goto/desiredPage.html";
},
commands: [pageCommands],
elements: {}
};
In page class I am using it as:
desiredPage
.url()
.foo()
.bar();
client.end();
but it is giving error .url is not a function.
You can see the nightwatch examples inside the nightwatch folder for example:
[page-objects/home.js]
var searchCommands = {
submit: function() {
this.waitForElementVisible('#submitButton', 3000)
.click('#submitButton')
.api.pause(1000);
return this; // Return page object for chaining
}
};
module.exports = {
url: 'http://google.com',
commands: [searchCommands],
elements: {
searchBar: { selector: 'input[name=q]' },
submitButton: { selector: 'button[type=submit]' }
}
};
and then in the test:
/* jshint expr: true */
module.exports = {
'Demo Google search test using page objects' : function (client) {
var homePage = client.page.home();
homePage.navigate();
homePage.expect.element('#searchBar').to.be.enabled;
homePage
.setValue('#searchBar', 'Nightwatch.js')
.submit();
var resultsPage = client.page.searchResults();
resultsPage.expect.element('#results').to.be.present.after(2000);
resultsPage.expect.element('#results').to.contain.text('Nightwatch.js');
resultsPage.expect.section('#menu').to.be.visible;
var menuSection = resultsPage.section.menu;
menuSection.expect.element('#web').to.be.visible;
menuSection.expect.element('#video').to.be.visible;
menuSection.expect.element('#images').to.be.visible;
menuSection.expect.element('#shopping').to.be.visible;
menuSection.productIsSelected('#web', function(result) {
this.assert.ok(result, 'Web results are shown by default on search results page');
});
client.end();
}
};
so "url()" command in pages does not exist you need to define the url in te page and the use "navigate()" instead.

Categories