add Base64UploadAdapter for ckeditor - vue.js

I use component locally method for use ckeditor and add Base64UploadAdapter plugin in config file.
but i have error ckeditor-duplicated-modules
how can i add truly Base64UploadAdapter plugin to ckeditor in nuxt component for Reuse this component.
//ckEditorNuxt
<template>
<ckeditor
:editor="editor"
:value="value"
:config="config"
:tagName="tagName"
:disabled="disabled"
#input="event => $emit('input', event)"
/>
</template>
<script>
let Classiceditor
let CKEditor
if (process.client) {
Classiceditor = require('#ckeditor/ckeditor5-build-classic')
CKEditor = require('#ckeditor/ckeditor5-vue2')
} else {
CKEditor = {component: {template: '<div></div>'}}
}
export default {
name: "ckEditorNuxt",
components: {
ckeditor: CKEditor.component
},
...and more
and use in this code.
<template>
<v-card height="100%">
<h4 class="pa-2">{{ title }}</h4>
<client-only placeholder="loading...">
<ckEditorNuxt v-model="contentHolder" :config="editorConfig"/>
</client-only>
</v-card>
</template>
<script>
import ckEditorNuxt from "#/components/ckEditor/ckEditorNuxt";
import {Base64UploadAdapter} from "#ckeditor/ckeditor5-upload";
export default {
name: "PersianCKEditor",
components: {
ckEditorNuxt,
},
props: {
title: String
},
data() {
return {
editorConfig: {
plugins: [
Base64UploadAdapter
],
placeholder: this.title,
removePlugins: ['Title'],
and more...

Related

Vue.js 2 data not displayed in the template

I'm using vue.js 2 / vue-cli with axios. I'm facing a problem with the display of my posts (in the wall). I've made my axios request, have gotten my data (in the console), I've written my template and ... nothing was displayed ... I really appreciate your help
my template :
<template>
<v-layout column>
<v-flex xs4>
<panel title="The Wall">
<p v-for="post in posts" :key="post.index">{{ post.title }} - {{ post.content }}</p>
</panel>
</v-flex>
</v-layout>
</template>
my script :
<script>
import Panel from '../components/Panel'
import PostService from "../services/PostService.js";
export default {
components: {
Panel
},
data() {
return {
posts: null
}
},
async mounted() {
this.posts = (await PostService.getAllPosts()).data;
}
}
</script>
Add a data property called cidItem for example and bind it to your props as follows
<template>
<div id="app" class="container" :cid="cidItem">
<Images :cid="cidItem" />
<Video :cid="cidItem" />
<TextType :cid="cidItem" />
<Card :cid="cidItem" />
</div>
</template>
<script>
import axios from 'axios';
import Images from "./components/Images";
import Video from "./components/Video";
import TextType from "./components/TextType";
import Card from "./components/Card";
export default {
name: 'app',
props: ["cid"],
components: {
Images,
Video,
TextType,
Card
},
mounted() {
axios({method: "GET", "url": this.contentDeliveryUrl}).then(result => {
// eslint-disable-next-line
this.content = amp.inlineContent(result.data)[0];
console.log(this.content)
}, error => {
console.error(error);
});
},
data() {
return {
contentDeliveryUrl: 'https://c1.adis.ws/cms/content/query?fullBodyObject=true&query=%7B%22sys.iri%22%3A%22http%3A%2F%2Fcontent.cms.amplience.com%2F${this.cid}%22%7D&scope=tree&store=testing',
content: [],
cidItem:'7e4301de-9c6e-4fab-9e68-3031b94d662d'
}
}
}
</script>
Since your component have the same structure i recommend to use mixins, create a file named myMixins.js and add the following code inside it :
const myMixins = {
props:['cid'],
mounted() {
axios({
method: "GET",
"url": this.contentDeliveryUrl
}).then(result => {
// eslint-disable-next-line
this.content = amp.inlineContent(result.data)[0];
console.log(this.content)
}, error => {
console.error(error);
});
},
data() {
return {
contentDeliveryUrl: 'https://c1.adis.ws/cms/content/query?fullBodyObject=true&query=%7B%22sys.iri%22%3A%22http%3A%2F%2Fcontent.cms.amplience.com%2F${this.cid}%22%7D&scope=tree&store=testing',
content: []
}
}
}
export default mixins;
and inside each component add this :
import myMixins from './myMixins'
export default{
....
mixins: [myMixin]
}

passing data in vuejs using props

I'm doing image upload in vuejs. And I separate the upload file, use props to listen
In user.vue
<template>
<a-form
:form="form"
#submit.prevent="uploadFile"
>
<a-tabs v-model="activeKey" tabPosition="right">=
<image-upload
:option="{
title: 'Upload',
placeholder: 'File upload'
}"
/>
</a-tabs>
</a-form>
</template>
<script>
import { Tabs, Form } from "ant-design-vue";
Vue.use(Tabs);
Vue.use(Form);
export default {
components: {
image-upload: () =>
import(
/* webpackChunkName: "js/chunks/photo-platform.chunk" */ "./upload/index.vue"
),
},
methods: {
uploadFile() {
this.form.validateFields((err, values) => {
console.log(values);
});
}
}
}
</script>
In upload/index.vue
<template>
<b-row>
<b-col md="3">
<b-form-group>
<label>{{option.title}}</label>
<b-form-file
accept="image/*"
placeholder= {{ option.placeholder }}
drop-placeholder="Drop file here..."
name="titleImage"
v-model="titleImage"
#change="changeTitle"
multiple
/>
</b-form-group>
</b-col>
</b-row>
</template>
<script>
import {
BCard,
BRow,
BCol,
BForm,
} from "bootstrap-vue";
export default {
props: {
option: Object
},
components: {
BFormGroup,
BRow,
BCol,
BCard,
},
data() {
return {
titleImage: [],
}
},
methods: {
changeTitle() {
////
}
}
}
</script>
I am using props in vuejs. Now I want when I select multiple images in upload/index.vue, and press submit form uploadFile in user.vue, I will get the data of the image I just selected in. Please give me your opinion. I'm new to vuejs so it's really hard for me. Thanks

Clicking routes in Header refreshes page in vuejs with prerender-spa plugin after serving dist

The connection in between components gets disrupted. Which shouldnt happen since I am using bootstrap-vue inbuilt router link (using to=" " instead of href="").
The app works perfectly fine when running without dist.
App.vue
<template>
<div class="container">
<app-header></app-header>
<div class="row">
<div class="col-xs-12">
<transition name="slide" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</div>
</template>
<script>
import Header from "./components/Header.vue";
export default {
components: {
appHeader: Header
},
created() {
this.$store.dispatch("initStocks");
}
};
</script>
Header.vue
<template>
<div>
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand to="/">Stock Broker</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/portfolio">Portfolio</b-nav-item>
<b-nav-item to="/stocks">Stocks</b-nav-item>
<b-nav-item #click="endDay">End Day</b-nav-item>
<b-navbar-nav right>
<b-nav-item right>Funds: {{ funds }}</b-nav-item>
</b-navbar-nav>
</b-navbar-nav>
</b-collapse>
</b-navbar>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
data() {
return {
isDropdownOpen: false
};
},
computed: {
funds() {
return this.$store.getters.funds;
}
},
methods: {
...mapActions({
randomizeStocks: "randomizeStocks",
fetchData: "loadData"
}),
endDay() {
this.randomizeStocks();
},
saveData() {
const data = {
funds: this.$store.getters.funds,
stockPortfolio: this.$store.getters.stockPortfolio,
stocks: this.$store.getters.stocks
};
this.$http.put("data.json", data);
},
loadData() {
this.fetchData();
}
}
};
</script>
vue.config.js
module.exports = {
pluginOptions: {
prerenderSpa: {
registry: undefined,
renderRoutes: ["/", "/portfolio", "/stocks"],
useRenderEvent: true,
headless: true,
onlyProduction: true
}
}
};
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/stocks',
name: 'Stocks',
component: () => import(/ '../views/Stocks.vue')
},
{
path: '/portfolio',
name: 'Portfolio',
component: () => import('../views/Portfolio.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
I figured it a minute after making this post haha.
The issue was that in App.vue I had my main div with a class of "container" instead of id of "app".
Corrected below:
<template>
<div id="app"> //correction here
<app-header></app-header>
<div class="row">
<div class="col-xs-12">
<transition name="slide" mode="out-in">
<router-view></router-view>
</transition>
</div>
</div>
</div>
</template>

VueJS display dynamic modal component

I have posts and replys s.t. replies belong to posts via the attribute reply.posts_id.
I am attempting to show the reply form as a modal for the user to enter a reply. However, I want to create a generic Modal component that I can use everywhere with content that is specified in another component built for a specific context.
Reply to post is the first place I woul like this to work.
Currently, the Vuex correctly returns Modal visible:true when the reply button is clicked, but the modal does not render and I get the error message showing that the Modal component is not found:
Unknown custom element: <ModalReplyForm> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I am using vuex to manage the visibility of the modal. Here are the relevant files:
store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
...
Vue.use(Vuex)
export default new Vuex.Store({
state: {
status: '',
...
modalVisible: false,
modalComponent: null
},
mutations: {
...
showModal(state, componentName) {
console.log('showing the modal')
state.modalVisible = true;
state.modalComponent = componentName;
},
hideModal(state) {
console.log('hiding the modal')
state.modalVisible = false;
}
},
actions: {
...
}
},
getters: {
isAuthenticated: state => !!state.user,
authStatus: state => state.status,
user: state => state.user,
token: state => state.token,
posts: state => {
return state.posts;
}
...
}
})
App.vue
<template>
<div id="app">
<app-modal></app-modal>
<NavigationBar />
<div class="container mt-20">
<router-view />
</div>
<vue-snotify></vue-snotify>
</div>
</template>
<script>
import AppModal from '#/components/global/AppModal';
import NavigationBar from '#/components/layout/NavigationBar'
export default {
name: "App",
components: {
AppModal,
NavigationBar
}
};
</script>
<style>
body {
background-color: #f7f7f7;
}
.is-danger {
color: #9f3a38;
}
</style>
Post.vue (houses the button to call the reply modal):
<template>
<div class="row ui dividing header news">
<!-- Label -->
<div class="m-1 col-md-2 ui image justify-content-center align-self-center">
<img v-if="post.avatar_url" :src="post.avatar_url" class="mini rounded"/>
<v-gravatar v-else :email="post.email" class="mini thumbnail rounded image rounded-circle z-depth-1-half"/>
</div>
<!-- Excerpt -->
<div class="col-md-9 excerpt">
...
<!-- Feed footer -->
<div class="feed-footer row">
<div class="small"> {{ post.created_at | timeAgo }}</div>
<button type="button" flat color="green" #click="showModal('ModalReplyForm')">
<i class="fa fa-reply" ></i>
...
<div v-show="postOwner(post)" class="">
<button type="button" flat color="grey" #click="deletePost(post.id)">
<i class="fa fa-trash " ></i>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
import PostsService from '../../services/PostsService'
import RepliesService from '../../services/RepliesService'
import Replies from '#/components/Reply/Replies'
import ReplyForm from '#/components/Reply/ReplyForm'
export default {
name: "Post",
props: {
post: {
type: Object,
required: true
}
},
components: {
Replies,
ReplyForm
},
computed: {
me() {
return this.$store.getters.user
}
},
methods: {
...mapMutations(['showModal']),
...
}
};
</script>
AppModal.vue - generic Modal component
<template>
<div class="c-appModal">
<div class="c-appModal__overlay" v-if="visible"></div>
<div class="c-appModal__content" v-if="visible" #click.self="hideModal"></div>
<div class="c-appModal__innerContent">
<component :is="component"></component>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import { mapState, mapMutations } from 'vuex';
export default {
name: 'AppModal',
data() {
return {
component: null
}
},
computed: {
...mapState({
visible: 'modalVisible',
modalComponent: 'modalComponent'
}),
},
methods: {
...mapMutations(['hideModal'])
},
watch: {
modalComponent(componentName) {
if (!componentName) return;
Vue.component(componentName, () => import(`#/components/modals/${componentName}`));
this.component = componentName;
}
},
created() {
const escapeHandler = (e) => {
if (e.key === 'Escape' && this.visible) {
this.hideModal();
}
};
document.addEventListener('keydown', escapeHandler);
this.$once('hook:destroyed', () => {
document.removeEventListener('keydown', escapeHandler);
});
},
};
</script>
ModalReplyForm - specific reply modal content
<template>
<div>
<div class="c-modalReply">
<div>
<label for="reply">Your comment</label>
<div class="field">
<textarea name="reply" v-model="reply" rows="2" placeholder="Compose reply"></textarea>
</div>
</div>
<button class="c-modalReply__cancel" #click="hideModal">Cancel</button>
<button class="c-modalReply__post" :disabled="!isFormValid" #click="createReply">Reply</button>
</div>
</div>
</template>
<script>
import RepliesService from '#/services/RepliesService'
import { mapMutations } from 'vuex';
export default {
name: "ModalReplyForm",
// props: {
// post: {
// type: Object,
// required: true
// }
// },
data() {
return {
reply: ""
};
},
computed: {
isFormValid() {
return !!this.reply;
},
currentGroup() {
return this.$store.getters.currentPost;
}
},
methods: {
...mapMutations([
'hideModal'
]),
async createReply () {
let result = await RepliesService.addReply({
reply: {
body: this.reply,
postId: this.post.id
}
});
this.$emit("reply-created");
this.hideModal();
}
}
};
</script>
Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
This message says that you never imported/defined ModalReplyForm, which you have not.
In my own generic modal, I ended up having to import all the components that might appear within the modal itself.
If you add a:
import ModalReportForm from ...
and a:
components: {
ModalReplyForm
}
to AppModal.vue, the modal should then do what you expect.

The component template do not shows up, it render to the `<!---->`

I have a forget-pwd.vue component:
<template>
<div class="page-common">
ABC
</div>
</template>
<script>
</script>
<style scoped>
</style>
in the router.js, there is my route:
export const paths = {
home: '/',
dataCenter: '/data-center',
forgetPassword: '/forget-password',
}
export const app_routes = [
......
{
path: paths.forgetPassword,
name: '忘记密码',
meta: {
title: ''
},
component: (resolve) => require(['./views/忘记密码/forget-pwd.vue'], resolve)
},
];
export const routes = [
...app_routes,
];
this is my index.vue:
<template>
<div class="index">
<i-header ></i-header>
<router-view></router-view>
<i-footer></i-footer>
</div>
</template>
<script>
import Home from './首页/home.vue'
import Header from '../components/header/header.vue'
import Footer from '../components/footer/footer.vue'
export default {
data() {
return {
}
},
methods: {
},
components: {
'home': Home,
'i-header': Header,
'i-footer': Footer,
}
};
</script>
<style scoped>
.index {
}
</style>
in a modal of my header.vue I link to the forget-pwd.vue:
<router-link class="forget-pwd" type="text" to="forgetPwdPath" #click.native="closeModal" >忘记密码?</router-link>
the route is skipped, but the forget-pwd.vue template do not shows up:
You forgot to bind the to in your router link. So bind it:
<router-link class="forget-pwd" type="text" :to="forgetPwdPath" #click.native="closeModal" >忘记密码?</router-link>
Or
<router-link class="forget-pwd" type="text" v-bind:to="forgetPwdPath" #click.native="closeModal" >忘记密码?</router-link>