I want to use #vueup/vue-quill ^1.0.0-beta.7 on my control panel admin based on vue ^3.2.29.
Unfortunately, I noticed that loading HTML content is not working for me. Quill converts <div> tags to <p> tags for me, also removing classy and css styles, which destroys the appearance of the content. On backand i use Laravel.
Can anyone help me with this? I sit on it all day to no avail.
<template>
// [...]
<QuillEditor
ref="mainContent"
v-model:content="form.content"
style="min-height: 300px"
:options="editorOptions"
theme="snow"
content-type="html"
output="html"
#text-change="countMainContent"
/>
// [...]
</template>
<script>
import { QuillEditor, Quill } from "#vueup/vue-quill";
import "#vueup/vue-quill/dist/vue-quill.snow.css";
import BlotFormatter from "quill-blot-formatter";
import QuillImageDropAndPaste, { ImageData } from "quill-image-drop-and-paste";
import ArticleCategoryField from "../forms/ArticleCategoryField.vue";
import htmlEditButton from "quill-html-edit-button";
import useVuelidate from "#vuelidate/core";
import { required } from "../../utils/i18n-validators";
Quill.register({
"modules/blotFormatter": BlotFormatter,
"modules/htmlEditButton": htmlEditButton,
"modules/imageDropAndPaste": QuillImageDropAndPaste,
});
// [...]
data() {
return {
// [...]
editorOptions: {
handlers: {
// handlers object will be merged with default handlers object
link: function (value) {
if (value) {
var href = prompt("Enter the URL");
this.quill.format("link", href);
} else {
this.quill.format("link", false);
}
},
},
modules: {
toolbar: [
["bold", "italic", "underline", "strike"], // toggled buttons
["blockquote", "code-block"],
[{ header: 1 }, { header: 2 }], // custom button values
[{ list: "ordered" }, { list: "bullet" }],
[{ script: "sub" }, { script: "super" }], // superscript/subscript
[{ indent: "-1" }, { indent: "+1" }], // outdent/indent
[{ direction: "rtl" }], // text direction
[{ size: ["small", false, "large", "huge"] }], // custom dropdown
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
[{ font: [] }],
[{ align: [] }],
["image", "link", "video"],
["clean"], // remove formatting button
],
blotFormatter: {},
htmlEditButton: {
debug: false,
msg: "Edytuj zawartość przy pomocy HTML",
cancelText: "Anuluj",
buttonTitle: "Pokaż kod źródłowy HTML",
},
imageDropAndPaste: {
handler: this.imageHandler,
},
},
},
// [...]
}
}
// [...]
methods: {
getArticle() {
if (this.articleId) {
this.$axios
.get("article/" + this.articleId, {
headers: {
Accept: "application/json",
Authorization: `Bearer ${this.$store.state.auth.token}`,
},
})
.then((response) => {
this.form.title = response.data.article.title;
this.form.mainImage =
response.data.article.uploaded_file_id;
this.form.category =
response.data.article.categories[0].id ?? 0;
this.$refs.mainContent.pasteHTML(
response.data.article.content
);
this.form.articleGallery = this.prepareGallery(
response.data.article.images
);
})
.catch((error) => {
if (process.env.MIX_APP_DEBUG)
this.$toast.error(error.message);
throw new Error(error);
});
}
},
// [...]
I know its bit late. But posting this to help those who visit this question.
I had the same problem. When i tried to load contents into use #vueup/vue-quill editor on the edit page, there were complications. I could load delta, html and plain text using setContents(),setHTML() etc, but after that the problem was that when i tried to type inside the same editor js errors occur. The only solution i found was to implement the quill on own. Sharing my experience to help others.
//do bootstrap if needed
// import './bootstrap';
import { createApp } from 'vue';
import { watch, ref, nextTick } from 'vue'
import axios from 'axios';
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.bubble.css";
import "quill/dist/quill.snow.css";
createApp({
data() {
return {
mainContentEditor: null,
mainContentEditorValue: '',
}
},
mounted() {
this.initMainContentEditor();
//call this to get article on load
this.getArticle();
},
methods: {
//initiate the main content editor
initMainContentEditor() {
var _this = this;
this.mainContentEditor = new Quill(this.$refs.mainContentEditor, {
modules: {
toolbar: [
[
{
header: [1, 2, 3, 4, false],
},
],
["bold", "italic", "underline", "link"],
],
},
//theme: 'bubble',
theme: "snow",
formats: ["bold", "underline", "header", "italic", "link"],
placeholder: "Type something in here!",
});
//register the event handler
this.mainContentEditor.on("text-change", function () {
_this.mainContentEditorChanged();
});
},
//this method is called when the editor changes its value
mainContentEditorChanged() {
console.log("main content changed!");
// do somethign with it like assign it to mainContentEditorValue
this.mainContentEditorValue = this.mainContentEditor.root.innerHTML;
},
getArticle() {
//do the api call to get the article response.
//once you get the respose
// assign the html content to quill editor
// check getArticle() method on question to fill this part
//replace
// this.$refs.mainContent.pasteHTML(
// response.data.article.content
// );
// with this
this.mainContentEditor.root.innerHTML = response.data.article.content;
}
}
}).mount('#app')
html/template
<div id="app">
<div ref="mainContentEditor"></div>
</div>
You can make it to a component and reuse it. I shared it to just show a working implementation.
Related
this is my first time posting here, i'm working on an application where i need to get data from an API and show it through a chart (i'm using vue chart js). The code is almost done, i can see in the console the API's data.
Showing API's data in console
This is my chart/api conection:
<template>
<div>
<bar-chart
:data="barChartData"
:options="barChartOptions"
:height="150"
:width="150"
/>
</div>
</template>
<script>
import BarChart from "~/components/BarChart";
const chartColors = {
grey: "rgba(210, 210, 210, 0.2)",
white: "rgb(255,255,255)",
};
export default {
components: {
BarChart,
},
data() {
return {
barChartData: {
asistencia: [],
labels: [],
datasets: [
{
label: "Income",
backgroundColor: [chartColors.white, chartColors.grey],
data: [0,0],
},
],
},
barChartOptions: {
responsive: true,
legend: {
display: true,
},
},
};
},
async fetch() {
this.asistencia = await fetch(
'http://127.0.0.1:8000/apiasistenciausuarioAsistenciaUsuario/',
).then(res => res.json())
console.log(this.asistencia);
},
components: {
BarChart,
},
methods: {
refresh() {
this.datos();
this.$nuxt.refresh();
},
datos() {
this.barChartData.datasets[0].data = [
this.res.is_presente,
];
},
}
};
As you can see i send the data to the console but the "Asistencia" graphic is not showing and that's because it isn't getting the data sucessfully
datos() {
this.barChartData.datasets[0].data = [
this.res.is_presente,
];
barChartData should get the data from "is_presente" var from the API but that var is a boolean so i was thinking on doing a validation to check when it's true/false and make a counter to fill the graphic.
datos() {
this.barChartData.datasets[0].data = [
if(this.res.is_presente == true){
count++;
}else{
count--;
}
];
I don't know how to do this, i have the idea but i don't know how to execute this....
Thanks in advance!
I am looking for a organization chart plugin for vue 3 and I have found only this one
https://github.com/megafetis/vue3-blocks-tree
The issue that I have is when changing the ref treeData variable the chart is not loading the new structure.
I want to dynamic load the chart. When fetch the data the chart to loads the new data and display it.
Here is the codesandbox example:
https://codesandbox.io/s/flamboyant-gwen-o8vp9?file=/src/App.vue
When press the Add ... the treeData reference variable should load the new data and the chart to display it ... but it doesn't.
Any ideas ?
Should I reload the component on every fetch ?
Try to use documented way make treeData reactive.
Replace ref to reactive for treeDate definition.
Change parts of treeData on onAddData instead replacing all object.
Full changed example:
import { reactive } from "vue";
import VueBlocksTree from "vue3-blocks-tree";
import "vue3-blocks-tree/dist/vue3-blocks-tree.css";
export default {
name: "Diagram",
components: { VueBlocksTree },
setup() {
let treeData = reactive({
label: "root",
children: [
{ label: "child 1" },
{ label: "child 2" },
{
label: "subparent 1",
children: [
{ label: "subchild 1" },
{
label: "subchild 2",
children: [{ label: "subchild 11" }, { label: "subchild 22" }],
},
],
},
],
});
// let treeData = ref({});
const onAddData = () => {
Object.assign(treeData, { label: "Test", children: [{ label: "Test 1" }, { label: "Test 2" }] });
};
return {
treeData,
onAddData,
};
},
};
UPD: Change code on onAddData by adding Object.assign.
I've been trying a couple of rich text editors, and Quill seems to be the best tool to implement into my projects. I'm using Node/Express and MongoDB/Mongoose. In my 'newPost route', I have a form that just takes a title and the main content. Since I'm just testing it out, the title field is outside of the Quill editor. Here the error I'm getting:
This is after I hit "submit". The console shows not only the title but also the main content that has a code-block with syntax highlight which is exactly what I wanted. But it's not being added to the database.
There's also this message Use of Mutation Events is deprecated. Use MutationObserver instead., and it seems I'm required to change Quill's source code myself to fix this.
Getting the main content of the post on the console kind of gave me a feeling that I'm halfway of getting this to work.
Is there a not-so-hard way to get this to work? Thanks!!
js
var quill;
var metaData = [];
hljs.configure({ // optionally configure hljs
languages: ['javascript', 'ruby', 'python']
});
hljs.initHighlighting();
$(document).ready(function() {
var toolbarOptions = [['blockquote', 'code-block'],
["bold", "italic", "underline", "strike"], // toggled buttons
//['blockquote'],
[{ list: "ordered" }, { list: "bullet" }],
[{ script: "sub" }, { script: "super" }], // superscript/subscript
[{ indent: "-1" }, { indent: "+1" }], // outdent/indent
[{ direction: "rtl" }], // text direction
[{ size: ["small", false, "large", "huge"] }], // custom dropdown
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
[{ font: [] }],
[{ align: [] }],
["clean"] // remove formatting button
];
quill = new Quill("#snow-container", {
placeholder: "Compose an epic...",
modules: {
syntax: true,
toolbar: toolbarOptions
},
theme: "snow"
});
var oldDelta = {"ops":[{"attributes":{"color":"#000000"},"insert":"This is sample text."}]};
quill.setContents(oldDelta);
});
var form = document.querySelector('form');
form.onsubmit = function() {
// Populate hidden form on submit
var formContent = document.querySelector('input[name=content]');
formContent.value = JSON.stringify(quill.getContents());
console.log("Submitted", $(form).serialize(), $(form).serializeArray());
// No back end to actually submit to!
//alert('Open the console to see the submit data!')
return false;
};
I'm a total newbie, so please bear with me if I'm still grasping with the coding fundamentals.
I want to use a template that is defined in the prop. The template is inside the DOM. The reason I want to do it this way is that I want to reuse the component logic (specifically the pagination), but may want to change how the way the template displays the data in different pages. So I wanted to seaparate the template from the script file.
This is the HTML File:
<div id="store-list">
<paginated-list :list-data="stores" use-template="#displayList"></paginated-list>
</div>
<script type="text/template" id="display-list">
<div>
<div v-for="p in paginatedData">
{{p.BusinessName}}
</div>
</div>
</script>
This is the .js file:
Vue.component('paginated-list', {
data() {
return {
pageNumber: 0
}
},
props: {
listData: {
type: Array,
required: true
},
useTemplate: {
type: String,
required: false
},
size: {
type: Number,
required: false,
default: 10
}
},
computed: {
pageCount() {
let l = this.listData.length,
s = this.size;
return Math.floor(l / s);
},
paginatedData() {
const start = this.pageNumber * this.size,
end = start + this.size;
return this.listData
.slice(start, end);
}
},
//template: document.querySelector('#display-list').innerHTML // this works
template: document.querySelector(useTemplate).innerHTML // this does not
});
var sl = new Vue({
el: '#store-list',
data: {
stores: [{
"BusinessName": "Shop Number 1"
}, {
"BusinessName": "Shop Number 2"
}, {
"BusinessName": "Shop Number 3"
}]
}
});
var shoppingList = new Vue({
el: '#shopping-list',
data: {
header: 'shopping list app',
newItem: '',
items: [
'1',
'2',
'3',
]
}
})
Any help is greatly appreciated. Thank you.
You can use the inline-template attribute to override the component's template at render time. For example
<paginated-list :list-data="stores" inline-template>
<div>
<div v-for="p in paginatedData">
{{p.BusinessName}}
</div>
</div>
</paginated-list>
See https://v2.vuejs.org/v2/guide/components-edge-cases.html#Inline-Templates
Your component can still have a default template but this will override it if set.
I am using https://github.com/matfish2/vue-tables with Laravel.
This is the vue code:
Vue.use(VueTables.client, {
compileTemplates: true,
highlightMatches: true,
pagination: {
dropdown:true,
chunk:5
},
filterByColumn: true,
texts: {
filter: "Search:"
},
datepickerOptions: {
showDropdowns: true
}
});
new Vue({
el: "#people",
methods: {
deleteMe: function(id) {
alert("Delete " + id);
}
},
data: {
options: {
columns: ['created_at', 'name', 'profession', 'footage_date', 'type', 'link', 'note'],
dateColumns: ['footage_date'],
headings: {
created_at: 'Added',
name: 'Name',
profession: 'Profesion',
footage_date: 'Footage Date',
type: 'Type',
link: 'Link',
note: 'Note',
edit: 'Edit',
delete: 'Delete'
},
templates: {
edit: "<a href='#!/{id}/edit'><i class='glyphicon glyphicon-edit'></i></a>",
delete: "<a href='javascript:void(0);' #click='$parent.deleteMe({id})'><i class='glyphicon glyphicon-erase'></i></a>"
},
},
tableData: [{ InsertDataHere }],
}
});
How do I get the data from DB for tableData ? Vue-resources?
I have a route /api/footage that gives me the following
[
{
"id": 2,
"user_id": 11,
"profession": "profession",
"type": "GvG",
"footage_date": {
"date": "2016-04-01 00:00:00.000000",
"timezone_type": 2,
"timezone": "GMT"
},
"link": "some link",
"note": "description",
"created_at": "1 hour ago",
"updated_at": "2016-04-03 23:06:32"
}
]
Now, User and Footage have a one to many relationship. How would I go about to show the user for each entry as well? ( also the ID for edit and delete )
This is the blade code
<div id="people" class="container">
<v-client-table :data="tableData" :options="options"></v-client-table>
</div>
Thank you in advance.
You can add a ready() function to call the API when the component is built:
ready:function(){
this.$http.get('/api/footage')
.then(function(response){
this.tableData = response.data
}.bind(this))
}
You may have to tweak the code based on the format of your API response. Cleaner version if youre using es2016:
ready(){
this.$http.get('/api/footage')
.then(({data})=>{
this.tableData = data
})
}
You should include vue-resource before this, yes. That allows you to use this.$http
As per #BillCriswell you could do this in the created() function to fire off the API call even sooner
When fetching async data use v-if along with some "loaded" flag on the component to ensure smooth compilation of templates.
<v-client-table v-if="loaded" :data="tableData" :options="options"></v-client-table>
See: https://github.com/matfish2/vue-tables/issues/20, last comment