vue: Downloading excel files using node-xlsx - excel

I am very new to programming and working on a web project.
I used node-xlsx make a button that export excel data.
But I got an error "Cannot read properties of undefined (reading 'utils')".
I think not many people are having the same problem.
It will be grateful if someone advice me solutions.
My template only contains a button.
<template>
<v-card class="custm">
<v-btn #click="excelDown">excel</v-btn>
</v-card>
</template>
My Data: See bottom
<script lang="ts">
import Vue from "vue";
import XLSX from 'xlsx';
public incomeLogData = new Array<IncomeLog>();
get IncomeLogList() {
return this.incomeLogData;
}
mounted() {
this.setData();
}
setData() {
// header
this.headers = [
{
text: this.$t("income.item06").toString(),
align: "center",
sortable: false,
value: "userID"
},
{
text: this.$t("income.item07").toString(),
align: "end",
sortable: false,
value: "nickname"
},
{
text: this.$t("income.item08").toString(),
align: "end",
sortable: false,
value: "money"
},
{
text: this.$t("income.item09").toString(),
align: "end",
sortable: false,
value: "exp"
}
];
// Dummy Data
this.incomeLogData = [
{
"userID":"ACEJTH1",
"nickname":"aceth1",
"money":2000,
"exp":8000,
},
{
"userID":"aceSK1",
"nickname":"acesk1",
"money":2000,
"exp":8000,
}
];
// get excel button
excelDown() {
const dataWS = XLSX.utils.json_to_sheet(this.incomeLogData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, dataWS, 'nameData');
XLSX.writeFile(wb, 'example.xlsx');
}
}
</script>
And I attached my dev tool error.
[enter image description here][1]
[1]: https://i.stack.imgur.com/2rEL1.png

I had this trouble with the 0.18.5 version. Uninstall an rollback to version 0.17.3. Everything worked fine!

Related

Why is the Tabulator getRows() function not working?

