"TypeError: __WEBPACK_IMPORTED_MODULE_1_jsplumb___default.a.draggable is not a function" - vue.js

I'm trying to do drag and drop using JsPlumb in vueJS. I used JsPlumb link and also imported jsplumb but it is not working. I'm getting error as
[Vue warn]: Error in created hook: "TypeError:
__WEBPACK_IMPORTED_MODULE_1_jsplumb___default.a.draggable is not a function"
This code is written inside the template
<div class="center_block">
<ul id="menu">
<li><img class="decision" src="../assets/images/symbol_decision.png" alt="human_gif"></li>
<li><img class="input" src="../assets/images/symbol_input1.png" alt="human_gif"></li>
</ul>
</div>
<div class="layout" id="layoutId" style="height:404px;"></div>
This code is written inside script
import jsPlumb from 'jsplumb'
export default {
name: 'HelloWorld',
data() {
return {
message: 'Welcome user',
endpoint1: '',
i: 0,
clone: '',
componentMap: {}
}
},
created() {
this.endpoint1 = {
isSource: true,
isTarget: true,
endpoint: ['Dot', {
radius: 4
}, {
outlineStroke: 'black'
}, {
outlineWidth: 10
}],
paintStyle: {
outlineStroke: 'black',
outlineWidth: 10
},
cssClass: 'ends',
maxConnections: -1,
connector: ['Flowchart', {
stub: [40, 60],
gap: 5,
cornerRadius: 5,
alwaysRespectStubs: true
}],
connectorStyle: {
strokeWidth: 2,
stroke: '#61B7CF'
},
connectorHoverClass: 'connector-line',
dropOptions: {
drop: function(e, ui) {
alert('drop!')
}
}
}
jsPlumb.draggable('decision', {
appendTo: 'body',
cursor: 'pointer',
containment: 'layoutId',
helper: 'clone',
revert: 'invalid'
})
window.jsPlumbInstance.droppable('layout', {
accept: '.decision, .input',
activeClass: 'ui-state-default',
hoverClass: 'ui-state-hover',
drop: function(event, ui) {
this.clone = ui.helper.clone()
this.clone.draggable({
containment: 'layout'
})
if (ui.draggable.attr('id') !== null) {
if (ui.draggable.attr('class').indexOf('decision') !== -1) {
this.clone.attr('id', 'input_' + this.i)
this.componentMap['input_' + this.i] = this.clone.attr('name')
jsPlumb.addEndpoint(this.clone, {
anchors: ['Left']
}, this.endpoint1)
jsPlumb.addEndpoint(this.clone, {
anchors: ['Right']
}, this.endpoint1)
}
}
}
})
}
}
can anyone please suggest me where I did the mistake?

