I am using VueJS and trying to fire a mouseover event on two elements, one a child element of the other.
I am unable to get the child mouseover event to fire. It appears the parent element is "covering" the child div and only the parent mouseover event is registered.
var vm = new Vue({
el: '#app',
data: {
hoverTarget: 'none'
},
methods: {
parentHover: function() {
this.hoverTarget = 'parent'
},
childHover: function() {
this.hoverTarget = 'child'
}
}
});
#parent {
width: 100px;
height: 100px;
background: #000000;
}
#child {
width: 50px;
height: 50px;
background: #FFFFFF;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id='app'>
<div id='parent' #mouseover="parentHover">
<div id='child' #mouseover="childHover">
</div>
</div>
{{ hoverTarget }}
</div>
Additionally, you could abbreviate this, using an event modifier, to #mouseover.stop="childHover".
<div id='app'>
<div id='parent' #mouseover="parentHover">
<div id='child' #mouseover="childHover">
</div>
</div>
{{ hoverTarget }}
</div>
This is happening because of the event bubbling principal
When an event happens on an element, it first runs the handlers on it,
then on its parent, then all the way up on other ancestors.
that means childHover handler will get executed and immediately after it
the parentHover will be executed making the child execution invisible.
to solve your problem you can use event.stopPropagation() method of the event to make sure no bubbling happens from child to parent.
var vm = new Vue({
el: '#app',
data: {
hoverTarget: 'none'
},
methods: {
parentHover: function() {
this.hoverTarget = 'parent'
},
childHover: function(event) {
event.stopPropagation()
this.hoverTarget = 'child'
}
}
});
Related
Long story short, Vue requires some trickery when debugging height and #scroll issues within componenets. The best call of action is to find what element is scrolling and move the scroll to the child, in my case.
So, how can I find what element is scrolling without countless additions/removals of event listeners?
You can get the element that you're scrolling on through the scroll event that gets passed to the scroll handler with event.target. I've included a snippet below which should hopefully help your case scenario.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
methods: {
scrollHandler(ev) {
console.log(ev.target.id);
}
}
});
#app > div > div {
height: 200px;
overflow-y: scroll;
max-height: 100px;
display:block;
}
h1 {
font-size: 3rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<div :id="i" v-for="i in 5" :key="i" #scroll="scrollHandler">
<h1>{{i}}</h1>
</div>
</div>
</div>
I have some html that renders these little boxes:
<div class="token-checkboxes">
<span class="checkbox-span" v-for="token_obj in token_to_vue_obj">
<input v-on:change="plot()" type="checkbox" id="checkbox" v-model="token_obj.show">
<label for="checkbox">{{ token_obj.token }}</label>
</span>
</div>
I want the effect from clicking on the outer pill element (the grey background area) to be the same as the effect from clicking on the checkbox itself. Is there a simple way to "forward" an event on a parent element to a child or something like that?
You can add an event listener on the outer pill element to change the model value. This isn't really forwarding an event but it should have the same effect (clicking the pill toggles the checkbox).
<span class="checkbox-span"
v-for="token_obj in token_to_vue_obj"
v-on:click="token_obj.show = !token_obj.show; plot()">
Edit (see comments): Remove plot() from the <input> element's change handler to prevent the plot() function being called twice if you click the checkbox.
Check out the snippet below.
var app = new Vue({
el: '.token-checkboxes',
methods: {
plot() {
console.log('Plot called!');
}
},
data: {
token_to_vue_obj: [
{ token: '_#misc', show: true },
{ token: '_#study', show: true },
{ token: '_#code', show: true },
{ token: '_#debug', show: true },
{ token: '_data', show: false }
]
}
})
.checkbox-span {
background-color: lightgrey;
padding: 0.5em;
border-radius: 0.5em;
border: 2px solid black;
margin: 0.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="token-checkboxes">
<span class="checkbox-span"
v-for="token_obj in token_to_vue_obj"
v-on:click="token_obj.show = !token_obj.show;plot()"
v-bind:key="token_obj.token">
<input type="checkbox" class="checkbox" v-model="token_obj.show">
<label for="checkbox">{{ token_obj.token }}</label>
</span>
</div>
Edit: see comment below. The non-unique id="checkbox" causes problems.
I have a div and a file input box. When we click on the div, the click of file input is to be triggered. How to do this in vue.js?
You will have to access the DOM to trigger the click event for the input.
But Vue can make it pretty convenient with the ref/$refs feature
With it, you can "mark" an element in the template and access it conveniently from within your component's code without relying on selectors.
new Vue({
el: '#app',
methods: {
clickHandler() {
this.$refs.fileInput.click()
}
}
})
.button {
padding: 10px;
border-radius: 5px;
border: 1px solid #CCC;
display: inline-block;
}
<script src="https://unpkg.com/vue#2.3/dist/vue.js"></script>
<div id="app">
<div class="button" #click="clickHandler">Click me!</div>
<input type="file" ref="fileInput">
</div>
Add a ref to you input and a click listener to your wrapper div
<div #click="triggerFileInput" id="wrapper">
<input type="file" ref="myFile">
</div>
methods:{
triggerFileInput(){
this.$refs.myFile.click();
}
}
I have function that start working when I click on parent and get parent id ( tmp ), but when I click on child my function works too but return undefind. How to get parent id doesn't matter on what I click child or parent or other elemnts in parent div ?
<div class="parent" id="tmp">
<div class="child"></div>
</div>
.parent {
width: 100px;
height: 100px;
}
.child {
width: 50px;
height: 50px;
}
'click .parent': function(e){
console.log($(e.target).attr("id")); // from MeteorJS framework , but same sense
}
In your click handler you should use this to refer to the element that is handling the event:
'click .parent': function(){
console.log(this.id);
}
By using e.target you're targeting the element which originated the event - which in the cases you describe would be the .child element which has no id attribute.
If you are unable to use the this keyword due to restrictions imposed by Meteor, you could instead use the currentTarget property on the event, as it should have the same effect:
'click .parent': function(e){
console.log(e.currentTarget.id); // or $(e.currentTarget).prop('id')
}
try:
$('.parent').click(function(){
console.log($(this).attr('id'));
//console.log($(this)[0].id)
});
or
$('.parent').click(function(e){
console.log(e.currentTarget.id);
});
or
$('.parent').click(function(e){
console.log(e.delegateTarget.id);
});
Is this what you want?
$(function() {
$('div').click(function(e) {
var id = $(e.target).parent().attr('id');
if (typeof id === 'undefined') {
//return current element as this is a parent
console.log($(e.target).attr('id'));
} else {
//return parent's id
console.log(id);
}
});
});
.parent {
width:100px;
height:100px;
background: red;
}
.child {
width:50px;
height:50px;
background: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent" id="tmp">
<div class="child">
</div>
</div>
I am trying to fire child div event but it seems that instead of child div , it is the parent div's click event that is getting fired. I tried using stopPropagation in child event but it doesnt seem to work.
$(document).ready(function() {
var lot = '<div class="divlot">This is a lot!</div>'
var lineitem = '<div class="divlineitem">This is a lineitem!</div>'
$("#container").on("click", function() {
$("#container").append(lot);
});
$(".divlot").on("click", function(e) {
e.stopPropagation();
alert($(this).attr("class"));
$(this).append(lineitem);
});
});
#container {
background-color: grey;
}
.divlot {
background-color: red;
padding-left: 20px;
}
.divlineitem {
background-color: blue;
padding-left: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">Container</div>
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the event binding call.
As of now, your are using direct event handler binding for divlot which doesn't exist in the page thus neither event handler work nor e.stopPropagation()
Since you are adding event dynamically you need to use Event Delegation using .on() delegated-events approach.
Bind event using
$("#container").on("click", ".divlot", function(e) {
e.stopPropagation();
alert($(this).attr("class"));
$(this).append(lineitem);
});
$(document).ready(function() {
var lot = '<div class="divlot">This is a lot!</div>'
var lineitem = '<div class="divlineitem">This is a lineitem!</div>'
$("#container").on("click", function() {
$("#container").append(lot);
});
$("#container").on("click", ".divlot", function(e) {
e.stopPropagation();
alert($(this).attr("class"));
$(this).append(lineitem);
});
});
#container {
background-color: grey;
}
.divlot {
background-color: red;
padding-left: 20px;
}
.divlineitem {
background-color: blue;
padding-left: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">Container</div>
You are creating the child divs dynamically. So you should use event delegation for properly binding the events.
$("#container").on("click",".divlot", function(e) {
e.stopPropagation();
alert($(this).attr("class"));
$(this).append(lineitem);
});
Fiddle