vue.js get innerhtml from contenteditable element on input - contenteditable

I'm trying to bind a vue.js event to detect a change on an element via contenteditable=true.
<div id="test" contenteditable="true" v-on-input="trigger" v-model="test"></div>
This triggers the trigger method in my vue.js vue, but I can't seem to grab the model value.
Does anyone know how I can grab the innerHTML/innerText after the input event?

Okay short description:
Template:
<div contenteditable="true"
v-html="myHtmlCode"
#input="onDivInput($event)">
</div>
Script:
methods: {
onDivInput: function(e) {
this.myHtmlCode = e.target.innerHTML;
console.log('Text: %o', this.myHtmlCode );
},
},

Solved it by using event.target.innerText in my vue.js component

export default {
data() {
return {
content: null
}
},
methods: {
onFocusOut: function(e) {
this.content = e.target.innerHTML
}
}
}
<div contenteditable="true" v-html="content" #focusout="onFocusOut($event)"></div>

one line only
use #blur instead of #input
<div contenteditable="true" #blur="test = $event.target.innerText">{{test}}</div>

Related

Vue stored valued through props not being reactive

So I pass value using [props] and stored it in child component's data. However, when passing [props] value changes from parent, it's not updating in child component's data. Is there a fix for this..?
Here is the link to w3 test (I tried to clarify the problem as much as possible here)
<div id='app'>
<div id='parent'>
<button #click='current_value()'>Click to see parent value</button>
<br><br>
<button #click='change_value($event)'>{{ txt }}</button>
<br><br>
<child-comp :test-prop='passing_data'></child-comp>
</div>
<br><br>
<center><code>As you can see, this methods is <b>NOT</b> reactive!</code></center>
</div>
<script>
new Vue({
el: "#parent",
data: {
passing_data: 'Value',
txt: 'Click to change value'
},
methods: {
current_value(){
alert(this.passing_data);
},
change_value(e){
this.passing_data = 'New Vaule!!';
this.txt = 'Now click above button again to see new value';
e.target.style.backgroundColor = 'red';
e.target.style.color = 'white';
}
},
components: {
"child-comp": {
template: `
<button #click='test()'>Click here to see child (stored) value</button>
`,
props: ['test-prop'],
data(){
return {
stored_data: this.testProp
}
},
methods: {
test(){
alert(this.stored_data);
}
},
watch: {
stored_data(){
this.stored_data = this.testProp;
}
}
}
}
});
Props have one way data flow, that's why it doesn't react when you update it from the parent component. Define a clone of your prop at data to make it reactive, and then you can change the value within the child component.
Short answer: you don't need stored_data. Use alert(this.testProp) directly.
Long answer: when child component is created, stored_data get it's value from this.testProp. But data is local, it won't change automatically. That's why you need to watch testProp and set it again. But is not working because of a simple mistake, your watch should be:
watch: {
testProp(){ // here was the mistake
this.stored_data = this.testProp;
}
}

how to access refs in methods in vuejs

I want to access template ref in functions inside method objects. Currently, it throws undefined when accessing the refs.
My Code Below:
<template>
<ul ref="lvl1_target" style="width: 440px" class="lvl1_target milestone_asset_data">
<li :style="{'width': getMileStonePercent(4,'lvl1_target')}" class="hybse_data">
<span></span>
<i></i>
<small>$4M</small>
</li>
</ul>
</template>
And My Code in Script tag is below:
export default {
methods: {
getMileStonePercent(num, secWrp) {
let ele = this.$refs[secWrp]
return ele.offsetWidth + '%'
},
},
created() {},
}
Kindly, provide solution to get the width by accessing the template reference in my function. Thanks in advance.
You need to add a ref attribute to the element you want to target.
I'm not really sure what exactly you are trying to do so here is a generic example instead:
<template>
<div ref="myElement"></div>
</template>
export default {
methods: {
setText() {
this.$refs.myElement.innerHTML = "Hello world"
},
},
}
Vue ref documentation
You can try
export default {
methods: {
this.$next(tick() => {
setText() {
this.$refs.myElement.innerHTML = "Hello world"
}
})
}}

Does kendo grid vue wrapper supports vue column template