I had the same issue and fixed it by importing jsPlumb this way:
import jsplum from 'jsplumb'
And then the calls should occurs like this:
jsplumb.jsPlumb.ready(function () {
jsplumb.jsPlumb.connect({
source: 'item0',
target: 'item1',
endpoint: 'Rectangle'
})

jsPlumb seems to be a non default export.
Do this:
import {jsPlumb} from 'jsplumb';

Related

setText error in quill text editor for Vue3.js

I created a text editor component for my Vue3 project which is based on Quill (for documentation --> https://quilljs.com/docs/api/#setcontents):
<template>
<div class="form-control" v-bind:class="inputClasses" ref="editor"></div>
</template>
<script>
import Quill from 'quill';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.bubble.css';
import 'quill/dist/quill.snow.css';
import GENERAL_COMPONENT_CONSTANTS from "../constants/GeneralComponentConstants";
export default {
props: {
modelValue: { type: String, default: '' },
},
data() {
return {
editor: null
};
},
mounted() {
var _this = this;
this.editor = new Quill(this.$refs.editor, {
modules: {
toolbar: [
[{ header: [1, 2, 3, 4, false]} ],
["bold", "italic", "underline", "link", "image"],
],
},
//theme: 'bubble',
theme: "snow",
formats: ["bold", "underline", "header", "italic", "link"],
placeholder: this.placeholder,
});
this.editor.root.innerHTML = this.modelValue;
this.editor.setText('Default Value');
this.editor.on("text-change", function () {
return _this.update();
});
},
methods: {
update: function update() {
this.$emit(
"update:modelValue",
this.editor.getText() ? this.editor.root.innerHTML : ""
);
},
},
computed: {
}
}
</script>
It works fine and as a default value, I set the text this.editor.setText('Default Value'); But I am getting Uncaught DOMException: Failed to execute 'setStart' on 'Range': The offset 4294967294 is larger than the node's length error when I try to delete the whole default value.

Error in mounted hook (Promise/async): "TypeError: Cannot read property 'length' of undefined"

I have created a project with Vue. I'm trying to show some data through a chart using the ChartJs library, to capture the information I use axios. I've been getting this error since the beginning but I don't know what I'm missing, any idea?
async created() {
const { data } = await axios.get("https://covid19.mathdro.id/api/confirmed");
var c=0
for(var i=0;i<1000;i++){
if(data[i].countryRegion=="India"){
if (data[i].provinceState in this.labels){
continue
}
else{
this.labels.push(data[i].provinceState)
this.confirmed.push(data[i].confirmed)
c=c+1
if(c==28){
break
}
}
}
}
console.log(this.labels)
}
In the error message it also mentions this function which is in the LineChart.vue file
<template>
<canvas ref="chartLine" width="900px" height="250px"></canvas>
</template>
<script>
import Chart from 'chart.js';
export default {
props: {
label: {
type: Array
},
chartData: {
type: Array
},
},
async mounted() {
await new Chart(this.$refs.myChart, {
type: 'line',
data: {
labels: this.label,
datasets: [
{
label: 'CASES',
borderColor: 'rgba(245, 229, 27, 1)',
backgroundColor: 'rgba(255, 236, 139,0.2)',
data: this.chartData,
}
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
}
</script>

Flickering of charts and getcontext error with chartjs in the context of Vuejs

Hello i am trying to display different charts using the chartjs by calling the API. Below code shows how i have formatted the chart.vue
Chart.vue:
<template>
<div class="chart-container" style="position: relative; height: 40vh; width:100%;">
<slot name="test1"></slot>
<slot name="test2"></slot>
</div>
</template>
<script>
export default {
name: 'charts',
data () {
return {
date: [],
challenge: [],
data: []
}
},
mounted () {
this.check(8, 'chart_8')
this.check(7, 'chart_7')
},
methods: {
check (id, name) {
this.$http.get(`/api_chart/${ id }/full`)
.then((response) => {
this.date = response.data.date
this.challenge = response.data.challenge
this.data = this.date.map((date, index) => ({
x: new Date(date * 1000),
y: this.challenge[index]
}))
const ctx = document.getElementById([name]).getContext('2d')
let myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: 'Challenge',
data: this.data,
borderColor: ' #EA5455',
}
]
},
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [
{
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true,
callback (value) {
return `${value}%`
}
}
}
],
xAxes: [
{
type: 'time',
time: {
unit: 'month'
},
scaleLabel: {
display: true,
}
}
]
}
}
})
})
}
}
}
</script>
App.vue:
<template>
<div class="In order to display chart1">
<chart-display> <canvas slot="test1" id="chart_7" ></canvas> </chart-display>
</div>
<div class="In order to display chart1">
<chart-display> <canvas slot="test2" id="chart_8" ></canvas> </chart-display>
</div>
</template>
<script>
import chart-display from './Chart.vue'
export default {
component: {chart-display}
}
</script>
As you can see i have shared my Chart.vue and App.vue, i am able to see my chart in the browser, but whenever i run the code or refresh the page, the charts flickers and stops. And then in my console i get below error:
Please someone help me to get rid of this issue, and please tell me if any changes i should do in my code to solve it. Please send me the modification code.
As I wrote in my comment, the charts are rendered twice. This causes flickering.
// every time you use <chart-display>, 2 charts are rendered, this means chart 1 renders
// itself and chart 2, char 2 renders itself and chart 1, this is a bad pattern in Vue in general
mounted() {
this.check(8, "chart_8");
this.check(7, "chart_7");
}
Make the following changes:
ChartDisplay.vue
<template>
<div
class="chart-container"
style="position: relative; height: 40vh; width: 100%"
>
<canvas ref="chart_7"></canvas>
<canvas ref="chart_8"></canvas>
</div>
</template>
<script>
import Chart from "chart.js";
export default {
name: "ChartDisplay",
data() {
return {
date: [],
challenge: [],
data: [],
// save charts in an array
charts: [],
// charts options
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [
{
scaleLabel: {
display: false,
},
ticks: {
beginAtZero: true,
callback(value) {
return `${value}%`;
},
},
},
],
xAxes: [
{
type: "time",
time: {
unit: "month",
},
scaleLabel: {
display: true,
},
},
],
},
},
};
},
mounted() {
this.render(7, this.$refs.chart_7);
this.render(8, this.$refs.chart_8);
},
methods: {
render(id, ctx) {
this.fetchData(id).then((response) => {
let data = response.date.map((date, index) => ({
x: new Date(date * 1000),
y: response.challenge[index],
}));
this.charts.push(
new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "Challenge",
data: data,
borderColor: " #EA5455",
},
],
},
options: this.options,
})
);
});
},
fetchData(id) {
return this.$http.get(`/api_chart/${ id }/full`);
},
},
beforeDestroy() {
this.charts.forEach((chart) => chart.destroy());
},
};
</script>
<style >
[v-cloak] {
display: none;
}
</style>
App.vue
<template>
<div>
<div class="In order to display chart1">
<chart-display/>
</div>
</div>
</template>
<script>
import ChartDisplay from "./ChartDisplay.vue";
export default {
components: { ChartDisplay },
};
</script>
See it on sandbox
I found several errors on your code. I fix them in Sandbox
For Chat.vue :
I rename the file as ChartDisplay.vue as similar as the component name
import chart.js package for using Chart() function
I use a demo API
<template>
<div
class="chart-container"
style="position: relative; height: 40vh; width: 100%"
>
<slot name="test1"></slot>
<slot name="test2"></slot>
</div>
</template>
<script>
import Chart from "chart.js";
export default {
name: "ChartDisplay",
data() {
return {
date: [],
challenge: [],
data: [],
};
},
mounted() {
this.check(8, "chart_8");
this.check(7, "chart_7");
},
methods: {
check(id, name) {
fetch(
"https://api.wirespec.dev/wirespec/stackoverflow/fetchchartdataforvuejs"
)
.then((response) => response.json())
.then((response) => {
this.date = response.date;
this.challenge = response.challenge;
this.data = this.date.map((date, index) => ({
x: new Date(date * 1000),
y: this.challenge[index],
}));
const ctx = document.getElementById([name]).getContext("2d");
new Chart(ctx, {
type: "line",
data: {
datasets: [{
label: "Challenge",
data: this.data,
borderColor: " #EA5455",
}, ],
},
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [{
scaleLabel: {
display: false,
},
ticks: {
beginAtZero: true,
callback(value) {
return `${value}%`;
},
},
}, ],
xAxes: [{
type: "time",
time: {
unit: "month",
},
scaleLabel: {
display: true,
},
}, ],
},
},
});
});
},
},
};
</script>
For App.vue
Your import should not carry any hyphen.
component should be components
render the component once to avoid flikering
<template>
<div>
<div class="In order to display chart1">
<chart-display>
<canvas slot="test1" id="chart_7"></canvas>
<canvas slot="test2" id="chart_8"></canvas>
</chart-display>
</div>
</div>
</template>
<script>
import ChartDisplay from "./ChartDisplay.vue";
export default {
components: {
ChartDisplay
},
};
</script>