This seems like the simplest of requests but I can't seem to retrieve a set of rows from a Tabulator object.
Here's the code which instantiates the Tabulator object.........
function TabulatorInvitees(divId, companyName, userEmail) {
try {
var table = new Tabulator(divId, {
columns: [
{
title: "<div style='width:20%; float:left; text-align:left; color:blue; font-size:14px;'>Vendor Invitees</div>",
columns: [
{ title: "Id", field: "Id", visible: false },
{ title: "Added", field: "Added", visible: false },
{ title: "Changed", field: "Changed", visible: false },
{ title: "MarkedForExclusion", field: "MarkedForExclusion", visible: false },
{ title: "Email Address", field: "Email", widthGrow: 1, responsive: 0, hozAlign: "center", editor: "input", visible: true },
{ title: "First Name", field: "FirstName", widthGrow: 0.5, responsive: 1, hozAlign: "center", editor: "input", visible: true },
{ title: "Last Name", field: "LastName", widthGrow: 0.5, responsive: 1, hozAlign: "center", editor: "input", visible: true }
]
},
{
title: tabulatorAddUser(companyName),
field: "ManageRows",
widthGrow: 0.25,
responsive: 2,
hozAlign: "center",
formatter: "tickCross",
headerClick: function (e, row) {
row.getTable().addRow({ Id: 0, Added: true }, false);
},
cellClick: function (e, cell) {
tabulatorFreezeUnfreezeDelete(cell.getRow());
}
},
],
data: [],
height: "100%",
layout: "fitColumns", // required when using 'widthGrow'
placeholder: tabulatorPlaceholder(companyName), //display message to user on empty table
reactiveData: true, //enable reactive data
responsiveLayout: "collapse",
rowContextMenu: tabulatorContextMenu(),
});
table.on("rowTapHold", function (e, row) {
// from Tabulator documentation: "The rowTapHold event is triggered when a user taps on a row on a touch display and holds their finger down for over 1 second."
//e - the tap event object
//row - row component
tabulatorContextMenu();
});
table.on("tableBuilt", function () {
if (companyName.length > 0) {
table.setData(getDataSync({ caseSelector: "VendorMgmt_EmployeeList", companyCode: companyName, userEmail: userEmail }));
}
else {
table.setData([]);
}
});
}
catch (error) {
console.log(error);
}
}
The setData() function makes a call to a database function which returns three rows, similar to the following:
The following JQuery function is called when a radio button is clicked....
$(".vendorStatus").click(function (e) {
const status = e.target.value;
const tbls = Tabulator.findTable("#divVendorEmployees");
const tbl = tbls[0];
const tblRows = tbl.getRows();
console.log("tbls.length", tbls.length);
console.log("tblRows", tblRows);
});
The browser console indicates a table has been found (tbls.length = 1) but the tblRows array is empty:
I see the three rows in my Tabulator but I am not able to recall them programmatically. It seems like a simple problem which should have a simple answer.
I am using the most recent version of Tabulator (v5.4).
Any assistance is greatly appreciated.
After much searching, I finally came to the realization the DOM element associated with the Tabulator instance must be managed when attempting to refresh or replace data. I've implemented a method which allows me to delete and rebuild the DOM element each time I need to save data to my database and subsequently refresh my Tabulator instance.
Here's the code...
function refreshTabulatorObject(obj) {
let parentId = obj.parentId;
let childId = obj.childId;
//Empty and remove the current version of the [Tabulator] object.
const tables = Tabulator.findTable(childId);
if (tables.length > 0) {
var table = Tabulator.findTable(childId)[0];
table.setData([]);
}
//Remove the existing <div> from the DOM.
$(childId).remove();
//Re-create the <div> element for the [Tabulator] object and append it to the DOM.
var parentDiv = document.getElementById(parentId);
parentDiv.innerHTML = "";
var childDiv = document.createElement("div");
childDiv.setAttribute("id", childId);
parentDiv.appendChild(childDiv);
//Re-create the [Tabulator] object.
TabulatorInvitees("#" + childId, obj.companyName);
}
I'm sure those of you with a more intimate knowledge of Tabulator would likely suggest a more elegant method, however, this one appears to work and I've already spent far more time on this issue that I had anticipated. Unfortunately, elegance is not a luxury I can afford at this point.
I hope this solution might be of help to some other struggling soul.

(this.internalValue || []).findIndex is not a function when enabling multiple selection on v-select

I am using Vue.js with Vuetify.
Following is my minimal reproducible example:
<template>
<v-app>
<v-select v-model="site" :items="sites" item-value="_id" item-text="name"></v-select>
<v-btn #click="showSelections">Show Selections</v-btn>
</v-app>
</template>
<script>
export default {
name: 'App',
data: () => ({
site: [],
sites: [
{
name: 'Vancouver',
_id: '5d9c276784e00100699281e2',
},
{
name: 'LA',
_id: '5d9c276784e00100699281e5',
},
{
name: 'Montreal',
_id: '5d9c276784e00100699281e3',
},
],
}),
methods: {
showSelections: function() {
console.log(this.site);
}
}
};
</script>
This example works perfect until you want to enable multiple selection on the v-select component.
<v-select v-model="site" :items="sites" multiple item-value="_id" item-text="name"></v-select>
As soon as you click the combobox, you'd get this:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in v-on handler: "TypeError: (this.internalValue || []).findIndex is not a function"
found in
---> <VSelectList>
<VThemeProvider>
<VMenu>
<VSelect>
<VMain>
<VApp>
<App> at src/App.vue
<Root>
TypeError: (this.internalValue || []).findIndex is not a function
at VueComponent.findExistingIndex (VSelect.ts?1576:338)
at VueComponent.selectItem (VSelect.ts?1576:816)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at VueComponent.invoker (vue.runtime.esm.js?2b0e:2179)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at VueComponent.Vue.$emit (vue.runtime.esm.js?2b0e:3888)
at click (VSelectList.ts?7bd1:169)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at VueComponent.invoker (vue.runtime.esm.js?2b0e:2179)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
This seems to be an issue caused by Vue CLI 4.5.11 transpiling Vuetify. If you remove vuetify from transpileDependencies, your example works properly:
// vue.config.js
module.exports = {
// transpileDependencies: [
// 'vuetify'
// ]
}
Interestingly, this isn't a problem at all (no config changes needed) with Vue CLI 5.0.0-alpha.4, so consider upgrading.
I had the same problem. I leave you here as I have it in case it works for you:
<!-- VueJS Template -->
<v-select :items="arrayItems" v-model="arrayItemsSelected" label="Items" item-text="text" outlined multiple chips attach dark></v-select>
// VueJS Data
export default {
data: () => ({
arrayItemsSelected: [],
arrayItems: [
{ value: "Item1", text: "Item1" },
{ value: "Item2", text: "Item2" },
{ value: "Item3", text: "Item3" },
{ value: "Item4", text: "Item4" },
{ value: "Item5", text: "Item5" },
],
}),
}
I had the same issue when I was toggling the multiple property of the v-select. See the reproduction link: https://codepen.io/kkojot/pen/MWOpYqZ
To avoid this error you have to clear the property bound to v-model and change it empty object {} or empty array [] accordingly.
computed: {
isMultiple() {
//comment the if statment below to see the 'TypeError: (this.internalValue || []).findIndex is not a function'
if (this.multiple) this.site = [];
else this.site = {};
return this.multiple;
},
},

