using vue-chartjs in vue 3 : createElement is not a function - vue.js

I'm using Vue.js 3 and I can't make a chart with Vue-chartjs because of this error:
Uncaught TypeError: createElement is not a function
at Proxy.render (BaseCharts.js?86fc:8)
at renderComponentRoot (runtime-core.esm-bundler.js?5c40:673)
at componentEffect (runtime-core.esm-bundler.js?5c40:4475)
at reactiveEffect (reactivity.esm-bundler.js?a1e9:42)
at effect (reactivity.esm-bundler.js?a1e9:17)
at setupRenderEffect (runtime-core.esm-bundler.js?5c40:4458)
at mountComponent (runtime-core.esm-bundler.js?5c40:4416)
at processComponent (runtime-core.esm-bundler.js?5c40:4376)
at patch (runtime-core.esm-bundler.js?5c40:3991)
at mountChildren (runtime-core.esm-bundler.js?5c40:4180)
this is App.vue that displays my chart:
<template>
<line-chart />
</template>
<script>
import LineChart from "./components/Chart";
export default {
name: "App",
components: {
LineChart
}
};
</script>
and this is Chart.vue that renders a line chart :
<script>
import { Line } from "vue-chartjs";
export default {
extends: Line,
data: () => ({
chartdata: {
labels: ["January", "February"],
datasets: [
{
label: "Data One",
backgroundColor: "#f87979",
data: [40, 20]
}
]
},
options: {
responsive: true,
maintainAspectRatio: false
}
}),
mounted() {
this.renderChart(this.chartdata, this.options);
}
};
</script>
I have tried this with various forms of data, but apparently, the problem is elsewhere.
Do I have to wait for the vue.js 3 ecosystem to become more complete?

Update 2022
The library supports vue 3 now and you can install as follows :
pnpm add vue-chartjs chart.js
# or
yarn add vue-chartjs chart.js
# or
npm i vue-chartjs chart.js
Old answer
According to this issue this library doesn't support Vue 3 yet, and the origin of this error could explained here :
in vue 2 we do the following to create a render function :
export default {
render(createElement ) { // createElement could be written h
return createElement('div')
}
}
in Vue 3 :
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
which means that createElement is undefined

https://github.com/apertureless/vue-chartjs
Vue Charts does not seem to be ready for vue3
Compatibility
v1 later #legacy
Vue.js 1.x
v2 later
Vue.js 2.x
Discussion about vue3 here: https://github.com/apertureless/vue-chartjs/issues/601
and here: https://github.com/apertureless/vue-chartjs/issues/637

Related

vite 2 production env ref element is undefined with compostion api

I use vue3 with composition api, but when I build my project, the ref element always undefined.
I reproduced it, maybe I used it incorrectly, but I don't know why.
I defined a ref in hooks function.
const isShow = ref(false)
const rootRef = ref<HTMLDivElement>();
export default function () {
function changeShow() {
isShow.value = !isShow.value;
console.log(isShow.value, rootRef.value);
}
return { isShow, rootRef, changeShow };
}
Use rootRef in the HelloWorld.vue and linked element.
<script setup lang="ts">
import useShow from "../composables/useShow";
const { rootRef, isShow } = useShow();
</script>
<template>
<div ref="rootRef" v-show="isShow" class="test"></div>
</template>
Create a button in App.vue and bind click function.
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
import useShow from "./composables/useShow";
const { changeShow } = useShow();
</script>
<template>
<button #click="changeShow">切换</button>
<HelloWorld />
</template>
When I click button, it works.
But when I build it and import from lib, it doesn't work.
My vite.config.ts is as follows:
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"#": path.resolve(__dirname, "src")
}
},
build: {
cssCodeSplit: true,
sourcemap: true,
lib: {
entry: path.resolve(__dirname, "src/index.ts"),
name: "my-project",
fileName: format => `my-project.${format}.js`
},
rollupOptions: {
external: ["vue"],
preserveEntrySignatures: "strict",
output: {
globals: {
vue: "Vue"
}
}
}
}
});
I think the problem is the definition of rootRef. It seems that only binding location can use it. This is no different from defining it in a component. I need to use it in multiple places.
Oddly, in this way, the Dev environment works fine, but Pro env is not available. Do I need to modify the build configuration of vite.
How do I do that?
The problem is your App.vue uses its own copy of composables/useShow instead of the one from the lib.
The solution is to export the composable from the lib so that your app can use the same one:
// src/index.ts
import { default as useShow } from './composables/useShow';
//...
export default {
//...
useShow
};
In App.vue, use the lib's composable:
import MyProject from "../dist/my-project.es";
const { changeShow } = MyProject.useShow();
GitHub PR

