jQuery autocomplete focus one more time after hide - javascript

Does anybody know why after clicking outside the search field and hiding autocomplete results a focus activate one more time? See please at http://layot.prestatrend.com/
Type for example just 3 letters at search field 'ipo'. Thanks for any reply!

I guess it is just the behavior of the plugin to re-focus the input if the suggestion menu was visible.
When you click outside (or use TAB to unfocus) the input, the "blur" event is triggered:
.blur(function() {
hasFocus = 0;
if (!config.mouseDownOnSelect) {
hideResults();
}
})
Executing hideResults' executes another functionhideResultsNow` which makes this check:
var wasVisible = select.visible();
...
if (wasVisible)
// position cursor at end of input field
$.Autocompleter.Selection(input, input.value.length, input.value.length);
wasVisible is true because the suggestion menu is open.
The job of $.Autocompleter.Selection is to set the text selection in the input and at the end, it focuses the input:
$.Autocompleter.Selection = function(field, start, end) {
if (field.createTextRange) {
...
} else if (field.setSelectionRange) {
...
} else {
...
}
field.focus();
};
If you click again outside the input, the variable wasVisible is false, because the suggestion menu is not open anymore, and the $.Autocompleter.Selection is not executed so the input is not re-focused.

The only way I found: Destroy the autocomplete on focus event for re initializing it.
function defaultFocusAction(e, options) {
if($(e.currentTarget).val() == '') {
$(e.currentTarget).autocomplete('destroy');
$(e.currentTarget).autocomplete(options);
}
$(e.currentTarget).trigger('keydown.autocomplete');
}
var options = {
autoFocus : false,
delay : 0,
minLength: 0,
source: ['foo', 'bar']
};
$('input.autocomplete').autocomplete(options).focus(function(e) {
defaultFocusAction(e, options);
});

Related

Simulating keydown event in Chrome

I am trying to simulate keydown event in Google chrome console. The site of my interest is web.whatsapp.com and the element of concern is document.getElementsByClassName("input-search")[0];
What I am trying to do is that as one types some text in that field, the contact list shown below that field gets updated with contacts containing the content in that text field.
Before trying anything else, I just set focus to this text field using this answer.
Things I tried are:
https://stackoverflow.com/a/12187302/1291122 - Nothing happens and no element is updated in the contact list shown.
https://stackoverflow.com/a/4176116/1291122 - Again, the same result.
https://stackoverflow.com/a/10520017/1291122 - Nothing happens. Same result
There were a few other sources as well. But nothing has worked. How do I simulate the exact effect (of typing some text in the text field and seeing the contact list update) using JavaScript the console?
My chrome version is the latest one as of the date of writing the answer- 41.0.2272.101
EDIT:
Here is one of the sample codes which I have tried. (From answer 3 above)
setTimeout(function () {
$(".input-search").focus();
Podium = {};
Podium.keydown = function(k) {
var oEvent = document.createEvent('KeyboardEvent');
// Chromium Hack
Object.defineProperty(oEvent, 'keyCode', {
get : function() {
return this.keyCodeVal;
}
});
Object.defineProperty(oEvent, 'which', {
get : function() {
return this.keyCodeVal;
}
});
if (oEvent.initKeyboardEvent) {
oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, k, k);
} else {
oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, k, 0);
}
oEvent.keyCodeVal = k;
if (oEvent.keyCode !== k) {
alert("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")");
}
document.dispatchEvent(oEvent);
}
Podium.keydown(83);
}, 5000);
Simply put this code in your chrome browser console(for web.whatsapp.com) and hit enter. Then immediately click on any part of your webpage(to transfer focus). After 5 seconds you would see the cursor on that text field. But key down event does not get invoked.
As I'm working on manipulating web.whatsapp.com with javascript, you can take a look at this function I created to type some text in the search input:
function searchContact(text)
{
var input = document.getElementsByClassName("input input-search")[0];
input.value = "";
var evt = document.createEvent("TextEvent");
evt.initTextEvent ("textInput", true, true, window, text, 0, "en-US");
input.focus();
input.dispatchEvent(evt);
}
input is the input element. evt is the typing event. text is the text you want to search.
This function does the following:
get the input -> clear it -> create a keyboard typing event -> focus the input -> apply the event on the input
EDIT: Since the wrriting of this answer, Whatsapp Web was updated and so this solution does not work anymore in Whatsapp Web. (might be useful for other places or projects)

OnBlur effect for select dropdown

