I'm working on a custom editor (dropdown with search & ajax-fetched items based on said search) and I need to keep cell in the edit mode after blur event.
As of Tabulator 5.1 blur must be handled either by calling cancel or success. If that is not satisfied Tabulator cancels the edit.
I've checked how built-in Autocomplete editor works around this but the solution lies around input type search and still adheres to this constraint.
How can this be achieved? For me personally it would make sense if the function implementing a custom editor would take an extra param passtrough changing the signature to (cell, onRendered, success, cancel, editorParams, passthrough). We could call passthrough() inside blur event to indicate we are ok with exceeding the active cell bounds and do not want to cancel the edit.
I've tried
not resolving blur event -> leads to fallback cancel
calling success, cancel -> leads to their respective results
commenting out blur handler -> results in fallback cancel too
Tabulator already has a built in autocomplete editor that allows for text searching and ajax lookup.
Full details can be found in the Editor Documentation
If you want to build a custom editor, i would suggest your starting point should be to look at the code for the existing select and autocomplete editors to see how the do this as they already work correctly, there is no need for an additional passthrough argument.
There has been no change in behaviour to the blur event behavior on editors in any of the recent releases of Tabulator, neither v5.0 or v5.1
You will see that on lines 226 and 405 of the select editor, it uses a mousedown event to track when a user clicks on elements relating to the editor and sets a blurable property to false, and then back to true a few ms later:
listEl.addEventListener("mousedown", function(e){
blurable = false;
setTimeout(function(){
blurable = true;
}, 10);
});
On line 559 it listens to the blur event on the editor, if the blurrable flag is false, ie someone just click on an element of the editor, then it ignores the blur event and dosnt cancel the edit
input.addEventListener("blur", function(e){
if(blurable){
cancelItem();
}
});
Related
I have a model, Color, with a foreign key mill that I'd like to autocomplete. Furthermore, I'd like to detect when the mill select box changes and do something with that in Javascript. However, I can't seem to trigger any JS off the select box being changed.
I set up my admin like so:
# admin.py
class MillAdmin(admin.ModelAdmin):
search_fields = ['name']
class ColorAdmin(admin.ModelAdmin):
class Media:
js = ['js/jquery/jquery.min.js', 'js/admin/some-function.js',]
autocomplete_fields = ['mill']
And I write some Javascript:
// some-function.js
console.log('loaded script');
document.addEventListener('change', (function(e) {
console.log('detected change event somewhere')
}))
console.log('event listener added')
In my browser console, when I visit the Color page, I see:
loaded script
event listener added
But when I select a mill, nothing more is logged.
Further notes:
The autocomplete itself is working just fine -- I am able to choose the mill I want, save, etc. Furthermore, if I remove autocomplete_fields = ['mill'] from my admin, I see that the vanilla select box does trigger the change event as expected:
loaded script
event listener added
detected change event somewhere
I dug around in the source code long enough to find that Django is using Select2, which promises to emit the change event just as if it were a normal select box. But if that is happening, something else in the page must be eating it, because I'm not seeing it. What's going on? If there's a conflict between Django and Select2, does anyone know a workaround? Thanks!
Events triggered by jQuery cannot be observed by native event listeners. Select2 uses jQuery's trigger function to handle events, which doesn't fire native DOM events, but you can swap the jQuery trigger for a native DOM one as illustrated here https://github.com/select2/select2/issues/4686
I have an application that uses ui-grid with cellNav and edit with editOnFocus=true for some columns. The problem I have is that the END_CELL_EDIT and CANCEL_CELL_EDIT in the edit feature always call gridCtrl.focus(). If I have an editable cell focused and then click on an input outside of the grid it will steal the focus and put it back in the grid.
What happens is I click in the input outside of the grid. It receives focus. At the same time the END_CELL_EDIT event is triggered. This then calls the gridCtrl.focus() and the focus is taken away from the outside input box.
Is there a way to override this behavior in ui-grid.edit? Why is this behavior standard?
Here is a plnkr to demonstrate. If you click on the age column to make it enter edit mode and then click on the text area you will see it momentarily gains focus and has a cursor but then quickly the grid steals the focus back and you can no longer edit.
http://plnkr.co/edit/Sg1dTcsMN0zNRDmauwoT
This behavior is not ideal for my situation because we are automatically focusing on a particular cell (entering edit mode) whenever the row is selected or navigated to. So any action that changes row or moves the focus outside of the grid triggers the END_CELL_EDIT event and the focus behavior described above.
The trick is setting up another focus, but delaying it by a digest cycle - thus allowing the grid to do what it needs to. Relevant code snip-its from your updated Plunker below.
HTML (for binding):
<textarea id="textarea" ng-focus="delayFocus()"></textarea>
Controller (to allow digest cycle):
$scope.delayFocus = function() {
$timeout(function() {
focus('textarea');
$scope.gridApi.grid.cellNav.clearFocus();
});
}
Factory (to use for re-focus):
app.factory('focus', function($timeout, $window) {
return function(id) {
// timeout makes sure that it is invoked after any other event has been triggered.
// e.g. click events that need to run before the focus or
// inputs elements that are in a disabled state but are enabled when those events
// are triggered.
$timeout(function() {
var element = $window.document.getElementById(id);
if (element)
element.focus();
});
};
});
Updated Plunker, http://plnkr.co/edit/UX8tbVwi9gG4zsMRG0kV?p=preview.
You could probably combine the above into one directive and then just apply it to the controls needed - happy to help, if desired/needed.
Hopefully, that'll get you off to a good start.
Scenario:
I have a RadCombobox and I have attached functions to most of the events.
One event of the combobox is OnClientBlur and I am using this to check whether value in Combo is "Unassigned" or not. If it is "Unassigned" I need to cancel the onblur event and keep the focus on to the same combo.
This is the javascript which I has been used to cancel the event.
if (sender.get_text() === "Unassigned") {
eventArgs.get_domEvent().preventDefault();
return false;
}
Problem:
When the user tabs out first time of the ComboBox the event gets cancelled and the focus stays on the same combo box (in this case it is the 3rd Combo).
But when the user hits the tab button again the focus moves to the next control.
When I debugged the code I found that when the user first hits the tab button, following line works
eventArgs.get_domEvent().preventDefault();
I can see the preventDefault function, see following snapshot.
but when the user hits the tab button again I get an error and cannot see preventDefault function, see following snapshot
I am not able to understand what is going wrong here. Anyhelp would be appreciated.
Your problem, revolves around the difference between MouseEvents and KeyEvents. And also the way Telerik implement the OnClientBlur event. As far as it doesn't point to a specific type of browser event, each time it gets triggered
As you see in the first snapshot you got clientX and clientY, which means your OnClientBlur derived from a MouseEvent.
Whereas in the second one you got altKey, altLeft, and also there is no button property, which means that this one is a KeyEvent.
The other point here is as you have these fields in the output:
e.bookmarks
e.behaviorPart
e.behaviorCookie
Means you are using one of the old versions of IE4+ to IE7 or IE8, which they have cancelBubble instead of preventDefault.
Sometimes events are not cancelable, and using event.cancelable you can make sure if the current event is cancelable or not.
At the end to fix you code you can simply do this:
if (sender.get_text() === "Unassigned") {
var domEvent = eventArgs.get_domEvent();
if(domEvent.cancelable){
if(typeof(domEvent.preventDefault)==="function")
domEvent.preventDefault();
else
domEvent.cancelBubble = true;
return false;
}
else{
//you can not cancel the event, do something else to make it manageable
}
}
Ok, so we all know that onChange is used to execute javascript code on a select statement when the option changes. However, if you change a select statement using the arrow keys, the onChange event is not called. Is there a way around this? Please help! I'm OCD I know.
--EDIT 1--
Just tested this in IE and arrow keys do work. Apparently it's just Chrome. ** Goes to check firefox
-- Edit 2 --
Tested in Firefox and realized just before an answer below talked about the onBlur action being required for the change. So the answer here is:
Internet Explorer recognizes onChange events from the keyboard as well as clicking on them.
Firefox and Chrome both require key events to be followed by blur event in order to call onChange.
Now normally, I don't like Internet Explorer, because it's a piece of garbage... But I think I... unfortunately, have to say they got that one right.
My understanding as to the reasoning for the blur event on chrome and firefox is to save resources, but I disagree with that. I feel it should follow the literal interpretation of the command onChange... Sigh... I suppose I'm probably wrong somehow, though.
I would suggest you to write the required code in Key Up event to capture the Key press and and also check for Key Code. Hope this helps
Scrolling through a select box is not considered a change. The change happens when you blur() the select and the new option value is applied to the select element.
Coming back to this, it appears that since the asking of this question, Chrome now fires onChange after key events. Firefox appears to still wait for onblur. http://jsfiddle.net/2aQBN/
$(document).ready(function() {
$("#test").on("change", function() {
console.log("Changed.");
});
});
W3C Specification appears to suggest using an input event instead.
When the input event applies, any time the user causes the element's
value to change, the user agent must queue a task to fire a simple
event that bubbles named input at the input element.
However, no input event appears to fire in Chrome or Firefox for the select element. (Just input elements.)
Test demonstrating the current value vs the last onchange value.
http://jsfiddle.net/teynon/MpyHK/5/
Firefox will change the value onmouseover. The key change will change the value as well. However, the onchange hasn't fired. If the form submits while the user has the select menu open, the currently highlighted option is submitted.
From W3C:
If the multiple attribute is absent, and the element is not disabled,
then the user agent should allow the user to pick an option element in
its list of options that is itself not disabled. Upon this option
element being picked (either through a click, or through unfocusing
the element after changing its value, or through a menu command, or
through any other mechanism), and before the relevant user interaction
event is queued (e.g. before the click event), the user agent must set
the selectedness of the picked option element to true and then queue a
task to fire a simple event that bubbles named change at the select
element, using the user interaction task source as the task source.
There is a LONG discussion at https://bugzilla.mozilla.org/show_bug.cgi?id=126379 about this with many people asking for the arrow keys to work. (And some defending the onchange approach.)
Some users have suggested that the W3C is flat out wrong in the specification for the select element's change event. Instead suggesting we propose changes to the specification for how we expect the select's onchange functionality to work.
The current functionality is clearly not intuitive to a large number of people based solely on the number of bug reports. (Mozilla has 40 marked as duplicates.)
This is a pretty dirty hack, but you can force the the change event to fire by doing this:
element.addEventListener('keyup', function(evt){
evt.target.blur();
evt.target.focus();
}, false);
So you'd register an event listener for change as well, and that function would get called when the user presses a key on the <select> via the code above.
You may want to scope this only to Firefox, but AFAIK you'd have to use UA sniffing for that so it's up to you if that's acceptable.
Source
I'm thinking about something like this (to not trigger event if value wasn't changed):
select.keydown(function(){
var _this = $(this);
var _val = $(this).val();
setTimeout(function(){
if(_this.val() !== _val){
_this.trigger("change");
}
}, 1);
});
Here's a realization of this request. For brevity only showing the code. See https://github.com/ida/skriptz/blob/master/js/fields/select/selection_changed.js for long explanations in comments.
function addSelectionChangedListener(selectionEle, onChangeDoWithEle) {
var selectedIndex = null
function onChangeEvent(eve) {
// If selection-change was caused of an option's click-event:
if(eve.explicitOriginalTarget.tagName.toLowerCase() == 'option') {
// We want to trigger passed event-handler:
onChangeDoWithEle(eve.target)
}
}
function onKeyEvent(eve) {
// Key-event is keydown, remember current selectedIndex:
if(eve.type == 'keydown') {
selectedIndex = eve.target.selectedIndex
}
// Key-event is keyup, if selection changed, trigger passed handler:
else if(selectedIndex != eve.target.selectedIndex) {
onChangeDoWithEle(eve.target)
}
}
selectionEle.onchange = function(eve) onChangeEvent(eve)
selectionEle.onkeydown = function(eve) onKeyEvent(eve)
selectionEle.onkeyup = function(eve) onKeyEvent(eve)
}
I'm using an auto-complete widget from YUI to implement live search as in the examples. However, it works fine when search text is typed in, but fails to work when the text is pasted into the field. Which would be the proper way to initiate an autocompletion on paste? Haven't found anything for that in the documentation...
EDIT: Pasting is not Ctrl-V, it's usually "Paste" from the context-menu. YUI does react to a keypress, but doesn't if anything is pasted by the mouse.
We have extended YUI's autocomplete widget and handle paste from the context menu in this way:
YAHOO.util.Event.on(input, 'paste', function(e, autocomplete) {
// We're interested in the value of the input field after text is pasted into
// it instead of the pasted text because the autocomplete proposals are based
// upon the field's whole value. The paste event happens before the input
// field has been updated so we need to wait until after this event has been
// handled to check the value of the input field.
window.setTimeout(function() {
if (autocomplete._sInitInputValue !== autocomplete.getInputEl().value) {
autocomplete.sendQuery(autocomplete.getInputEl().value);
}
}, 1);
}, this);
Where this is the autocomplete widget.
Perhaps on key event, you could detect if they pressed v while holding ctrl. If they have, then do a sendQuery('query=' + textInput.value);
Edit
Here's a compatibility table showing which browsers let you subscribe to the paste events.
http://www.quirksmode.org/dom/events/cutcopypaste.html
Here's his testing page where you can see how to subscribe to the events.
http://www.quirksmode.org/dom/events/tests/cutcopypaste.html
I imagine you could subscribe to that using YUI & then just have your callback be this:
function() {
autoCompleteObject.sendQuery(autoCompleteElement.value);
}
Watch out for browser incompatibilities, looks like some have a weird implementation of the events.