Make content editable div get focus on button click - javascript

I have a content editable div that I'm using to retrieve some data.
<div contenteditable="true" ref="test">/*SomeText*/</div>
After running the focus through the ref with this.$refs.test.focus(). It didn't work and I get an error on the console (Cannot read properties of undefined reading focus)
How can I trigger a focus effect on content editable div?

The attribute for content editable should not be content-editable="true", but instead contenteditable="true".
const App = {
el: '#app',
methods: {
focusDiv() {
this.$refs.test.focus()
}
}
}
const app = new Vue(App)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div contenteditable="true" ref="test">My Div</div>
<button #click="focusDiv">Focus on div</button>
</div>

Related

How can DOM manipulation like wrapping text in a paragraph element be achieved using only Vue.js?

I have a Vue component which has a contenteditable div that lets users type in a message. When the user first attempts to create a message, I am using jQuery to wrap the text in a <p> tag. I cannot understand how this could be achieved using Vue.js alone...
Vue.js component
<template>
<div id="Message" contenteditable="true" #focus="formatMessage" #keydown="formatMessage" #keyup="formatMessage" #keypress="formatMessage">
</div>
</template>
<script>
import $ from 'jquery'
formatMessage: function(event) {
if ($("#Message > p").length === 0) { // if no <p> element when user interacts with div
$("#Message").contents().eq(0).wrap("<p />"); // then wrap a <p> tag around the first child content
}
}
Is it possible to do this using just Vue.js so I don't have to load the jQuery library for simple DOM manipulation (which may cause an issue with Vue's virtual DOM being out-of-sync with jQuery's changes)?
Before formatMessage():
<div id="Message" contenteditable="true">
I started typing here
</div>
After formatMessage():
<div id="Message" contenteditable="true">
<p>I started typing here</p>
</div>
Is it possible/better to try to do it using Vue's virtual DOM? Could I somehow use createElement to create a new p tag and then update its contents with what the user is typing? Maybe thats not the way the Virtual DOM works I'm not sure.
You can use v-if and duplicate the code a little if you want to achieve something similar
<template>
<div v-if="shouldWrap === false" contenteditable="true" #focus="formatMessage" #keydown="formatMessage" #keyup="formatMessage" #keypress="formatMessage">
</div>
<p v-else>
<div contenteditable="true" #focus="formatMessage" #keydown="formatMessage" #keyup="formatMessage" #keypress="formatMessage">
</div>
</p>
</template>
<script>
export default {
data () {
return {
shouldWrap: false
}
},
methods: {
formatMessage() {
this.shouldWrap = true
}
}
}
</script>
But probably trying to match the styling of a p should also work.
Do not use JQuery-like DOM manipulation in VUE, VUE is data driven framework, you need to store some data in component to trigger layout, for example
<template>
<div contenteditable="true" #focus="formatMessage" #keydown="formatMessage" #keyup="formatMessage" #keypress="formatMessage">
<!-- wrap 'p' tag, if 'shouldWrap'-->
<p v-if="shouldWrap">{{content}}</p>
<!-- without wrap-->
<template v-else>{{content}}</template>
</div>
</template>
<script>
export default {
data () {
return {
shouldWrap: false,
content:'' // text, you want to display inside div
}
},
methods: {
formatMessage() {
this.shouldWrap = true
}
}
}
</script>

get dom from content in vuejs

let say i have some divs in my page :
<div id="root">
<div id="content1" v-html="content"></div>
<div id="content2"></div>
<div id="content3"></div>
</div>
and i write script :
cont myapp = new Vue({
el:'#root'
,data:{'content':''}
,methods{
get_content_dom:function(){
return document.getElementById('id_from_content');
}
}
})
how to set method get_content_dom to find the dom where html content is attached,
because maybe sometime i want to move the html content to #content1 or #content2 or #content3.
any way to set the method to get the dom of html content?
=========================================================================
my point exactly is i need to know the dom when click event :
let say i have some divs in my page :
<div id="root">
<div id="content1"></div>
<div id="content2" v-click="fired"></div>
<div id="content3"></div>
</div>
and i write script :
cont myapp = new Vue({
el:'#root'
,data:{'content':''}
,methods{
fired:function(){
console.log('here is my dom and i can get current div id #content2');
}
}
})
I wouldn't recommend using the DOM to control content. Instead, drive the content with your data
data: () => ({
contents: ['content 1', 'content 2', 'content 3']
}),
methods: {
fired (event, content, index) {
console.log('Click event on DOM element', e.target)
console.log('Click event on content index', index)
console.log('Click event on content', content)
}
}
<div id="root">
<div v-for="(content, index) in contents"
:id="`content${index + 1}`"
:key="index"
#click="fired($event, content, index)"
v-html="content"></div>
</div>

Jquery toggle sidebar with 2 buttons