vue-chartJs, Unable to update the chart

I am using Vue-Chartjs to create a simple Line chart, I'm filling the chart with data via a get request to an API
however I want to generate new values randomly when I click on a button, & pass the values as a prop to chart-line component.
I've tried using reactiveProp & I also tried using a watcher for chartData prop, but I'm always getting this error
client.js?06a0:83 TypeError: Cannot read property 'map' of undefined
Dashboard Component
<template>
<div class="container">
<h1>Dashboard Page</h1>
<v-alert v-if="errorDetected"
class="mt-4"
dense
outlined
type="error"
>
There was an error while getting the chart data
</v-alert>
<v-btn #click="generateNewData()">Generate new data</v-btn>
<div class="loader-container">
<img v-if="!loaded" class="chart-loader mt-3" src="../static/loader-dotted.gif" alt="">
</div>
<ChartLine v-if="loaded" :chartData="values" :bind="true" />
</div>
</template>
<script>
import ChartLine from '../components/chart-line'
export default {
middleware: 'session',
components: {
ChartLine
},
data() {
return {
values: [],
customValues: [],
loaded: false,
errorDetected: false
}
},
head() {
return {
title: 'Dashboard page',
meta: [
{
hid: 'description',
name: 'description',
content: 'simple dashboard SPA'
}
]
}
},
mounted() {
this.requestData()
},
methods: {
requestData() {
this.loaded = false
this.$axios.get('http://www.mocky.io/v2/5eda474f330000fefc79eab4?mocky-delay=2000ms').then(response => {
console.log("requestData -> response", response)
this.values = response.data.data.value
this.loaded = true
}).catch(error => {
this.loaded = true
this.errorDetected = true
})
},
generateNewData() {
this.values = [];
for(let i=0; i<7; i++)
this.values.push(Math.floor((Math.random() * 10) + 1))
}
}
}
</script>
<style>
.loader-container {
display: flex;
justify-content: center;
}
.chart-loader {
width: 150px;
}
</style>
ChartLine Component
<script>
//Importing Line class from the vue-chartjs wrapper
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
//Exporting this so it can be used in other components
export default {
extends: Line,
mixins: [reactiveProp],
props: ['chartData'],
data () {
return {
datacollection: {
//Data to be represented on x-axis
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: "Data 1",
backgroundColor: "transparent",
borderColor: "rgba(1, 116, 188, 0.50)",
pointBackgroundColor: "rgba(171, 71, 188, 1)",
//Data to be represented on y-axis
data: this.chartData
}
],
},
options: {
responsive: true,
maintainAspectRatio: false
}
//Chart.js options that controls the appearance of the chart
}
},
watch: {
chartData() {
this.renderChart(this.datacollection, this.options)
}
},
mounted () {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.datacollection, this.options)
}
}
</script>
UPDATE
I've managed to solve the issue of updating the chart
I removed the dataCollection from the chart-line component & added it in the dashboard component, I've also used the requestData() method in the created() hook to make a get request to the API, then on a button click I generate a new values and pass it as a prop
Update Code
Dashboard Component
<template>
<div class="container">
<h1>Dashboard Page</h1>
<v-alert v-if="errorDetected"
class="mt-4"
dense
outlined
type="error"
>
There was an error while getting the chart data
</v-alert>
<v-btn class="primary" #click="generateNewData()">Generate New Data</v-btn>
<div class="loader-container">
<img v-if="!loaded" class="chart-loader mt-3" src="../static/loader-dotted.gif" alt="">
</div>
<ChartLine v-if="loaded" :chart-data="dataCollection" />
</div>
</template>
<script>
import ChartLine from '../components/chart-line'
export default {
middleware: 'session',
components: {
ChartLine
},
data() {
return {
dataCollection: null,
values: [],
customValues: [],
loaded: false,
errorDetected: false
}
},
head() {
return {
title: 'Dashboard page',
meta: [
{
hid: 'description',
name: 'description',
content: 'simple dashboard SPA'
}
]
}
},
created() {
// this.loaded = false
// this.fillData()
// this.loaded = true
this.requestData()
},
methods: {
requestData() {
this.loaded = false
this.$axios.get('http://www.mocky.io/v2/5eda474f330000fefc79eab4?mocky-delay=2000ms').then(response => {
this.values = response.data.data.value
this.loaded = true
this.fillData()
}).catch(error => {
this.loaded = true
this.errorDetected = true
})
},
fillData () {
this.dataCollection = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: "Data 1",
backgroundColor: "transparent",
borderColor: "rgba(1, 116, 188, 0.50)",
pointBackgroundColor: "rgba(171, 71, 188, 1)",
data: this.values
}
]
}
},
generateNewData() {
this.values = []
this.loaded = false
setTimeout(function(){},2000)
for(let i=0; i<7; i++) {
this.values.push(Math.floor(Math.random() * (50 - 5 + 1)) + 5)
}
this.fillData()
this.loaded = true
}
}
}
</script>
<style>
.loader-container {
display: flex;
justify-content: center;
}
.chart-loader {
width: 150px;
}
</style>
Chart-Line Component
<script>
//Importing Line class from the vue-chartjs wrapper
import { Line, mixins } from 'vue-chartjs'
//Exporting this so it can be used in other components
export default {
extends: Line,
mixins: [mixins.reactiveProp],
// props:['chartData'],
data () {
return {
options: {
responsive: true,
maintainAspectRatio: false
}
//Chart.js options that controls the appearance of the chart
}
},
mounted () {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.chartData, this.options)
}
}
</script>
however there's still one thing I can't figure out, which is the loading state, when clicking on the button to generate new data
when I first open the dashboard page, the loading state works, but when I click on the button, loading state doesn't work
any Idea why??????

