How to use v-model in QuillJS in vue 3 app? - vue.js

If I try to use v-model in the div with editor reference it gives me this error:
"'v-model' directives aren't supported on elements."
<div ref="editor"></div>
<script>
import Quill from "quill";
export default {
data() {
return {
description: "", // variable that I'm trying to use in v-model
options: {
modules: {
toolbar: ["bold", "italic", { list: "ordered" }, { list: "bullet" }],
},
theme: "snow",
},
};
},
watch: {
isDescription(newVal, oldVal) {
if (newVal == true) {
setTimeout(() => {
new Quill(this.$refs.editor, this.options);
}, 1);
}
},
},
};
</script>

Related

how to create vue-shepperd component

I am trying to develop guided tour with shepherd: https://www.npmjs.com/package/vue-shepherd but I cannot get the element. So here is my component for guide tour:
<template>
<div></div>
</template>
<script>
import { useShepherd } from 'vue-shepherd';
export default {
props: {
element: {
required: true,
},
id: {
type: Number,
required: true,
},
title: {
type: String,
},
text: {
type: String,
required: true,
},
position: {
type: String,
required: true,
},
},
mounted() {
this.tour.start();
},
data() {
return {
tour: null,
};
},
methods: {
createTour() {
this.tour = useShepherd({
useModalOverlay: true,
});
this.tour.addStep({
title: this.title,
text: this.text,
attachTo: { element: this.element, on: this.position },
buttons: [
{
action() {
return this.back();
},
classes: 'shepherd-button-secondary',
text: 'Back',
},
{
action() {
return this.next();
},
text: 'Next',
},
],
id: this.id,
});
this.tour.start();
},
},
created() {
this.createTour();
},
};
</script>
and here is my parent component:
<button ref="button">
Click
</button>
<guide :element="element" :title="'Tour'" :text="'Example'" :position="'bottom'" :id="1" />
and the mounted of the parent element:
mounted() {
this.element = this.$refs.button;
},
but the tour doesnt attach the the button element. it just appears in the middle of the page. Why do you think it is?
Looks like a usage problem in vue hooks. The child component's hooks fire before the parent component's hooks. Therefore, at the time of the creation of the tour, the element does not exist. Vue-shepherd does not use vue reactivity.
Use
mounted() {
this.$nextTick(() => {
this.createTour();
});
},
Codesanbox
But it's better to change the component structure. If you are using vue3 you can use my package
In this case it will look like this
<template>
<button v-tour-step:1="step1">
Click
</button>
</template>
<script>
import { defineComponent, inject, onMounted } from "vue";
export default defineComponent({
setup() {
const tour = inject("myTour");
onMounted(() => {
tour.start();
});
const step1 = {
/* your step options */
}
return {
step1,
};
}
});
</script>

v-if is not updated when importing a 3rd party script with vue-meta

I want to use vue-meta to import a 3rd party SwiperJS script into my nuxt website.
The script is loaded only after mounted()-hook is called so I also initialize it on update(). This kind of works but the v-if on the wrapper does not update.
<template>
<section
class="swiper"
v-if="isSwiperLoaded"
>
<div class="swiper-wrapper"> ... </div>
</section>
</template>
<script>
export default {
data() {
return { swiperLoaded: false, swiperInitialized: false }
},
computed: {
isSwiperLoaded: {
get() {
return this.swiperLoaded
},
set(value) {
this.swiperLoaded = value
},
},
isSwiperInitialized: {
get() {
return this.swiperInitialized
},
set(value) {
this.swiperInitialized = value
},
},
},
head() {
return {
script: [
{
hid: 'swiper',
src: 'https://cdn.jsdelivr.net/npm/swiper#8/swiper-bundle.min.js',
defer: true,
// Changed after script load
callback: () => {
this.isSwiperLoaded = true
},
},
],
link: [
{
rel: 'stylesheet',
type: 'text/css',
href: 'https://cdn.jsdelivr.net/npm/swiper#8/swiper-bundle.min.css',
},
],
}
},
methods: {
initSwiper() {
const swiperOptions = {
...
}
let swiper = new Swiper(this.$el, swiperOptions)
},
},
mounted() {
if (!this.isSwiperInitialized && this.isSwiperLoaded) {
console.log('INIT LOADED')
this.initSwiper()
this.isSwiperInitialized = true
}
},
updated() {
if (!this.isSwiperInitialized && this.isSwiperLoaded) {
console.log('UPD LOADED')
this.initSwiper()
this.isSwiperInitialized = true
}
},
}
</script>
Also I noticed the computed values are normally for getting and setting values from store and not local values. Maybe there is an easier way of updating the variables.

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.

Initialization of variables with Vuex

