The desired behavior is that a user can click on this object (so it has an ng-click) but if the click turns into a drag before mouseup, then the ng-click handler is not fired.
Perhaps a way to detect, given the $event object which I pass to the handler, whether or not the click was a drag, and have a conditional which checks that in the handler?
(motivation is that the clickable object has text, and I want that text to be able to be highlighted and copied without triggering the click)
using angular version 1.5.6
I think you can set both ng-mousedown and ng-mouseup handlers. When ng-mousedown fires you can save coordinates and then calculate the difference with new coordinates inside ng-mouseup event. If the difference is small - it's a click and you can run you ng-click function.
This is how I managed this - in my controller I have this:
$scope.dragging = false;
$scope.mouseIsDown = false;
$scope.mouseDown = function(event){
//console.log("mouse down");
$scope.mouseIsDown = true;
$scope.dragging = false;
};
$scope.mouseUp = function(event){
//console.log("mouse up");
$scope.mouseIsDown = false;
if($scope.dragging){
//console.log("Must have dragged");
return false;
}else{
//handle single click here, since drag didn't happen
}
};
$scope.mouseMove = function(event){
//console.log("mouse moved");
$scope.dragging = true;
};
In my HTML element I have these handles set, although I'm certain this is what Roman meant:
ng-mousedown="mouseDown(event)"
ng-mouseup ="mouseUp(event)"
ng-mousemove="mouseMove(event)"
Related
I'm trying to put a link on a selectize dropdown in order to allow the user make an operation other than select an item while still allowing that the user selects the item as main option.
Here is an example of what I want to achieve (but is not working as expected):
What I did is plainly insert links on the HTML. But it's not working, I suppose that for some kind of event propagation stop, is it possible to achieve with selectize?
Nobody did answer yet and I think there's more to say about, so, here is an example of what I did:
render: {
option: function(item) {
return '<div><span>'+item.label+'</span>'
+ '<div class="pull-right">'
+ 'Link'
+ '</div></div>';
}
}
As you can see, I did change the "option" renderization, and inserted a link in plain HTML. The problem is that -as shown on image- when I do click the link, the browser does not follow the link, but executes the default action for selectize, which is selecting the clicked element.
What I want to achieve is to make it follow the link when clicked.
Here is a fiddle of what I did: http://jsfiddle.net/uetpjpa9
The root problem is that Selectize has mousedown and blur handlers that are dismissing the dropdown before the mouseup event that would complete the click that your link is waiting for from ever occurring. Avoiding this without direct support from Selectize is not easy, but it is possible thanks to its plugin system and the amount of access it gives you to Selectize internals.
Here's a plugin that allows a dropdown element with the class clickable to be clicked on. (demo)
Selectize.define('option_click', function(options) {
var self = this;
var setup = self.setup;
this.setup = function() {
setup.apply(self, arguments);
var clicking = false;
// Detect click on a .clickable
self.$dropdown_content.on('mousedown click', function(e) {
if ($(e.target).hasClass('clickable')) {
if (e.type === 'mousedown') {
clicking = true;
self.isFocused = false; // awful hack to defuse the document mousedown listener
} else {
self.isFocused = true;
setTimeout(function() {
clicking = false; // wait until blur has been preempted
});
}
} else { // cleanup in case user right-clicked or dragged off the element
clicking = false;
self.isFocused = true;
}
});
// Intercept default handlers
self.$dropdown.off('mousedown click', '[data-selectable]').on('mousedown click', '[data-selectable]', function() {
if (!clicking) {
return self.onOptionSelect.apply(self, arguments);
}
});
self.$control_input.off('blur').on('blur', function() {
if (!clicking) {
return self.onBlur.apply(self, arguments);
}
});
}
});
To use it, you need to pass the plugin option to the selectize call (.selectize({plugins:['option_click']})) and add the clickable class to links in your dropdown template. (This is fairly specific. If there are nested elements, make sure clickable is on the one that will first see the mousedown event.)
Note that this is a fairly hackish approach that may have edge cases and could break at any time if something about how Selectize dispatches events changes. It would be better if Selectize itself would make this exception, but until the project catches up to its backlog and becomes more receptive to requests and PRs this may be the most practical approach.
I'm trying to make a simple plugin to be able to make a div draggable. Of course a div can have a content inside (typically a form) and it should be dragged with it.
Here is a prototype: http://jsfiddle.net/Xcb8d/539/
The problem is that the texbox inside this div never gets focus, so I cannot type in it:
<div id="draggable-element">Drag me!
<form>
<input type="text" style="width:50px;"/>
<button>ok</button><br><br>
<input type="checkbox">check it</input>
</form>
</div>
As you can see, this does not happen to other elements on the form. Checkbox can be regularily used, as well as the button.
In addition, I would like only the grey coloured area to be draggable, and not the inner elements. On this example, you can place the mouse cursor fully inside the textbox and start the drag of the whole parent div.
the onmousedown handler on the draggable element return false and there by stopping event propagation, allowing it will make the input focus-able and the dragging still works. (at least on chromium)
document.getElementById('draggable-element').onmousedown = function (e) {
// memorize the offset to keep is constant during drag!
x_offset = e.clientX - x_elem;
y_offset = e.clientY - y_elem;
_drag_init(this);
return true;
};
In your onmousedown handler you end with a return false. This prevents the click event from happening when you click on the input, and thus it never gets focus. What I think you are looking for is this:
// Bind the functions...
document.getElementById('draggable-element').onmousedown = function (e) {
if (e.id == 'draggable-element') {
// memorize the offset to keep is constant during drag!
x_offset = e.clientX - x_elem;
y_offset = e.clientY - y_elem;
_drag_init(this);
return false;
}
};
paradoxix's answer was correct in stating that the return falseon the mousedown event is preventing the propagation of all other events.
On any element listening to the mousedown event you won't have any problems, because the event happens for them first, and only after for the box itself. But the input listens to the focusevent, which never happens due to the return false in the box's event.
The solution is to prevent onmousedown from bubbling from the child elements into the box, like so:
var nodes = document.getElementById('draggable-element').childNodes;
for(var i=0; i<nodes.length; i++) {
nodes[i].onmousedown = function(e) {
e.stopPropagation();
}
}
Working fiddle: http://jsfiddle.net/Xcb8d/546/
I am implementing drag'n'drop functionality on the page. The idea is that user can start dragging image from special place and drop it (release left mouse button) inside textarea, where special tag insertion will occur.
I have no issues with the dragging itself, the problem I got is that I can't determine position of the mouse inside textarea. I know x and y positions from mouseup event and I definetely know the mouse pointer is inside textarea, but can't determine at which position do I need to insert the required tag. Since the focus is not inside the textarea, selectionStart and selectionEnd properties are 0. Also, it is worth noticing that I prevent default behavior by returning false in mousemove handler - otherwise default behavior will put the image itself inside the textarea (which is extremely bad for base64 images).
Below is the code I currently have.
window.onPreviewItemMouseDown = function (e) {
var curTarget = $(e.currentTarget);
var container = curTarget.parent();
window.draggingImage = funcToGetId();
$(document).on("mousemove", window.onPreviewItemDragged);
$(document).on("mouseup", window.onPreviewItemDropped);
};
window.onPreviewItemDragged = function (e) {
return false;
};
window.onPreviewItemDropped = function (e) {
var target = $(e.target);
$(document).off("mousemove");
$(document).off("mouseup");
if (target[0].id === ID_TEXTAREA_TEXT) {
// here I need to get mouse pointer position inside the text somehow
}
return false;
};
Any help is appreciated.
In your case it would be easier to use native ondragstart event instead of a complex mousedown-move-up implementation, and manipulate the data to drop. Something like this:
document.getElementById('img').addEventListener('dragstart', function (e) {
e.dataTransfer.setData("text", '[img]' + this.id + '[/img]');
});
A live demo at jsFiddle. Or a delegated version. Notice that you can also delegate to the "special place" element, which might make the page running a little bit faster.
I have the following html code:
<input type="text" id="theInput" value=""/>
Click me
I want to detect when the input changes and perform an operation in this case, but ONLY when the user has not clicked in the link. I have tried this:
$('#theLink').live('click', function(){
alert('click');
});
$('#theInput').live('change', function(){
alert('change');
});
However change is always executed before click when the value in the input changed, due to Javascript event precedence rules, and therefore only "change" message is displayed.
I would like it to display change only if the input value changed and the user exited the input clicking in any other place instead of the link. In that last case I would like to display click.
The example is here.
I use jQuery 1.6.4.
As far as I know, the click event fires after the blur and change events in every browser (have a look at this JSFiddle). The order of blur and change is different across browsers (source: Nicholas Zakas).
To solve your problem, you could listen to click events on the document and compare the event's target with #theLink. Any click event will bubble up to the document (unless it is prevented).
Try this:
var lastValue = '';
$(document).click(function(event) {
var newValue = $('#theInput').val();
if ($(event.target).is('#theLink')) {
// The link was clicked
} else if (newValue !== lastValue) {
// Something else was clicked & input has changed
} else {
// Something else was clicked but input didn't change
}
lastValue = newValue;
});
JSFiddle: http://jsfiddle.net/PPvG/TTwEG/
Both events will fire but in your example the alert in the onchange event handler fired when the onmousedown event occurs will stop the onmouseup event required for the onclick event to fire. Using console.log will show both events firing.
http://jsfiddle.net/hTqNr/4/
Ok, now i got it, you could do
$('#theLink').live('click', function(e){
alert('click');
});
$('#theInput').live('change', function(e){
//Check if the change events is triggerede by the link
if(e.originalEvent.explicitOriginalTarget.data === "Click me"){
//if this is the case trigger the click event of the link
$('#theLink').trigger("click");
}else{
//otherwise do what you would do in the change handler
alert('change');
}
});
Fiddle here http://jsfiddle.net/hTqNr/19/
why you dont pick the value of input box. you have to store initial value of input box on ready function
initialvalue= $('#theInput').val();
then compare the value
$('#theLink').live('click', function(){
var newvalue =$('#theInput').val();
if(newvalue!=initialvalue) {
//do something
}
});
I want to detect whenever someone clicks in a div (essentially I want to know when a user is interacting with a section of text on my site, be that by selecting some text or clicking on a link), but I don't want to interfere with what the user is doing.
If I put a onmousedown or onclick event on the div it ends up breaking selection, links, etc. Is there any way to catch these events without causing any interference ?
Onmousedown or onclick shouldn't interfere with anything as long as it doesn't return false;.
You can do this:
document.getElementById("spy-on-me").onmousedown = function () {
console.log("User moused down");
return true; // Not needed, as long as you don't return false
};
If you have other scripts that are attaching behaviour via this method on the page, then to prevent overriding them you can do:
var spyElement = document.getElementById("spy-on-me");
var oldMousedown = spyElement.onmousedown;
spyElement.onmousedown = function () {
console.log("User moused down");
if(oldMousedown) oldMousedown();
};
Yes, I suspect you are currently returning false at the end of the event binding, just don't do that or any of the things in this binding:
$('a').click(function(e) {
e.stopPropagation();
e.preventDefault();
return false;
});
If you do not do any of these three things, jQuery will not stop the event from bubbling up to the browser.
Edit: Sorry didn't realise it was a plain JavaScript question.
you can use do it by adding a event listener as well
var myNode= document.querySelector('.imagegrid');
myNode.addEventListener("click",function(e){
alert(e.target+" clicked");
});
A similar example is demonstrated here
Can't you simply add a click event to the div?
<div id="secretDiv" (click)="secretDivClick()">
then on your component:
secretDivClick() {
console.log('clicked');
}