How to reuse your Trix WYSIWYG editor with Vue?
Sheary Tan
Posted on February 13, 2020
When adding a WYSIWYG editor to your site, have you considered:
1) Which library to use?
2) How to implement one?
3) What if I have more than 2 editors I have to add?
4) Could I make them reusable?
Yes you can.
Here I am using the Trix editor from Basecamp.
Have a look at the doc and install the library before getting started!
Before making it reusable, let's quickly set the editor up first.
Getting Started
First, let's add the editor tag like what the doc has mentioned:
<template>
<div>
<input id="x" type="hidden" name="content">
<trix-editor input="x"></trix-editor>
</div>
</template>
Now you've got a nice editor. But it would be great to store the text you've typed in somewhere. Let's create a two-way binding on the form input:
<template>
<div>
<input id="x" type="hidden" name="content" v-model="trixText"> <!-- new code here -->
<trix-editor input="x"></trix-editor>
</div>
</template>
<script>
import Trix from 'trix';
export default {
data() {
return {
trixText: '' // new code here
}
}
}
</script>
Listen to the changes on the Trix editor
From the doc:
The editor emits several events which you can use to observe and respond to changes in editor state.
More of that can be found here.
Here we will be using the trix-change
listener.
<template>
<div>
<input id="x" type="hidden" name="content" v-model="trixText">>
<trix-editor input="x"></trix-editor>
</div>
</template>
<script>
export default {
data() {
return {
trixText: ''
}
},
methods: {
setTextToTrix: function() {
this.trixText = document.getElementById("x").value;
}
}
mounted() {
document.addEventListener("trix-change", this.setTextToTrix); // Listen to the changes on the editor
}
}
</script>
And remove the event listener once done.
<!-- TrixComponent.vue -->
<script>
export default {
..
mounted() {
document.addEventListener("trix-change", this.setTextToTrix);
},
beforeDestroy: function() {
document.removeEventListener("trix-change", this.setTextToTrix); // New code here
}
};
</script>
Make it reusable
So now you've got your basic editor set up! It's time to make it reusable.
The secret to make the trix-editor reusable:
The
id
on the tags
<input id="x" type="hidden" name="content" v-model="trixBody"> <!-- notice the id? -->
<trix-editor ref="trix" input="x"></trix-editor> <!-- notice the id? -->
That means we can create a unique id
for each component that is using TrixComponent.vue
.
To demonstrate this, let's have 2 components: ComponentA.vue
and ComponentB.vue
using the same editor that you just created.
And let's work on ComponentA.vue
first.
<!-- ComponentA.vue -->
<template>
<div class="component-a">
<h3>Component A</h3>
<h6>
Text:
<span v-html="textA"></span> <!-- Data received will be in HTML format -->
</h6>
<TrixComponent></TrixComponent> <!-- TrixComponent -->
</div>
</template>
<script>
import TrixComponent from "./TrixComponent";
export default {
components: {
TrixComponent
},
data() {
return {
textA: "",
};
},
methods: {
}
};
</script>
We can pass the id as props from ComponentA.vue
to TrixComponent.vue
.
<!-- ComponentA.vue -->
<template>
<div class="component-a">
<h3>Component A</h3>
<h6>
Text:
<span v-html="textA"></span>
</h6>
<TrixComponent :id="id"></TrixComponent> <!-- pass the id here -->
</div>
</template>
<script>
import TrixComponent from "./TrixComponent";
export default {
components: {
TrixComponent
},
data() {
return {
id: "A" // Here we have an id 'A'
};
},
methods: {
}
};
</script>
And we can assign the props(id)
to the the input & the trix-editor.
<!-- TrixComponent.vue -->
<template>
<div>
<input :id="id" type="hidden" name="content" v-model="trixText"> <!-- Set the id according to the props -->
<trix-editor :input="id"></trix-editor> <!-- Set the id according to the props -->
</div>
</template>
<script>
export default {
props: ["id"], // Receive the id from the parent component
data() {
return {
trixText: ""
};
},
methods: {
setTextToTrix(e) {
this.trixText = document.getElementById(this.id).value; // REMEMBER TO UPDATE THE ID HERE TOO!
},
},
mounted() {
document.addEventListener("trix-change", this.setTextToTrix);
},
beforeDestroy: function() {
document.removeEventListener("trix-change", this.setTextToTrix);
},
};
</script>
Getting data back from TrixComponent.vue
We will emit the data back from TrixComponent.vue
to its parent component, which is ComponentA.vue
<!-- TrixComponent.vue -->
<template>
<div>
<input :id="id" type="hidden" name="content" v-model="trixText">
<!-- updated here -->
<trix-editor :input="id"></trix-editor>
</div>
</template>
<script>
export default {
props: ["id"],
data() {
return {
trixText: ""
};
},
methods: {
setTextToTrix(e) {
this.trixText = document.getElementById(this.id).value;
},
emitDataBackToComponent() {
this.$emit("dataFromTrix", this.trixText); // Emit the data back to the parent component
}
},
mounted() {
document.addEventListener("trix-change", this.setTextToTrix);
},
beforeDestroy: function() {
document.removeEventListener("trix-change", this.setTextToTrix);
},
updated() {
this.emitDataBackToComponent(); // Fire the event whenever there's an update
}
};
</script>
And ComponentA.vue
will then be able to receive the data from TrixComponent.vue
<!-- ComponentA.vue -->
<template>
<div class="component-a">
<h3>Component A</h3>
<h6>
Text:
<span v-html="textA"></span>
</h6>
<TrixComponent :id="id" @dataFromTrix="getDataFromTrix"></TrixComponent> <!-- Receive the data back -->
</div>
</template>
<script>
import TrixComponent from "./TrixComponent";
export default {
components: {
TrixComponent
},
data() {
return {
textA: "",
id: "A"
};
},
methods: {
getDataFromTrix: function(data) {
this.textA = data; // Assign the data back to the the variable
}
}
};
</script>
It will be the same logic for ComponentB.vue
: just pass a different id (maybe id: 'B'
?) to TrixComponent.vue
.
That's it!
You've now created a reusable trix editor :)
Here is the code example.
Happy coding 😊
Posted on February 13, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.