now_world
now_world

Reputation: 1106

Vue model not updating

When I try to update my custom text-area component's model data this.message='<span id="foo">bar</span> the text and html does not display in the htmltextarea tag like it should, but I can see the update applied in the Vue dev tool's console. I've also tried switching to an object instead of a string and using Vue.set, but this does not work either.

Any suggestions on how to fix this?

The goal with the htmlTextArea component is to get the users text from the htmlTextArea tag (this works), manipulate this text and bind it back to the textarea, but with HTML in it.

Custom text-area component:

<template>
  <div contenteditable="true" @input="updateHTML" class="textareaRoot"></div>
</template>
<script>
export default {
  // Custom textarea 
  name: 'htmlTextArea',
  props:['value'],
  mounted: function () {
      this.$el.innerHTML = this.value;
  },
  methods: {
      updateHTML: function(e) {
          this.$emit('input', e.target.innerHTML);
      }
  }
}
</script>

Other component:

<template>
...
<htmlTextArea id="textarea" v-model="message"></htmlTextArea>
...
</template>
<script>
      data: {
        return {
          message: 'something'//this works
        }
      }
     ...
     methods: {
      changeText() {
        this.message='<span id="foo">bar</span>'//this does not
      }
     },
     components: {
         htmlTextArea
     }
</script>

Upvotes: 10

Views: 39159

Answers (2)

Brian Lee
Brian Lee

Reputation: 18197

Change the data property into a function, as you have it defined it is not reactive.

data () {
    return {
        message: 'something'//this works 
    }
}

Now when you update the message property in your method, the component will update accordingly.

Reactivity in depth

Upvotes: 4

Jacob Goh
Jacob Goh

Reputation: 20845

You need to set the value explicitly after the value props change. you can watch for value change.

<template>
    <div contenteditable="true" @input="updateHTML" class="textareaRoot"></div>
</template>
<script>

export default {
  // Custom textarea
  name: "htmlTextArea",
  props: ["value"],
  mounted: function() {
    this.$el.innerHTML = this.value;
  },
  watch: {
      value(v) {
          this.$el.innerHTML = v;
      }
  },
  methods: {
    updateHTML: function(e) {
      this.$emit("input", e.target.innerHTML);
    }
  }
};
</script>

Upvotes: 16

Related Questions