2

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>
6
  • Don't name the prop and the computed the same name. I expect that is the cause of your this.$emit is not a function issue. Commented Mar 26, 2017 at 22:31
  • Why not just specify a data value and use that instead of a prop? It seems like that's an internal value and not a property. Commented Mar 26, 2017 at 22:36
  • Thanks I changed that but it had no effect Commented Mar 26, 2017 at 22:36
  • Derp. I missed the callback. You need to call your function properly. I'll add an answer. Commented Mar 26, 2017 at 22:39
  • I tried using a prop, and the internalValue method you did on the other question didn't work here because redactor add new HTML into the dom so I can't use an event in the template because that html is not present into template. Thats why I am trying to get the HTML via the computed property and send it to the prop. Commented Mar 26, 2017 at 22:39

4 Answers 4

3

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));
    }
};
Sign up to request clarification or add additional context in comments.

9 Comments

Your work is magnificent as usual. Thanks heaps!!! I had no idea about using bind inside the function.
Well, there are a number of ways to use the right this, that is just one. See this documentation. stackoverflow.com/documentation/vue.js/9350/…
Are you wanting to use v-model on this component? Is that way you wanted to $emit redactorValue?
I wanted to go the v-model route but then I couldn't find a way because the html I need to put it on is not in the template. BTW it has stopped working since you update the answer to use refs and el
I'll back those out. Ideally you would want to use those instead of jQuery. I just don't have something to play with to make sure it works.
|
1

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>

Comments

1

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

Comments

0

FOR ANYONE WANTS TO DO EVENTS IN OTHER WAY

Even if You wanted to use $emit there There is another way by using EventBus Just create a event-bus.js file and write this

import Vue from 'vue';
const EventBus  = new Vue();
export default EventBus;

after it import it in your components

import EventBus from '/your path/event-bus.js';

and then You can Emit it

EventBus.emit('myevent','I am boy');

to receive it you don't have to specify the event name on receiving components prop

You simply can do this

EventBus.on('myevent',value=>{
console.log(value) // I am boy will be displayed
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.