I have an HTML element (form element - textbox) inside another series of divs.
I created listener for mouseup event on the outer div, but it fires when I click on the textbox.
I thought it would only fire when mouseup on the outer div since I attached the listener to that element - not to the textbox
Is there a way to prevent it from firing when 'mouseup' fires on the textbox?
require([
"dijit/form/TextBox",
"dojo/on",
"dojo/dom"
], function (
TextBox,
on,
dom) {
var box = new TextBox({
name: "any",
value: "",
placeholder: "Type anything here"
}, "textBox");
var canvas = dom.byId("outerDiv");
on(canvas, "mouseup", function (e) {
alert();
});
});
dojo.require("dijit.form.anyText");
var textBox = dijit.byId("textBox");
console.log( "--- >> "+textBox.get("value"));
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.12.1/dojo/dojo.js"></script>
<Div id="outerDiv" style="width: 3in; height: 3in; border: 1px solid;border-color:black; cursor: pointer;">
<Div id="innerDiv" style="height: auto; border: 1px solid;border-color:blue;">
<div id="textBox" readonly></div>
</Div>
</Div>
When you click the text box, the event "bubbles up" to the outer elements.
JavaScript's Event.stopPropagation() "prevents further propagation of the current event in the capturing and bubbling phases".
Below is an example in pure JavaScript, but see also dojo.stopEvent.
var outerDiv = document.getElementById('outerDiv');
var textBox = document.getElementById('textBox');
outerDiv.addEventListener('mouseup', function(event) {
console.log('mouse up on outer div');
});
textBox.addEventListener('mouseup', function(event) {
event.stopPropagation();
console.log('mouse up on text box');
});
#outerDiv {
width: 3in;
height: 3in;
border: 1px solid;
border-color: black;
cursor: pointer;
}
#innerDiv {
height: auto;
border: 1px solid;
border-color: blue;
}
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.12.1/dojo/dojo.js"></script>
<Div id="outerDiv">
<Div id="innerDiv">
<div id="textBox" readonly>textbox</div>
</Div>
</Div>
Edit
Here's a Dojo example:
require([
"dijit/form/TextBox",
"dojo/on",
"dojo/dom"
], function(
TextBox,
on,
dom) {
var box = new TextBox({
name: "any",
value: "",
placeholder: "Type anything here"
}, "textBox");
var canvas = dom.byId("outerDiv");
on(box, "mouseup", function(e) {
console.log('mouse up on text box');
dojo.stopEvent(e);
});
on(canvas, "mouseup", function(e) {
console.log('mouse up on outer div');
});
});
#outerDiv {
width: 3in;
height: 3in;
border: 1px solid;
border-color: black;
cursor: pointer;
}
#innerDiv {
height: auto;
border: 1px solid;
border-color: blue;
}
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<Div id="outerDiv">
<Div id="innerDiv">
<div id="textBox" readonly>textbox</div>
</Div>
</Div>
You can check the id before creating the alert
on(canvas, "mouseup", function (e) {
if (e.target.id == "outerDiv") {
alert();
}
});
JS Fiddle
Related
I want to implement some draggable elements on the page, which should not break the currently focused control on the page. That is what I tried:
$('input').focus();
$('div').on('mousedown', function(event) {
// event.preventDefault(); // drag does not work anymore
// $('input').focus(); // focus still lost
});
div {
display: inline-block;
border: 1px solid green;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div draggable="true">Hello World</div><br />
The input field should not loose focus, when dragging "Hello World".<br />
<input type="text" />
If I activate event.preventDefault(), the focus is not lost on mousedown, but the drag operation cannot start anymore. Does anyone know how to solve this problem?
I guess, setTimeout will solve your problem
$('input').focus();
$('div').on('mousedown', function(event) {
window.setTimeout(
function() {
$('input').focus();
}, 1);
});
div {
display: inline-block;
border: 1px solid green;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div draggable="true">Hello World</div><br />
The input field should not loose focus, when dragging "Hello World".<br />
<input type="text" />
Result;
jsfiddle
Hope helps,
$(document).ready(function(){
$("div").on("mousedown",function(event){
event.preventDefault();
$("div").draggable();
$("input").droppable({
drop: function(event, ui) {
$("input").css('background', 'rgb(0,200,0)');
}
});
});
});
div {
display: inline-block;
border: 1px solid green;
padding: 10px;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div draggable="true">Hello World</div><br />
The input field should not loose focus, when dragging "Hello World".<br />
<input type="text" />
When I drag & drop the text, nothing happens. But the same script works when I change the event to "dragenter" or "dragleave". Did I miss anything?
function handleDragDrop(e) {
console.log("Something droped");
dropStatus.innerHTML = "Something droped";
}
var dropZone = document.getElementById("dropZone");
var dropStatus = document.getElementById("dropStatus");
dropZone.addEventListener("drop", handleDragDrop);
.drop-zone {
width: 300px;
padding: 20px;
border: 2px dashed #000;
}
<div id="dropZone" class="drop-zone">Drop Zone!</div>
<div id="dropStatus"></div>
<div class="" draggable="true">DRAG ME</div>
Need to cancel the over
function handleDragDrop(e) {
console.log("Something droped");
dropStatus.innerHTML = "Something droped";
}
var dropZone = document.getElementById("dropZone");
var dropStatus = document.getElementById("dropStatus");
dropZone.addEventListener("drop", handleDragDrop);
dropZone.addEventListener("dragover", function(e) {
e.preventDefault();
return false;
});
.drop-zone {
width: 300px;
padding: 20px;
border: 2px dashed #000;
}
<div id="dropZone" class="drop-zone">Drop Zone!</div>
<div id="dropStatus"></div>
<div class="" draggable="true">DRAG ME</div>
I have a basic input[file] element which I hide. When you click on the #holder a file explorer pops up. But selecting a file triggers the console.log() line to be executed twice (on my computer).
Beware: the following code below crashes my Chrome tab.
You should better run it as a separate file. Cannot provide a "working" demo, but this is the closest I can get to MCVE.
var element = document.getElementById('holder');
element.onclick = function(e) {
var input = document.getElementById('file-input');
input.click();
input.addEventListener("change", function(evt) {
console.log(evt);
Phimij.addFiles(input.files);
}, false);
};
#holder {
border: 10px dashed #ccc;
width: 300px;
height: 300px;
margin: 20px auto;
}
#holder.hover {
border: 10px dashed #333;
}
#file-input {
display: none;
}
<div id="holder">
<input type="file" multiple id="file-input" />
</div>
click events bubble up the ancestry tree. That means a click on your input will bubble up to your #holder element and fire your click handler on it. In your click handler on #holder, you fire the click event on the input. That's why your browser crashes: You've triggered an infinite loop.
The solution is to hook click on the input and tell it not to bubble (propagate); see flagged lines (but keep reading, further notes below):
var element = document.getElementById('holder');
// **** Added vvvv
document.getElementById('file-input').addEventListener("click", function(evt) {
evt.stopPropagation();
}, false);
// *** Added ^^^^
element.onclick = function(e) {
var input = document.getElementById('file-input');
input.click();
input.addEventListener("change", function(evt) {
console.log(evt);
// Phimij.addFiles(input.files);
}, false);
};
#holder {
border: 10px dashed #ccc;
width: 300px;
height: 300px;
margin: 20px auto;
}
#holder.hover {
border: 10px dashed #333;
}
#file-input {
display: none;
}
<div id="holder">
<input type="file" multiple id="file-input" />
</div>
There are a few other things I'd change. You're adding a change handler to the input every time there's a click on #holder; you really only want to do that once. I'd also add that handler before triggering the click.
So for what it's worth, some changes I'd make:
var element = document.getElementById('holder');
var input = document.getElementById('file-input');
element.addEventListener("click", function() {
input.click();
}, false);
input.addEventListener("click", function(evt) {
evt.stopPropagation();
}, false);
input.addEventListener("change", function(evt) {
console.log(evt);
// Phimij.addFiles(input.files);
}, false);
#holder {
border: 10px dashed #ccc;
width: 300px;
height: 300px;
margin: 20px auto;
}
#holder.hover {
border: 10px dashed #333;
}
#file-input {
display: none;
}
<div id="holder">
<input type="file" multiple id="file-input" />
</div>
I'm sure this has been asked before, but I haven't had any luck finding an answer. There's probably a term for this which I don't know.
Can a jQuery event handler return an element other than the one from which it was triggered?
Normally, when you trigger a jQuery event for an element, that element will be returned by the event handler. Is there a way to return a different element instead? (other than event.target, event.currentTarget, etc.)
Here's my HTML:
<div id="content">
<div id="wrapper">
<div class="instance">
</div>
</div>
</div>
If I make a custom jQuery event for #wrapper, can I make its event handler return an .instance?
Here's my JavaScript:
$('#content').on('new.instance', '#wrapper', function(event) {
var wrapper = $(event.currentTarget);
var instance = wrapper.find('div.instance').first();
var newInstance = instance.clone(true, true);
newInstance.appendTo(wrapper);
return newInstance;
});
var returnValue = $('#wrapper').trigger('new.instance');
console.log('returnValue.html():', returnValue.html()); // #wrapper, not .instance
Can I make the new.instance event handler return an .instance element? If so, what am I missing in the code?
.trigger()
...
When we define a custom event type using the .on() method, the second argument to .trigger() can become useful.
You could simply add an object to the .trigger method as a second parameter and collect your instances in there.
var instances = {data:[]};
$('#content').on('new.instance', '#wrapper', function(event, instances) {
var wrapper = $(event.currentTarget);
var instance = wrapper.find('div.instance').first();
var newInstance = instance.clone(true, true);
instances.data.push(newInstance);
newInstance.appendTo(wrapper);
});
$('#wrapper').trigger('new.instance', instances);
console.log(instances.data[0].get(0));
// somewhere else at a latter time trigger new.instance again
setTimeout(function() {
$('#wrapper').trigger('new.instance', instances);
$.each(instances.data, function(index, item) {
var counter = index + 1
item.text( 'cloned instance ' + counter );
console.log(item.get(0))
})
}, 2000)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content">
<div id="wrapper">
<div class="instance"></div>
</div>
</div>
.instance is in the event.chain so you can access it on callback during the bubbling phase. Review the Snippet by clicking each element.
Snippet
var wrp = document.getElementById('wrapper');
wrp.addEventListener('click', function(e) {
if (e.target != e.currentTarget) {
var trueTarget = e.target.className;
alert(trueTarget + ' has been clicked!');
}
e.stopPropagation();
}, false);
#content {
border: 2px dashed grey;
width: 50vw;
height: 50vh;
background: rgba(0, 0, 0, .3);
text-align: right;
color: white;
}
#wrapper {
border: 3px dotted orange;
background: rgba(0, 0, 0, .5);
width: 50%;
height: 50%;
text-align: right;
font-size: small;
color: orange;
}
.instance {
border: 1px solid yellow;
width: 50%;
height: 50%;
background: rgba(0, 0, 0, .7);
text-align: center;
font-size: smaller;
color: yellow;
}
<div id="content">
CONTENT
<div id="wrapper">
WRAPPER
<div class="instance">
INSTANCE
</div>
</div>
</div>
I have looked through same questions on this topic but somehow suggested solutions do not work for me :/
Problem is that divs get moved from #box1 to #box2 only once. If detach() used then divs are clickable in #box2 but get rearranged when clicked. If remove()used divs are not clickable in #box2 at all (event listener gone?). I have a feeling that the process of moving the divs is somehow not really complete and I ether have duplicates around in DOM or moved divs disappear entirely and do not react to clicks.
I tried detach(), remove() and appendTo() in various combinations and the best I can get is in the fiddle below
http://jsfiddle.net/uoz3t914/13/
$('#box1 .item' ).on('click', function() {
// $( this ).detach().appendTo('#box2'); moves divs around in #box2
$( this ).remove().appendTo('#box2');
});
$('#box2 .item' ).on('click', function() {
// $( this ).detach().appendTo('#box2'); moves divs around in #box2
$( this ).appendTo('#box1');
});
In your case you have to use the Event Delegation
$('#box1' ).off().on('click','.item', function() {
// $( this ).detach().appendTo('#box2'); moves divs around in #box2
$( this ).appendTo('#box2');
});
$('#box2' ).off().on('click', '.item', function() {
// $( this ).detach().appendTo('#box2'); moves divs around in #box2
$( this ).appendTo('#box1');
});
You attach the event to the parent, that propagate it to the children, and then any time that you attach the event, put an off() to detach it.
$('#box1' ).off().on('click','.item', function() {
// $( this ).detach().appendTo('#box2'); moves divs around in #box2
$( this ).appendTo('#box2');
});
$('#box2' ).off().on('click', '.item', function() {
// $( this ).detach().appendTo('#box2'); moves divs around in #box2
$( this ).appendTo('#box1');
});
.item {
width: 50px;
height: 50px;
float: left;
}
#box1 {
border: 1px dotted blue;
position: relative;
width: 200px;
height: 100px;
}
#i1 {
background-color: yellow;
}
#i2 {
background-color: green;
}
#i3 {
background-color: red;
}
#box2{
border: 1px solid black;
width: 250px;
height: 100px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id ="box1">
<div class ="item" id ="i1"></div>
<div class ="item" id ="i2"></div>
<div class ="item" id ="i3"></div>
</div>
<div id = "box2">
</div>
You can move them between the boxes with:
$('#box1, #box2').on('click', '.item', function () {
$(this).appendTo($(this).parent().prop('id') == 'box1' ? '#box2' : '#box1');
});
$('#box1, #box2').on('click', '.item', function () {
$(this).appendTo($(this).parent().prop('id') == 'box1' ? '#box2' : '#box1');
});
.item {
width: 50px;
height: 50px;
float: left;
}
#box1 {
border: 1px dotted blue;
position: relative;
width: 200px;
height: 100px;
}
#i1 {
background-color: yellow;
}
#i2 {
background-color: green;
}
#i3 {
background-color: red;
}
#box2 {
border: 1px solid black;
width: 250px;
height: 100px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="box1">
<div class="item" id="i1"></div>
<div class="item" id="i2"></div>
<div class="item" id="i3"></div>
</div>
<div id="box2"></div>
This uses .on()'s event delegation syntax to handle the elements, and a ternary operator to determine which box the element exists in.
Use this html:
<div id="wrapper">
<div id ="box1" class="container">
<div class ="item" id ="i1"></div>
<div class ="item" id ="i2"></div>
<div class ="item" id ="i3"></div>
</div>
<div id = "box2" class="container">
</div>
</div>
and this javascript
$('.item').on('click', function(){
var index = $("#wrapper > .container").index($(this).parent()),
maxIndex = $('#wrapper > .container').length,
nextIndex = (index + 1) < maxIndex ? (index + 1) : 0;
$(this).appendTo($('#wrapper > .container').eq(nextIndex));
});
in your fiddle to move boxes between any number of containers
You may also add Box3, Box4 (with class .container) etc. into the "#wrapper div", you may do it dynamycally