angular-drag-and-drop-lists
angular-drag-and-drop-lists copied to clipboard
Cursor position of inputs not changable by mouse in FF and IE
Clicking on an input (I tried text, text area) sets the cursor to index 0 for FF and IE. Additionally, under IE a double click is required to get a cursor. Chrome and Safari work as expected (i.e. the cursor is set to the position next to the mouse).
Can be reproduced with the "types" demo: http://marceljuenemann.github.io/angular-drag-and-drop-lists/demo/#/types
+1 I can verify this issue is happening.
Any workarounds for this?
If you do not need the item to be draggable while the input field is displayed, you can set the draggable attribute to false on the dnd-draggable element.
<div dnd-list="myList">
<div ng-repeat="item in myList" dnd-draggable="item" draggable="{{!item.editing}}">
<span ng-if="item.editing"><input ng-model="item.name"> <a href ng-click="item.editing = false">Save</a></span>
<span ng-if="!item.editing">{{item.name}} <a href ng-click="item.editing = true">Edit</a></span>
</div>
</div>
Tested in FF 43 and IE 10/11.
I think the issue occurs because text boxes/areas automatically become drop zones. The issue seems to be a problem with how FF and IE implemented HTML5 drag and drop.
Thanks for the response. I did get this to work by conditionally setting dnd-disable-if. This little trick won't work if the input element is already inside of a dnd-nodrag (which I require to keep users from accidentally dragging the container while trying to edit the field).
Seems like the demo have the same problem in FF : http://marceljuenemann.github.io/angular-drag-and-drop-lists/demo/#/types
I had some problem similar. I think that was related to this kind of problem: https://connect.microsoft.com/IE/feedback/details/927470/ie-11-input-field-of-type-text-does-not-respond-to-mouse-clicks-when-ancestor-node-has-draggable-true I solve the problem, making sure that input parents were not draggable="true", so I needed to add in dndNoDrag directive this code:
.directive('dndNodrag', function() { return function(scope, element, attr) { // Set as draggable so that we can cancel the events explicitly element.attr("draggable", "true");
// If the dnd-disable-if attribute is set, we have to watch that
if (attr.dndDisableIf) {
scope.$watch(attr.dndDisableIf, function(disabled) {
element.attr("draggable", !disabled);
});
}
I can reproduce this issue on FF51 and IE11. Text inputs do not respond to mouse clicks as expected if they are contained in a dnd-draggable element. Any ancestor element with draggable="true" triggers this bug.
dnd-nodrag does not help.
Issues #273, #403, #242, #389 seem to be duplicates.
The following directive is a kludgy workaround. It sets all "draggable" attributes to false on mouseover, and restores them on mouseout.
Caveats:
- Touch devices do not have mouseover, this is not tested on mobile.
- If you have styles relying on the "draggable" attribute, you have to change them.
To use the directive, add it to the input element: <input type="text" dnd-nodrag-mouseover>
.directive('dndNodragMouseover', function(){
return {
restrict: 'A',
require: 'dndNodragMouseover',
controller: function ( $element ) {
this.ancestors = [];
this.findDraggableAncestorsUntilDndDraggable = function ( h ) {
var a = [];
while ( h !== null ) {
if ( h.attr('draggable') !== undefined ) {
a.push({
element : h,
draggable : h.attr('draggable')
});
}
if ( h.attr('dnd-draggable') !== undefined ) {
break;
}
h = h.parent();
}
return a;
};
this.cleanup = function () {
this.ancestors = [];
};
this.removeDraggable = function () {
this.ancestors = this.findDraggableAncestorsUntilDndDraggable( $element );
this.ancestors.forEach(function(o){
o.element.attr('draggable', 'false');
});
};
this.restoreDraggable = function () {
this.ancestors.forEach(function(o){
o.element.attr('draggable', o.draggable);
});
};
},
link: function (scope, iElement, iAttrs, controller) {
iElement.on('mouseover', function(event){
controller.removeDraggable();
});
iElement.on('mouseout', function(event){
controller.restoreDraggable();
});
scope.$on('$destroy', function(){
iElement.off('mouseover');
iElement.off('mouseout');
controller.cleanup();
});
}
};
})
Thanks @timostamm, this seems like the best solution at the moment.
@timostamm I'm trying to implement your solution, but i get the following error: Controller 'dndNodragMouseover', required by directive 'dndNodragMouseover', can't be found!
<input type="text" dnd-nodrag-mouseover class="form-control" ng-model="...">
Any idea?
@SebSob I am still using exactly the same code in a project. It is still on angular ~1.4.6. I suggest to double check for typos (the require must match the directive name). If this does not work, then maybe there is a breaking change in newer angular js versions?
I suggest trying to isolate the problem. require: 'dndNodragMouseover' just makes the controller available to the link function. That should definitely still be possible in later angular versions.
If you can't get it to work, just refactor the code. Remove the "require" and put the controller logic into the link function.
@timostamm I had to rewrite the directive a little bit, because I use john papa's approach: (btw using angularjs 1.6.5)
Maybe you see the reason why it fails?
(function () {
'use strict';
angular
.module('FormGenerator')
.directive('dndNodragMouseover', dndNodragMouseoverDirective)
function dndNodragMouseoverDirective() {
var directive = {
link: link,
cntroller: controller,
restrict: 'A',
require: 'dndNodragMouseover',
};
return directive;
// Controller function
function controller ($element) {
this.ancestors = [];
this.findDraggableAncestorsUntilDndDraggable = function (h) {
var a = [];
while (h !== null) {
if (h.attr('draggable') !== undefined) {
a.push({
element: h,
draggable: h.attr('draggable')
});
}
if (h.attr('dnd-draggable') !== undefined) {
break;
}
h = h.parent();
}
return a;
};
this.cleanup = function () {
this.ancestors = [];
};
this.removeDraggable = function () {
this.ancestors = this.findDraggableAncestorsUntilDndDraggable($element);
this.ancestors.forEach(function (o) {
o.element.attr('draggable', 'false');
});
};
this.restoreDraggable = function () {
this.ancestors.forEach(function (o) {
o.element.attr('draggable', o.draggable);
});
};
}
// Link function
function link (scope, iElement, iAttrs, controller) {
iElement.on('mouseover', function (event) {
controller.removeDraggable();
});
iElement.on('mouseout', function (event) {
controller.restoreDraggable();
});
scope.$on('$destroy', function () {
iElement.off('mouseover');
iElement.off('mouseout');
controller.cleanup();
});
}
}
})();
It seems like the directive itself requires a controller (require: 'dndNodragMouseover'
), which does not exist?
@timostamm My bad, i did a typo cntroller: controller
, I misspelled "controller", forgot the 'o'... :fearful: !
Now it seems to work, but double clicking in the input to select all the text still does not work, right? :thinking: And when I have the cursor in the input field I can still drag the element.