I am trying to create a toggle on a sidebar so that the toggle button opens the sidebar. This works great on desktop, however, if I am using mobile, the toggle button gets hidden. Is it possible to add a close button in the sidebar which can close the sidebar without breaking the script? The script I have is:
<div id="sidebar">content</div>
<div id="filter-icon">Refine Selection <div id="filterswitch"></div></div>
<script>
jQuery(document).ready(function() {
jQuery("#filter-icon").click(function() {
jQuery("#filterswitch").toggleClass('active');
jQuery("#sidebar").toggleClass('show-sidebar');
});
});
</script>
Shouldn't be a problem, have you tried something like this?
<div id="sidebar"><button id="closeSidebar">Close</button></div>
<div id="filter-icon">Refine Selection <div id="filterswitch"></div></div>
<script>
const toggleSidebarAndSwitch = () => {
jQuery("#filterswitch").toggleClass('active');
jQuery("#sidebar").toggleClass('show-sidebar');
}
jQuery(document).ready(() => {
jQuery("#filter-icon").click(() => {
toggleSidebarAndSwitch()
});
jQuery("#closeSidebar").click(()=>{
toggleSidebarAndSwitch()
})
});
</script>
Yes it's possible just add another div in your sidebar like this:
<div id="sidebar">
content
<div class="filterswitch"></div>
</div>
<div id="filter-icon">
Refine Selection
<div class="filterswitch"></div>
</div>
If you ad the class filterswitch to both div's jQuery will automatically listen for clicks on both elements.

Vue.js select closest div with certain classname

I have the following HTML markup:
<div id="app">
<div class="image">
<div class="overlay">
<p>Some overlay text</p>
</div>
<img src="https://placeimg.com/640/480/any" class="img-fluid">
</div>
<div class="info">
<h6 class="name">Title here</h6>
<p class="meta">Meta here</p>
</div>
<div class="info-button" #mouseover="addParentClass" #mouseout="removeParentClass">
Mouse over here!
</div>
What I would like to do is whenever someone hovers over the div with class "info-button" certain classes get added to the image above and the overlay.
I have got it working with the following Vue.js markup:
let vm = new Vue({
el: "#app",
data:{
isHovering: false
},
methods: {
addParentClass (event) {
event.target.parentElement.children[0].children[1].classList.add('active')
event.target.parentElement.children[0].children[0].classList.add('overlay-active')
},
removeParentClass (event) {
event.target.parentElement.children[0].children[1].classList.remove('active')
event.target.parentElement.children[0].children[0].classList.remove('overlay-active')
},
},
})
However it seems like a lot of redundant JS. I have tried to get it working with:
event.target.parent.closest('.overlay'.).classList.add('overlay-active')
And a lot of similar parent/children/closest selectors, however I can not seem to get the result I want. How can I get the "closest" selector to work here?
Here's a codepen with a very rough working example: Link to codepen
Edit: I want to point out that i want to use this in a loop, so I will have mulitple images and I want to make the overlay only appear on the current image.
VueJS is reactive. This means the data should drive the DOM. You should not play with the DOM yourself.
Add an active property to data;
let vm = new Vue({
el: "#app",
data:{
isHovering: false,
active: false
},
methods: {
addParentClass (event) {
this.active = true;
},
removeParentClass (event) {
this.active = false; },
},
})
And make the DOM reactive by;
<div class="overlay" :class="{'overlay-active': active}" >
<p>Some overlay text</p>
</div>
Here is the updated codepen
https://codepen.io/samialtundag/pen/Jeqooq

How make one way binding for element which changed by any action(which made not by user) in vue.js

I try to use vue.js for creating Interactive preview of my form.
But i haven't custom element for loading image and creating preview for them. I need to bind my hidden input, which changed by handler function to image.
It's my hidden image, which hold base64 form of the loaded image
input(type="text" name="logotype" v-model="brandLogo" style="display: none;")#image-attach
My preview element
img(src="{{brandLogo}}")
Some vue.js setting
var Brand = new Vue({
el: '#brand',
data: {
brandName: 'title of form',
brandDesc: 'decription of form',
brandLogo: 'img/logo.png',
brandColorBg: '#2c6aa2',
brandColorText: '#fff'
}
});
But after changed value form of my hidden input element, don't happen to change of my data in Vue.
I suggest, that v-model change element after some action as (typing text in input) but how to observer another actions, which can to apply to elements?
First make sure the input and the preview part are within(inside) the brand div
This is working perfect. When i enter the path on input it automaticall update the image.
<div id="app">
<input type="text" v-model='image.path'>
<div>
<img :src="image.path" width="100" height="100">
</div>
<pre> {{ $data | json}}</pre>
</div>
<script src="vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
image:{
'name':'',
'path':''
}
}
});
</script>
</body>
</html>

Categories