Uncaught Reference Error: Vue is not Defined (Despite Direct Script Included in file)

I have been trying to implement this vue.js template into my vue project and it has been returning "Uncaught ReferenceError: Vue is not defined" despite the direct script set on the first line.
<script type="text/javascript" src="https://vuejs.org/js/vue.min.js"</script>
<template>
<div id="app" class="wrapper">
<fullcalendar class="full-Calendar" :events="events" :editable="true"></fullcalendar>
</div>
</template>
<script>
Vue.component('full-calendar', {
template: '<div></div>',
props: {
events: {
type: Array,
required: true
},
editable: {
type: Boolean,
required: false,
default: false
},
droppable: {
type: Boolean,
required: false,
default: false
}
},
data: function()
{
return {
cal: null
};
},
ready: function()
{
var self = this;
self.cal = $(self.$el);
var args = {
lang: 'en',
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
height: "auto",
allDaySlot: false,
slotEventOverlap: false,
timeFormat: 'HH:mm',
events: self.events,
dayClick: function(date)
{
self.$dispatch('day::clicked', date);
self.cal.fullCalendar('gotoDate', date.start);
self.cal.fullCalendar('changeView', 'agendaDay');
},
eventClick: function(event)
{
self.$dispatch('event::clicked', event);
}
};
if (self.editable)
{
args.editable = true;
args.eventResize = function(event)
{
self.$dispatch('event::resized', event);
}
args.eventDrop = function(event)
{
self.$dispatch('event::dropped', event);
}
};
if (self.droppable)
{
args.droppable = true;
args.eventReceive = function(event)
{
self.$dispatch('event::received', event);
}
};
this.cal.fullCalendar(args);
}
});
new Vue({
el: '#app',
data: {
events: [
{
title: 'Event1',
start: '2018-08-10 12:30:00',
end: '2018-08-10 16:30:00'
},
{
title: 'Event2',
start: '2018-08-07 17:30:00',
end: '2018-08-07 21:30:00'
}
]
},
events: {
'day::clicked': function(date)
{
console.log(date);
}
}
});
</script>
<style>
.wrapper {
margin: 2rem;
}
</style>
I've also tried adding the direct script to index.html and it leads to "[Vue warn]: Unknown custom element"
you are allowed to use only one <script> tag in the component.
since 2 are present it will give preference to the default syntax flow
<templete></templete>
<script></script>
<style></style>
check out this
https://github.com/vuejs/vue-loader/issues/228
and
https://medium.com/#lassiuosukainen/how-to-include-a-script-tag-on-a-vue-component-fe10940af9e8