How to create a custom button in Jodit to wrap the text in a code tag?

Basically I want to be able to generate html like <code>{a: true}</code>
As far as I can tell, the button should do the same thing as the "underline" button for example, except it will wrap the text in <code> instead of <u>;
I have tried using this:
{
buttons:
'bold,strikethrough,underline,italic,eraser,|,superscript,subscript,|,ul,ol,align,|,outdent,indent,|,font,fontsize,brush,paragraph,|,image,video,table,link,|,undo,redo,\n,selectall,cut,copy,paste,copyformat,|,hr,symbol,source,fullsize,print,code',
language: lang,
placeholder,
toolbarAdaptive: false,
uploader: {
insertImageAsBase64URI: true,
},
controls: {
code: {
name: 'code',
iconURL: 'someurl.com',
tagRegExp: '_PxEgEr_/^(code)$/i',
tags: ['code'],
tooltip: 'Code',
},
},
}
The button shows up in the toolbar, but nothing happens when I click it. The documentation shows buttons that insert text, but I need a button that wraps text instead.
Ok I figured it after going through their code, it's not well documented, but this is how you do it:
{
buttons: 'blockquote,code',
controls: {
code: {
name: 'code',
iconURL: 'someiconurl.com',
tooltip: 'Insert Code Block',
exec: function (editor) {
editor.execCommand('formatBlock', false, 'code');
},
isActive: (editor, control) => {
const current = editor.s.current();
return Boolean(
current && Jodit.modules.Dom.closest(current, 'code', editor.editor)
);
},
},
blockquote: {
name: 'blockquote',
iconURL: 'someiconurl.com',
tooltip: 'Insert blockqoute',
exec: function (editor) {
editor.execCommand('formatBlock', false, 'blockquote');
},
isActive: (editor, control) => {
const current = editor.s.current();
return Boolean(
current && Jodit.modules.Dom.closest(current, 'blockquote', editor.editor)
);
},
},
},
}

jTable dynamic custom toolbar item in child table