Unknown custom element: <FullCalendar> - FullCalendar Vue

I'm trying to create a vue component that utilizes the FullCalendar vue component:
<script>
import FullCalendar from '#fullcalendar/core'
import interactionPlugin from '#fullcalendar/interaction'
import dayGridPlugin from '#fullcalendar/daygrid'
export default {
components: {
FullCalendar
},
data: function() {
return {
calendarOptions: {
plugins: [ dayGridPlugin, interactionPlugin ],
initialView: 'dayGridMonth',
events: '/schedule/month_events',
eventOrder: "building_id",
selectable: true,
defaultAllDay: true,
editable: true,
dateClick: this.handleDateClick,
headerToolbar: {
left: '',
center: 'title',
right: 'prev today next'
}
}
}
},
methods: {
handleDateClick: function(arg) {
console.log('test');
}
}
}
</script>
<template>
<FullCalendar :config="calendarOptions" />
</template>
<style scoped>
</style>
and I get the following error:
[Vue warn]: Unknown custom element: <FullCalendar> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
If I create my own component, it displays the template and finds the component just fine.
How do I properly use FullCalendar component in my Vue JS component?
Since you are using Vue component, you need to import from #fullcalendar/vue. You are currently importing from #fullcalendar/core.

How to use annotorious in vue.js template