I am using vue kendo grid but whenever i use a column template i need to go with html and jquery if there are any method call instead can i use vue template for the column just like row template?.
Yes check this more informations in the forum post
Set a template to a column
<kendo-grid-column :template="itemTemplate"></kendo-grid-column>
Reference to vue file
import Template from "./Template.vue";
var itemTemplate = Vue.component(Template.name, Template);
and
export default {
...
methods: {
itemTemplate: function(e) {
return {
template: itemTemplate,
templateArgs: e
};
}
},
Example of a template
<template>
<span>
<a role='button' class='k-button k-button-icontext filter-clear' href='\\#' #click="buttonClick">
<span class='k-icon k-i-filter-clear'></span>
open
</a>
</span>
</template>
<script>
export default {
name: "template1",
methods: {
buttonClick: function(e) {
alert("Button click");
}
},
data() {
return {
templateArgs: {}
};
}
};
</script>

Why is my computed property not computing?

Below is a single-file Vue.js template. The note object is passed to the template as a prop, and includes audio_length and id.
<template>
<span v-show="note.audio_length > 0" class="audio-element-wrapper">
<audio controls preload="none">
<source :src="audioURL" type="audio/webm">
Your browser does not support the audio element.
</audio>
<span>
({{note.audio_length}}s)
</span>
</span>
</template>
<script>
module.exports = {
mounted: function() {
console.log("mounted audioelement", this.note.id);
},
props: ['note'],
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.note.id;
}
}
};
</script>
However, when I load the component, the computed audioURL results in /notes/getAudio/undefined. Apparently, it runs before the note property is loaded. The code inside the curly braces is interpreted correctly. How can I bind the src property to the correctly computed url?
i suppose is not working because your audioURL computed value return a path without your file format.
try to change your computed:
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.id + ".webm";
}
}
For a better debug i advise you to install vue-devtools
Thanks for everyone's help. It turns out that the problem isn't really with Vuejs per se. It's a browser issue. Even though the src element was actually modified, it doesn't update the action of the element until you call .load()
So, the solution that worked was as follows:
<template>
<span v-show="note.audio_length > 0" class="audio-element-wrapper">
<audio ref="player" controls preload="none">
<source :src="audioURL" type="audio/webm">
Your browser does not support the audio element.
</audio>
<span>
</template>
And then, in the scripts:
updated: function() {
this.audioURL = "/notes/getAudio/" + this.note.id;
this.$refs.player.load();
},
Solution 1 (vue 2.x)
If you want to pass the object properties as a props then you have to use v-bind directive, see the docs here.
I suppose in your parent component you have something like that for data property:
data: function () {
return {
note: {
audio_lenght: 100,
id: 12
}
}
Then write your component as:
<your-component v-bind='note'></your-component>
And in YourComponent.vue:
...
props: ['id', 'audio_lenght']
...
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.id;
}
}
Solution 2
Write your component as:
<your-component :note='note'></your-component>
In YourComponent.vue:
props: {
note: {
type: Object
}
},
computed: {
audioURL: function() {
return "/notes/getAudio/" + this.note.id;
}
}

Handle Bootstrap modal hide event in Vue JS

Is there a decent way in Vue (2) to handle a Bootstrap (3) modal hide-event?
I found this as a JQuery way but I can't figure out how to capture this event in Vue:
$('#myModal').on('hidden.bs.modal', function () {
// do something…
})
Adding something like v-on:hide.bs.modal="alert('hide') doesn't seem to work.
Bootstrap uses JQuery to trigger the custom event hidden.bs.modal so it is not easily caught by Vue (which I believe uses native events under the hood).
Since you have to have JQuery on a the page to use Bootstrap's native modal, just use JQuery to catch it. Assuming you add a ref="vuemodal" to your Bootstrap modal you can do something like this.
new Vue({
el:"#app",
data:{
},
methods:{
doSomethingOnHidden(){
//do something
}
},
mounted(){
$(this.$refs.vuemodal).on("hidden.bs.modal", this.doSomethingOnHidden)
}
})
Working example.
Please see https://bootstrap-vue.js.org/docs/components/modal#overview
There you can find event "hide" or "hidden"
So you can bind this event:
<b-modal ref="someModal" #hide="doSometing">
One option is to tie it to a variable:
data: function(){
return {
showModal: false
//starts as false. Set as true when modal opens. Set as false on close, which triggers the watch function.
},
watch: {
showModal: function(){
if(this.showModal == false){
// do something
},
}
HTML
<button id="show-modal" #click="showModal = true">Show Modal</button>
//later if using a component
<modal v-if="showModal" #close="showModal = false">
// or alternatively in the bootstrap structure
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" #click="showModal = false">Close</button>
</div>
This may be late but another way if you are using a custom modal component (Modal.vue) you have created is to
create a method in mounted to catch the event of closure (doesn't have to be the same name as below)
mounted: function(){
this.triggerHidden();
}
create the method
methods: {
triggerHidden: function(){
var self = this;
if( $('#getModal').length ){
$('#getModal').on('hidden.bs.modal', function(){
//catch the native bootstrap close event and trigger yours
self.#emit('modal-close');
});
}
}
}
now call use your custom event with your custom/reusable modal component
<custom-modal #modal-close="doSomething"></custom-modal>
The method doSomething will be called when the modal closes. You can also use the approach to hijack the other jquery event so its a little more manageable.
Maybe creating a Custom Vue Directive can help:
Vue.directive('bsevent', {
bind: function bsEventCreate(el, binding, vnode) {
let method = binding.value || (() => { });
$(el).on(binding.arg.replaceAll(/_/g, "."), (event) => { method(event); });
},
unbind(el, binding) {
$(el).off(binding.arg.replace(/_/, "."));
},
});
And then just use it on the element you wish (this example is on a bootstrap collapsible, but you could use it to any other bootstrap event):
<div id="myCollapsible" class="collapse" v-bsevent:hidden_bs_collapse="methodToCall">
...
</div>
The only thing to remember is to register the event with underscores instead of dots (show.bs.modal => show_bs_modal).
If working with bootstrap-vue then below code snippet will be helpful:
export default {
mounted() {
this.$root.$on('bv::modal::hide', (bvEvent, modalId) => {
console.log('Modal is about to be shown', bvEvent, modalId)
})
}
}
for other events please refer to the official docs.
Just use native addEventListener (Vue 3, Composition API)
template:
<div ref="modalElement" class="modal">
...
</div>
script:
import { Modal } from "bootstrap"
import { onMounted, ref } from "vue";
const modalElement = ref(null)
let modal = null;
onMounted(() => {
modal = new Modal(modalElement.value)
modalElement.value.addEventListener("hidden.bs.modal", onHidden)
})
function onHidden() {
// do something…
}
We can also use this simple approach like this example
<template>
<div>
<button #click="openModal = true">Open Modal</button>
<div v-if="openModal">
<div class="modal-background"></div>
<div class="modal-content">
<button #click="openModal = false">Close Modal</button>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
openModal: false
}
}
}
</script>