I have a select dropdown and if a user clicks 'outside' of that select dropdown, I want it to disappear. This is what I currently have:
$(this).html($("<select/>", {
id: 'sel',
change: function() {
selectdone(this, title_id, status_type);
},
blur: function() {
selectdone(this, title_id, status_type);
},
In the above, if I click outside of the dropdown, nothing happens. The only time the function is firing is if I change the value of the select dropdown.
How would I accomplish the above, such that when a user clicks anywhere on the document outside of the select dropdown, it fires this function?
I don't think this is possible. As pointed out in another answer, it appears that the active <select> is prohibiting other input from being accepted.
See my updated fiddle. Notice that when you click the background you get the alert test when the select isn't expanded. When it is expanded and you click off, the alert doesn't fire. This appears to be the default behavior of the browser. It appears to be ignoring all other inputs (mouse movements included) while the select is activated.
I was, however, able to get your event to fire for any selected element by setting the selectedIndex to -1. This way any valid option will result in a change.
Example
$(function(){
var title_id = '', status_type = '';
$('body').html(
$("<select/>", {
id: 'sel',
change: function() {
selectdone(this, title_id, status_type);
},
blur: function() {
selectdone(this, title_id, status_type);
}
})
.append($('<option />', { 'text':'one'}))
.append($('<option />', { 'text':'two'}))
);
$('#sel').prop('selectedIndex', -1);
});
function selectdone(element, titleid, statustype){
$(element).hide().prop('selectedIndex', -1);
}

Tooltip of previous onValidationError event displayed even when correct values are entered in the slickgrid node

I am using requiredFieldValidator for my TextEditor. Using the onValidationError event as given below, i set the title attribute of my cell to the error message so that a tooltip will be displayed as 'This is a required field'.
var handleValidationError = function(e, args) {
var validationResult = args.validationResults;
var activeCellNode = args.cellNode;
var editor = args.editor;
var errorMessage = validationResult.msg
$(activeCellNode).live('mouseover mouseout', function(event) {
if (event.type == 'mouseover') {
$(activeCellNode).attr("title", errorMessage);
} else {
$(activeCellNode).attr("title", "");
}
});
grid.onValidationError.subscribe(handleValidationError);
Successfully, the tooltip is displayed when there is some validation error.
But the problem is When the same cell is given a correct value and validation succeeds, the previous tooltip appears again.
How do I remove that tooltip on successful validation?
I have found a solution for this issue and it works fine.
By going through the slick.grid.js code, i understood that OnValidationError event will be triggered only when the 'valid' value from the validator is false.
My idea was to fire the onValidationError event whenever validator is called i.e on both validation success and failure, and to check for 'valid' value and handle the tooltip according to that value.
STEPS:
In slick.grid.js, I added the trigger for onValidationError event when 'valid' from validator is true also.
(i.e) add the below given code before return statement in if(validationResults.valid) in slick.grid.js
trigger(self.onValidationError, {
editor: currentEditor,
cellNode: activeCellNode,
validationResults: validationResults,
row: activeRow,
cell: activeCell,
column: column
});
2. In the onValidationError event handler of your slickgrid,get the value of the parameter 'valid'. If true, it means validation is success and remove tooltip i.e remove
title attribute for that node. If 'valid' is false, it means
validation has failed and add tooltip.i.e set the title attribute to
error message. By doing this, the tooltip of the previous
onValidationError will not appear on the same node. The code goes as
follows:
grid.onValidationError.subscribe(function(e, args) {
var validationResult = args.validationResults;
var activeCellNode = args.cellNode;
var editor = args.editor;
var errorMessage = validationResult.msg;
var valid_result = validationResult.valid;
if (!valid_result) {
$(activeCellNode).attr("title", errorMessage);
}
else {
$(activeCellNode).attr("title", "");
}
});
Hope this solution will help others for this issue.
HAPPY LEARNING!!!
Rather than editing the slick grid js - I've submitted a request for this change - in the meantime you can subscribe to the following events to remove the previous validation display:
grid.OnCellChange.Subscribe(delegate(EventData e, object a)
{
// Hide tooltip
});
grid.OnActiveCellChanged.Subscribe(delegate(EventData e, object a)
{
// Hide tooltip
});
grid.OnBeforeCellEditorDestroy.Subscribe(delegate(EventData e, object a)
{
// Hide tooltip
});
A much more appropriate way to implement this is to subscribe to the onBeforeCellEditorDestroy event and clean up the state (i.e. clear the tooltip) there.
I wasn't able to determine the current cell in OnBeforeCellEditorDestroy, so I just cleared the title in onCellChange, which fires before onValidationError. For example:
grid.onCellChange.subscribe(function (e, args) {
$(grid.getCellNode(args.row, args.cell)).children("input").attr( "title", "");
});

Customised jQuery autocomplete

I have a customised jQuery autocomplete control that is declared something like this.
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
change: function(event, ui) {// some function},
select: function(event, ui) {// some function}
});
The change and select events are custom.
The problem is if I type something into the textbox then click the submit button (i.e. no tab out, or lost of focus), or if I press the key to submit after typing into the text box, the change event isn't fired and it has to be before I submit.
I was hoping to do it without putting javascript behind the submit button, and to ideally do it from within the autocomplete control itself. I tried adding the change to the blur event.
${'foo').blur(function() { $('bar').trigger('autocompletechange');
// or
${'foo').blur(function() { $('bar').change();
But none of them have worked, anyone have any ideas?
You can try something like this:
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
change: function(event, ui) {/* some function */},
select: function(event, ui) {/* some function */}
}).each(function(){
var self = $(this).closest("form").submit(function(e){
self.trigger("change");
// you may not need anything like this...but whatever
if(!functionToCheckIfFormIsValid()){
e.preventDefault();
}
});
});
focus function autocomplete
Before focus is moved to an item (not selecting), ui.item refers to the focused item. The default action of focus is to replace the text field's value with the value of the focused item, though only if the focus event was triggered by a keyboard interaction. Canceling this event prevents the value from being updated, but does not prevent the menu item from being focused.
Solve the problem:
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
focus: function( event, ui ) {
return false;
},
select: function(event, ui) {
alert('Select Event:'+ui.item.value);
}
});
So your problem is that you have to make sure that action a occurs before action b and you're having trouble reconciling that between two event handlers? That actually sounds like a pretty common UI problem, not something that's limited to jQuery.
How would you solve it in any other circumstance? What if I suggested you to use the jQuery data object to attach to the element and then do some sort of semaphore checking in each method, like setting a flag in the one method, and in the other method checking to see if the flag is set?
That's how I would do it, were it me.
DEMO: http://ask.altervista.org/demo/jquery-autocomplete-help/
$(function() {
var json = [{"label":"Access","value":0},{"label":"Documentum","value":0}];
$('#SystemCode_Autocomplete').autocomplete({
source: function( request, responce ) {
responce( $.map( json, function( item ) {
return { id: item.value, label: item.label, value: item.label }
}));
$.each( json, function( i, item ) {
if ( request.term.toLowerCase() == item.label.toLowerCase() ) {
// do something here, ex.: AJAX call or form submit...
$('#submit_button').click();
}
});
},
minLength: 1,
change: function(event, ui) { /*alert(ui.item.label + ' ' + ui.item.id)*/ },
select: function(event, ui) {}
});
});
Ok I completely for to update this to what we actually did to get it to work.
Basically we editted the autocomplete .js file to get it to do want we wanted.
Specifically we added our own options to the autocomplete then we editted the _response method to something like this
_response: function (content) {
if (content.length) {
content = this._normalize(content);
this._suggest(content);
this._trigger("open");
this.options.isInError = false;
this.element.removeClass("input-validation-error");
} else {
this.close();
if (this.element.val() == '') {
this.options.hiddenField.val('');
} else {
this.options.hiddenField.val('-1');
}
if (this.options.mustBeInList) {
this.options.isInError = true;
this.element.addClass('input-validation-error');
}
}
this.element.removeClass("ui-autocomplete-loading");
},
That way we know if the User is entering "rubbish" as they type and the controll goes red and into an "error"mode. To stop them from posting back we do this
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if (self.options.isInError == true) {
return false;
}
if (self.menu.element.is(":visible")) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if (!self.menu.active) {
return;
}
self.menu.select(event);
break;

Set focus on textfield when un-focused

I want a text field to always be focused. When they click out of the textfield, I want the focus to go back into the textfield.
How would I accomplish this with jQuery?
$('input').focus();
$('input').**unfocused?**( function($) { $('input').focus();} );
You're looking for the blur event:
$(':text').blur(function() { this.focus(); });
The following code is an alternative solution which depends on periodically checking the control's state.
var controlFocus=false;
$("#txtName").focus(function(){
$(this).addClass("focused");
if(!controlFocus) {
controlFocus = true;
setInterval(function(){
var o = $("#txtName");
if(!o.hasClass("focused")) o.focus();
}), 200);
}
}).blur(function(){$(this).removeClass("focused");});
After the textbox (named txtName) gets its first focus, every 0.2 second, the code controls whether the textbox has focus. If it doesn't, it's focused. But this can be a really annoying thing.
Bind to get the change event, and check if focus must be forced to this input if so, insert some data in the document. $(document).data(‘_force_focus’, e.target)
$('input.force').bind('change', function(e) {
if( need_force_focus() ) {
$(document).data('_force_focus', e.target);
} else {
$(document).removeData('_force_focus');
}
});
Now on the document bind to the focusin event, testing if document have the “_force_focus” data. If so set the focus to the value. It’s important prevent the focusin retrigger by testing against e.target
$(document).bind('focusin', function (e) {
var t = $.data(document, '_force_focus');
if( t && e.target !== t ) {
$(t).trigger('focus');
return false;
}
return true;
});

Categories

Resources