I have a jTable with a child table for each row. On the toolbar header of the child table I have added a custom toolbar item. I want to make that toolbar item dynamic in the sense that if there are already some rows I do not want it to show. I came across a very similar query for the main toolbar "add new" button which added a function to run on recordsLoaded:
Below is my first attempt - it is just the field entry for the main table that specifies the child table. However the ".find(....)" spec will not work in my case as mine is a custom toolbar item. What do I need to put as the .find criteria?
Thanks
Dance: {
title: '',
width: '4%',
sorting: false,
create: false,
listClass: 'centreCol',
display: function(book) {
var $img = $('<img src="Images/layers.png" title="Show associated dance entries" />');
//Open child table when user clicks the image
$img.click(function() {
var thisrow = $img.closest('tr'); //Parent row
if($('#BookTableContainer').jtable('isChildRowOpen',thisrow)) { // Clicking image a second time closes the child row
$('#BookTableContainer').jtable('closeChildRow',thisrow);
} else {
currentTitleID = book.record.DanceTitleID;
$('#BookTableContainer').jtable(
'openChildTable',
thisrow,
{
title: 'Related Dance',
toolbar: {
items: [
{
icon: 'Images/add.png',
text: 'New dance',
tooltip: 'Add dance details',
click: function() { CreateDanceDialog(); }
}
]
},
actions: {
listAction: 'BookPageData.php?action=listChildDances&DanceTitleID=' + currentTitleID,
// createAction: 'dancesData.php?action=createAssignment',
// deleteAction: 'dancesData.php?action=deleteAssignment'
},
recordsLoaded: function(event, data) {
var rowCount = data.records.length;
if (rowCount>0){
$('#BookTableContainer').find('.jtable-toolbar-item.jtable-toolbar-item-add-record').remove();
}
},
fields: {
DanceID: { key: true, create: false, edit: false, list: false, visibility: 'hidden' },
DanceTitleID: { type: 'hidden', defaultValue: currentTitleID },
ChoreographerID: { title: 'Choreographer', width: '40%', options: function() { return ChoreographerOptions; } },
FormationID: { title: 'Formation', width: '30%', options: function() { return FormationOptions; } },
GenreID: { title: 'Genre', width: '30%', options: function() { return GenreOptions; } }
}
},
function(data) { data.childTable.jtable('load'); }
);
}
});
//Return image to show on the person row
return $img;
}
},
Try this
$('#BookTableContainer').find('.jtable-toolbar').remove();

Using image and carousel on the same panel in sencha touch

I am new in sencha touch and need to achieve this layout on a single simple page:
I need an image and below the image, there should be a carousel containing two another images which the user can swipe.
Here is my code:
Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function() {
// Create a Carousel of Items
var carousel1 = new Ext.Carousel({
defaults: {
cls: 'card'
},
items: [{
html: "<img src='teil1.jpg' width='320' height='60' alt='' border='0'>"
},
{
html: "<img src='teil2.jpg' width='320' height='60' alt='' border='0'>"
}
]
});
var panel = new Ext.Panel({
fullscreen: true,
html: "<img src='sport1_top.jpg' width='320' height='302'>"
});
new Ext.Panel({
fullscreen: true,
layout: {
type: 'vbox',
align: 'stretch'
},
defaults: {
flex: 1
},
items: [panel, carousel1]
});
}
});
The carousel and the panel containing the first image are displayed on the same portion of the page.
Am I missing something?
Thanks for your interest.
leon.
Removing the
fullscreen: true
from the sport1_top panel worked for me
Mark
This problem was nagging me too. After trying everything I could think of, what appears to help was to get rid of all of those fullscreen properties except on the main Ext.Panel, and use "layout:'fit'" on all of the cards, which I added to my defaults in the Ext.Carousel object.
var toolbar = new Ext.Toolbar({ title: 'testing', dock: 'top'});
var around = new Ext.Carousel({
ui: 'dark',
direction: 'horizontal',
defaults: { cls: 'card', layout:'fit' },
items: [
{ html: 'card 1'},
{ html: 'card 2'},
{ html: 'card 3'},
{ html: 'card 4'},
]
})
var panel = new Ext.Panel({
fullscreen: true,
layout: {
type : 'fit',
align: 'top'
},
defaults: {
flex: 1
},
items: [ around ],
dockedItems: [ toolbar ]
});
panel.show();
I believe you have to use layout: 'fit' for your Carousel (In your Panel, instead of vbox). Or you could make another panel SubPanel that has your vbox and that SUbPanel({layout: 'fit'});
I came across the same problem, I believe this works.
GL

Resources