I want to use annotorious (with openseadragon plugin) in a vue.js (vue 3) template.
I've installed annotorious with npm.
This is what i've got so far:
<template>
<div class="flex-grow">
<img ref="tag_img" width="100%" :id="img_id" src='../../assets/images/apple.png'>
</div>
</template>
<script>
import * as Annotorious from '#recogito/annotorious-openseadragon'
import '#recogito/annotorious-openseadragon/dist/annotorious.min.css'
export default {
props: {
img_id: String
},
mounted: function () {
var anno = Annotorious({
image: this.$refs.tag_img
}, {})
anno.setDrawingTool('polygon')
}
}
</script>
I recieve the following error in my browser:
[Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'style' of undefined"
found in
---> <AnnotoriousImage> at src/components/interaction/AnnotoriousImage.vue
<Tagging> at src/components/pages/Tagging.vue
<App> at src/App.vue
<Root>
warn # vue.esm.js?efeb:628
logError # vue.esm.js?efeb:1893
...
vue.esm.js?efeb:1897 TypeError: Cannot read property 'style' of undefined
You are mixing up the standard version of Annotorious (for images) and the OpenSeadragon plugin (for high-res images, displayed in the OpenSeadragon viewer) I believe.
What you are importing is the OpenSeadragon version. But the way you are initializing is the one you'd use for the standard version of Annotorious.
Assuming you want to annotate a normal image: the init is correct. But you'd need to
import * as Annotorious from '#recogito/annotorious'
The answer of Rainer brought me to a working version. It is possible to init it in the mount function of annotorious.
import OpenSeadragon from 'openseadragon'
import * as Annotorious from '#recogito/annotorious-openseadragon'
import '#recogito/annotorious-openseadragon/dist/annotorious.min.css'
export default {
props: {
img_url: String,
default: '../../../assets/images/apple.png'
},
mounted: function () {
const viewer = OpenSeadragon({
id: 'annotorious_container',
minZoomImageRatio: 0,
maxZoomPixelRatio: Infinity,
tileSources: {
type: 'image',
url: require('../../../assets/images/apple.png'),
ajaxWithCredentials: false,
fitBounds: true
}
})
var options = {
disableEditor: true // the default editor is disabled to implement a custom behaviour
}
var anno = Annotorious(viewer, options)
anno.setDrawingTool('polygon')
window.viewer = viewer
window.anno = anno
},
components: {
'Icon': Icon,
'AnnotoriusEditorPopup': AnnotoriusEditorPopup
}
}

Vuetify Storybook remapInternalIcon issue

Using Vuetify 2 and Storybook 6 (source https://github.com/lydonchandra/vuetify2storybook6 )
The component renders fine, but keep getting this error TypeError because vm.$vuetify.icons is undefined, when rendering component for first time.
Not sure which storybook-vuetify initialization bridge did I miss ?
TypeError: Cannot read property 'component' of undefined
at remapInternalIcon (vuetify.js:44048)
at VueComponent.getIcon (vuetify.js:16881)
at Proxy.render (vuetify.js:17009)
at VueComponent.Vue._render (vue.esm.js:3557)
at VueComponent.updateComponent (vue.esm.js:4075)
at Watcher.get (vue.esm.js:4488)
at new Watcher (vue.esm.js:4477)
function remapInternalIcon(vm, iconName) {
// Look for custom component in the configuration
var component = vm.$vuetify.icons.component; // <-- issue here when rendering for first time
if (iconName.startsWith('$')) {
// Get the target icon name
src/plugins/vuetify.ts
import Vue from "vue";
import Vuetify from "vuetify/lib";
import { UserVuetifyPreset } from "vuetify";
Vue.use(Vuetify);
export const options: UserVuetifyPreset = {
icons: {
iconfont: "mdiSvg"
}
};
export default new Vuetify(options);
Workaround for now is to set addon-essentials.docs to false. (Ref.
https://github.com/storybookjs/storybook/issues/7593)
file: .storybook/main.js
...
"addons": [
"#storybook/addon-links",
{
name: "#storybook/addon-essentials",
options: {
docs: false
}
}
],
...
If you don't want to disable addon-essentials.docs, you can add the following style in .storybook/preview-head.html
<style>
.sb-errordisplay {
display: none !important;
}
</style>
Another workaround without having to disable addon-essentials or adding any styles in the preview-head.html file you can import Vuetify at the top of your .stories.js (or .stories.ts) file like so e.g.
import vuetify from '#/plugins/vuetify'
then when you declare your storybook Template, pass in your vuetify object
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { YourComponent },
vuetify, // <-- Very important line
template: `<YourComponent />`
})
I found this workaround in this thread Cannot read property 'mobile' of undefined - Vue/Vuetify/Storybook

Gridsome Full Calendar build error - no SSR

I'm trying to use the Full Calendar vue component (https://github.com/fullcalendar/fullcalendar-vue) in a Gridsome project like so:
<template>
<div class="tabStaffManage">
<div>
<FullCalendar
ref="staffCalendar"
class="fullCalendar"
defaultView="dayGridMonth"
:events="calendarEvents"
:plugins="calendarPlugins"
:allDaySlot="false"
:header="{
center: 'dayGridMonth, timeGridDay',
right: 'prev, next'
}"
minTime="09:00:00"
:selectable="true"
maxTime="18:30:00"
#eventClick="onEventClick"
#select="onDateSelect"
:showNonCurrentDates="false"
></FullCalendar>
</div>
</div>
</template>
<script>
import { formatDate } from "#fullcalendar/core"
import FullCalendar from "#fullcalendar/vue"
import timeGridPlugin from "#fullcalendar/timegrid"
import dayGridPlugin from "#fullcalendar/daygrid"
import interactionPlugin from "#fullcalendar/interaction"
export default {
components: {
FullCalendar,
},
data() {
return {
calendarPlugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
}
},
}
</script>
This, however, produces an error on build:
Could not generate HTML for "/staff/dashboard/":
ReferenceError: Element is not defined
at Object.338 (node_modules/#fullcalendar/core/main.esm.js:102:0)
at __webpack_require__ (webpack/bootstrap:25:0)
at Module.552 (assets/js/page--src-pages-staff-dashboard-vue.ea5234e7.js:598:16)
at __webpack_require__ (webpack/bootstrap:25:0)
I understand that Full Calendar does not support SSR. So as per the Gridsome documentation (https://gridsome.org/docs/assets-scripts/#without-ssr-support) I did this to import the component:
I created an alias for it's dependencies in gridsome.config.js like so:
var path = require('path');
api.configureWebpack({
resolve: {
alias: {
"timeGridPlugin": path.resolve('node_modules', '#fullcalendar/timegrid'),
etc....
}
},
})
and required those plugins in the mounted() lifecycle hook:
mounted() {
if (!process.isClient) return
let timeGridPlugin = require('timeGridPlugin')
...
},
components: {
FullCalendar: () =>
import ('#fullcalendar/vue')
.then(m => m.FullCalendar)
.catch(),
}
I then wrapped the FullCalendar component in:
<ClientOnly>
<FullCalendar></FullCalendar>
</ClientOnly>
The extra dependencies required in the mounted() hook are included no problem.
However I now get the following error:
TypeError: Cannot read property '__esModule' of undefined
It seems that components() is failing to import the '#fullcalendar/vue' component.
Am I doing something wrong when importing the '#fullcalendar/vue' component?
Is there another way to include both the '#fullcalendar/vue' component and the plugin dependencies with no SSR?
Requiring the full calendar vue component in main.js by checking the gridsome client API and registering the component globally in vue seems to work and does what I expected:
// Include no SSR
if (process.isClient) {
const FullCalendar = require("#fullcalendar/vue").default
Vue.component("full-calendar", FullCalendar)
}
I also was not pointing to the default object when requiring the other modules in the component:
mounted() {
if (!process.isClient) return
let timeGridPlugin = require('timeGridPlugin').default
...
}