I made a VueJS 3 project with VueX to store the data.
When I print the variable data.doughnutChart.data in the following code it displays
{ "labels": [ "OK", "WARNING", "ERROR" ], "datasets": [ {
"backgroundColor": [ "#d4efdf", "#fdebd0", "#fadbd8" ], "data": [ 3,
1, 2 ] } ] }
But the graph doesn't use these data [3,1,2], the graph uses the values of the initialization in the index.js of VueX.
Here my code :
<template>
{{data.doughnutChart.data}}
<div style="height:200px;width: 200px; position:center">
<vue3-chart-js
:id="data.doughnutChart.id"
:type="data.doughnutChart.type"
:data="data.doughnutChart.data"
:options="data.doughnutChart.options"
></vue3-chart-js>
</div>
</template>
<script>
import Vue3ChartJs from '#j-t-mcc/vue3-chartjs'
export default {
name: 'App',
components: {
Vue3ChartJs,
},
beforeMount() {
this.$store.dispatch("getData");
},
computed: {
data() {
return {
doughnutChart: {
id: 'doughnut',
type: 'doughnut',
data: {
labels: ['OK', 'WARNING', 'ERROR'],
datasets: [
{
backgroundColor: [
'#d4efdf',
'#fdebd0',
'#fadbd8'
],
data: [this.$store.state.nbOk, this.$store.state.nbWarning, this.$store.state.nbError]
}
]
},
options:
{
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Current situation'
}
},
}
}
}
}
}
}
</script>
I read the value in my index.js (VueX) :
import axios from 'axios'
import { createStore } from 'vuex'
export default createStore({
state: {
data: [],
nbError : 0,
nbWarning : 0,
},
actions: {
getData({commit}){
axios.get('http://localhost:8080/data/mock.json')
.then(res => {
commit('SET_DATA', res.data)
})}
},
mutations: {
SET_DATA(state, data){
state.data = data.data;
state.nbWarning = 0;
state.nbError = 0;
for (let i = 0; i < state.data.length; i++) {
if(state.data[i].status == 'WARNING'){
state.nbWarning += 1;
};
if(state.data[i].status == 'ERROR'){
state.nbError += 1;
};
};
}
})
However it works when, in my Vuejs project, I go in an other page and come back but not when I just open the project or refresh the page.
Do you know why ?
data property should be defined as computed in order to receive store changes:
<template>
{{data}}
</template>
<script>
export default {
data() {
return {
}
},
computed:{
data(){
return [this.$store.state.nbWarning, this.$store.state.nbError]
}
},
beforeMount() {
this.$store.dispatch("getData");
}
}
</script>

Unable to display chart using API call in chartjs in the context of Vuejs

Im trying to display chart using chartjs by calling API, but unable to do so.
Here s my LineChart.vue:
<script>
import {Line, mixins} from 'vue-chartjs' // We specify what type of chart we want from vue-chartjs and the mixins module
const { reactiveProp } = mixins
export default { //We are extending the base chart class as mentioned above
extends: Line,
mixins: [reactiveProp],
data () {
return {
options: { //chart options
lineTension: 0,
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
yAxes: [
{
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true,
// eslint-disable-next-line no-unused-vars
callback (value, index, values) {
return `${value }%`
}
}
}
],
xAxes: [
{
type: 'time',
time: {
unit: 'month'
},
scaleLabel: {
display: true,
labelString: ''
}
}
]
}
}
}
},
mounted () {
// this.chartData is created in the mixin
this.renderChart(this.chartData, this.options)
}
}
</script>
And here is my Home.vue where i have imported the LineChart:
<template>
<div class="chart">
<line-chart :chart-data="datacollection"></line-chart>
</div>
</template>
<script>
import LineChart from './LineChart'
import axios from 'axios'
import DateTime from 'luxon'
export default {
data () {
return {
date: {},
challenge: {},
datacollection: {}
}
},
component: {LineChart},
created() {
this.fillData()
},
mounted () {
this.fillData()
},
methods: {
fillData () {
axios.get('https://my_api_goes_here')
.then(response => {
const results = response.data
const dateresult = results.map(a => a.date)
const challengeresult = results.map(a => a.challenge)
this.date = dateresult
this.challenge = challengeresult
this.datacollection = {
labels: [this.date].map(labels => DateTime.fromMillis(labels * 1000).toFormat('MMM yyyy')),
datasets: [
{
data: [this.challenge],
label: 'Africa',
borderColor: '#7367F0'
}
]
}
})
.catch(error => {
console.log(error)
})
}
}
}
</script>
Dont know why the chart did not appear even though my other resources have been loaded from the API call, when i checked out my console, this is what error im getting:
TypeError: results.map is not a function
Please check out my logic and let me where the error is.