I have added the jquery redactor plugin in a vue component. The plugin is working fine but I need to access the html so I can see it in Vue.
I have tried everything I can think of, methods, computed properties but I can't find a way. It's particularly tricky because Redactor adds new html into the dom, and I need to get the data from the added html.
Currently I am getting this error, this.$emit is not a function
. I need to get the html value of .redactor-editor
into the prop so it will be available in the vue data. The var textContent
prints out correctly in console but I can't get that to show in the prop
. Any help is greatly appreciated.
Component
<template>
<div>
<textarea class="form-control question-create-editor" id="question_description" placeholder="Go wild with all the details here - make image upload work" rows="3">
</div>
</template>
<script>
export default {
props: ['redactorValue'],
mounted: function(){
$('#question-create-form .question-create-editor').redactor({
imageUpload:'/urlGoesHereBro/',
plugins: ['video', 'imagemanager', 'counter', 'limiter'],
buttonsHide:['html', 'formatting', 'deleted', 'indent', 'outdent', 'alignment', 'horizontalrule']
});
},
computed: {
redactorValue: function(){
$('#question-create-form .redactor-editor').on('keyup', function(){
var textContent = $('#question-create-form .redactor-editor').html();
console.log( 'textContent = ' + textContent );
this.$emit('redactorValue', textContent);
});
}
}
};
HTML
<vueredactor></vueredactor>
The this.$emit is not a function
issue is because this
is pointing to the window
.
Also I moved the keyup
definition into mounted
.
export default {
data(){
return {
redactorValue: null
}
},
mounted: function(){
$('#question-create-form .question-create-editor').redactor({
imageUpload:'/urlGoesHereBro/',
plugins: ['video', 'imagemanager', 'counter', 'limiter'],
buttonsHide:['html', 'formatting', 'deleted', 'indent', 'outdent', 'alignment', 'horizontalrule']
});
$('#question-create-form .redactor-editor').on('keyup', function(){
this.redactorValue = $('#question-create-form .redactor-editor').html();
}.bind(this));
}
};
Just to add to @BertEvans superb answer. Here is a solution that adds props and v-model back into the mix. This allows you to get the redactor content as a value and have access to that data in the root.
Component
<template>
<div>
<textarea class="form-control question-create-editor" id="question_description" placeholder="Go wild with all the details here - make image upload work" rows="3">
</div>
</template>
<script>
export default {
props: ['value'],
data(){
return {
redactorValue: null
}
},
mounted: function(){
$('#question-create-form .question-create-editor').redactor({
imageUpload:'/urlGoesHereBro/',
plugins: ['video', 'imagemanager', 'counter', 'limiter'],
buttonsHide:['html', 'formatting', 'deleted', 'indent', 'outdent', 'alignment', 'horizontalrule']
});
$('#question-create-form .redactor-editor').on('blur', function(){
this.redactorValue = $('#question-create-form .redactor-editor').html();
this.$emit('input', this.redactorValue);
}.bind(this));
}
};
</script>
JS
Vue.component('vueredactor', require('./components/redactor.vue'));
var App = new Vue({
el: '#app',
data: {
redactorContent: null
}
});
HTML
<div id="app>
<vueredactor v-model="redactorContent"></vueredactor>
</div>
Here my working VueJS 2 component with Redactor Editor 3 from Imperavi.
Support multi-editor in same view, but editor need unique name/id.
Not require jQuery library.
RedactorEditor.vue
<template>
<div class="redactor">
<textarea ref="redactorContainer" :id="id" :value="value"></textarea>
</div>
</template>
<script>
import 'addons/redactor/css/redactor.css'
import 'addons/redactor/redactor'
//import 'addons/redactor/plugins/wordslimiter/wordslimiter'
//import 'addons/redactor/plugins/beyondgrammar/beyondgrammar'
export default {
name: 'redactor-editor',
props: {
value: {
required: true,
twoWay: true
},
id: {
type: String,
default: 'editor'
},
minHeight: {
type: String,
default: '300px',
},
maxHeight: {
type: String,
default: '800px',
},
buttons: {
type: Array,
default: () => ['html', 'format', 'bold', 'italic', 'deleted', 'lists', 'link']
},
plugins: {
type: Array,
default: () => []
},
wordslimiter: {
type: Number,
default: 0
},
beyondgrammarSettings: {
type: Object,
default: null
}
},
data () {
return {
propValue: this.value
}
},
created () {
this.isChanging = false;
this.app = null;
},
mounted () {
var me = this;
this.app = $R(this.$refs.redactorContainer, {
style: true,
breakline: false,
shortcodes: false,
pasteClean: true,
autoparseImages: false,
autoparseVideo: false,
multipleUpload: false,
clipboardUpload: false,
pasteLinkTarget: '_blank',
placeholder: 'Write your text here ...',
minHeight: this.minHeight,
maxHeight: this.maxHeight,
buttons: this.buttons,
plugins: this.plugins,
wordslimiter: this.wordslimiter,
beyondgrammar: this.beyondgrammarSettings,
callbacks: {
start: function() {
// set initial data
this.source.setCode(me.propValue);
},
blur: function (e) {
// keyup not work with last typed text, fix sync with v-model by using blur
if (!me.isChanging) {
me.isChanging = true;
var code = this.source.getCode()
me.propValue = (code === null || code.length === 0 ? null : code);
me.$emit('input', me.propValue);
me.$nextTick(function() {
me.isChanging = false;
});
}
}
}
})
},
destroyed () {
this.app = $R(this.$refs.redactorContainer)
if (this.app) {
this.app.destroy()
}
}
};
</script>
App.vue
import Vue from 'vue'
import RedactorEditor from './components/RedactorEditor.vue'
// app
const app = new Vue({
el: '#my-app',
data: {
editorButtons: ['undo', 'redo', 'bold', 'italic', 'lists', 'link'],
editorPlugins: [],
beyondgrammarSettings: {}
editorHTMLContent: '',
},
components: {
RedactorEditor
}
}
HTML usage
<redactor-editor
v-model="editorHTMLContent"
:text-value="editorHTMLContent"
:id="'editor_1"
:name="'editor_1"
:plugins="editorPlugins"
:buttons="editorButtons"
></redactor-editor>
Example with custom Validator using vee-validate: https://gist.github.com/matinfo/52214f7f34ce6b746b483f0f92e6b5e5