jQuery autocomplete selection event - javascript

I have created jQuery UI autocomplete which is working very good. But my requirement is that what I display as list should also select same in text box. But it is not selecting
For example list like XXX (XYZ) but when I select it only select XXX not XXX (XYZ)
what I am missing !!
function getDeptStations() {
$("#txDestination").autocomplete({
source: function (request, response) {
var term = request.term;
var Query = "";
if (lang === "en")
Query = "City_Name_EN";
else if (lang === "fr")
Query = "City_Name_FR";
if (lang === "de")
Query = "City_Name_DE";
if (lang === "ar")
Query = "City_Name_AR";
var requestUri = "/_api/lists/getbytitle('Stations')/items?$select=City_Code," + Query + "&$filter=startswith(" + Query + ",'" + term + "')";
$.ajax({
url: requestUri,
type: "GET",
async: false,
headers: {
"ACCEPT": "application/json;odata=verbose"
}
}).done(function (data) {
if (data.d.results) {
response($.map(eval(data.d.results), function (item) {
return {
label: item[Query] + " (" + item.City_Code + ")",
value: item[Query],
id: item[Query]
}
}));
}
else {
}
});
},
response: function (event, ui) {
if (!ui.content.length) {
var noResult = { value: "", label: "No cities matching your request" };
ui.content.push(noResult);
}
},
select: function (event, ui) {
$("#txDestination").val(ui.item.label);
cityID = ui.item.id;
},
minLength: 1
});
}

Almost there, just return a false from select event.
select: function (event, ui) {
$("#txDestination").val(ui.item.label);
cityID = ui.item.id;
return false;
},
or Simply
select: function (event, ui) {
alert(ui.item.id);
return false;
},
This will guide jquery autocomplete to know that select has set a value.
Update: This is not in the documentation, I figured out by digging into source code, took me some time. But indeed it deserves to be in the doc or in options.

in this case you have to options
the obvious one set value:item[Query] + " (" + item.City_Code + ")" but I am assuming this is not the option.
Handle the selection by yourself first check the api doc and you will see event like below. with event.target you can access your input with ui you can access you selected item.
$( ".selector" ).autocomplete({
select: function( event, ui ) {}
});

I understand its been answered already. but I hope this will help someone in future and saves so much time and pain.
After getting the results in autocomplete you can use below code for keeping the value in the autocomplete textbox field. (you can replace 'CRM.$' with '$' or 'jQuery' depending on your jQuery version)
select: function (event, ui) {
var label = ui.item.label;
var value = ui.item.value;
//assigning the value to hidden field for saving the id
CRM.$( 'input[name=product_select_id]' ).val(value);
//keeping the selected label in the autocomplete field
CRM.$('input[id^=custom_78]').val(label);
return false;
},
complete code is below: This one I did for a textbox to make it Autocomplete in CiviCRM. Hope it helps someone
CRM.$( 'input[id^=custom_78]' ).autocomplete({
autoFill: true,
select: function (event, ui) {
var label = ui.item.label;
var value = ui.item.value;
// Update subject field to add book year and book product
var book_year_value = CRM.$('select[id^=custom_77] option:selected').text().replace('Book Year ','');
//book_year_value.replace('Book Year ','');
var subject_value = book_year_value + '/' + ui.item.label;
CRM.$('#subject').val(subject_value);
CRM.$( 'input[name=product_select_id]' ).val(ui.item.value);
CRM.$('input[id^=custom_78]').val(ui.item.label);
return false;
},
source: function(request, response) {
CRM.$.ajax({
url: productUrl,
data: {
'subCategory' : cj('select[id^=custom_77]').val(),
's': request.term,
},
beforeSend: function( xhr ) {
xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
},
success: function(result){
result = jQuery.parseJSON( result);
//console.log(result);
response(CRM.$.map(result, function (val,key) {
//console.log(key);
//console.log(val);
return {
label: val,
value: key
};
}));
}
})
.done(function( data ) {
if ( console && console.log ) {
// console.log( "Sample of dataas:", data.slice( 0, 100 ) );
}
});
}
});
PHP code on how I'm returning data to this jquery ajax call in autocomplete:
/**
* This class contains all product related functions that are called using AJAX (jQuery)
*/
class CRM_Civicrmactivitiesproductlink_Page_AJAX {
static function getProductList() {
$name = CRM_Utils_Array::value( 's', $_GET );
$name = CRM_Utils_Type::escape( $name, 'String' );
$limit = '10';
$strSearch = "description LIKE '%$name%'";
$subCategory = CRM_Utils_Array::value( 'subCategory', $_GET );
$subCategory = CRM_Utils_Type::escape( $subCategory, 'String' );
if (!empty($subCategory))
{
$strSearch .= " AND sub_category = ".$subCategory;
}
$query = "SELECT id , description as data FROM abc_books WHERE $strSearch";
$resultArray = array();
$dao = CRM_Core_DAO::executeQuery( $query );
while ( $dao->fetch( ) ) {
$resultArray[$dao->id] = $dao->data;//creating the array to send id as key and data as value
}
echo json_encode($resultArray);
CRM_Utils_System::civiExit();
}
}

Related

Why is the jQuery blur not working jQuery's tag-it library?

I am trying to use JQuery's blur with tag-it library, however, it isn't working.
I am not sure why blur isn't working.
I click off the input and nothing happens, I don't get an error.
The alert in the blur doesn't appear.
I have tried using:
.on(blur, handler)
And:
$(document).ready(function(){
("#id").blur()
})
Neither of them worked.
Here is my code:
var id_name = [[],[]];
var selected = true;
$("#Approversdisp").tagit({
allowSpaces: true,
autocomplete:{
minLength: 3,
delay: 600,
source: function(request, response){
$("#divreviewersearch").show();
$.ajax({
"url" :"private",
"type" : "GET",
"data" : {"name": request.term.trim()},
"contentType" : "application/json",
"success" : function(data) {
id_name[0] = data[0];
id_name[1] = data[1];
response(data[0]);
$("#divreviewersearch").hide();
},
"error" : function(error)
{
alert("error: "+JSON.stringify("There was an error!"));
}
});
},
select: function(event, ui) {
selected = false;
var nameid = ui.item.value;
var approvers = document.addcontent' . $item_id .'.Approvers.value;
ui.item.label = ui.item.label.replace(/\((.*?)\)/, "");
ui.item.value = ui.item.value.replace(/\((.*?)\)/, "");
document.addcontent' . $item_id .'.Approvers.value = approvers+"|"+id_name[1][id_name[0].indexOf(nameid)];
},
}
});
$("#Approversdisp").blur(function() {
alert("in blur");
if(selected){
var input = $("#Approversdisp").val();
input = input.split(",");
$("#Approversdisp").tagit("removeTagByLabel", input[input.length-1]);
alert("please pick the tag from the list.");
}
selected = true;
});
The expected result is the blur working.
I figured out the answer you have to use
$("#inputid").data("ui-tagit").tagInput.blur()

jquery Autocomplete is not loading the results correctly and menu doesn't show unless I press down key

This is what I have:
searchTimeoutID;
InitQuickSearch = function() {
$( 'input#quick-search' ).autocomplete({
source: []
});
$('input#quick-search', document).on('keyup', function(e) {
switch(e.which) {
default: // live search
window.clearTimeout(searchTimeoutID); // remove timer
var str = $(this).val(); // search string
if (str !== '') { // do the search
searchTimeoutID = window.setTimeout(LiveSearch, 100);
}
break;
}
});
};
LiveSearch = function() {
var str = $('input#quick-search').val();
if(str !== '') {
$.ajax({
type: 'POST',
url: '/livesearch',
data: { query: str },
cache: false,
success: function(data){
var results = data.split(',');
alert(results); // displays correct results here
$( 'input#quick-search' ).autocomplete( 'option', { source: results });
},
error: function(response) {
printError(response);
}
});
}
return false;
};
When I output the results variable using alert(results), the values look correct.
However, when I try and update the values in autocomplete it does not display the correct values. Also, I have to press the down key for the menu to appear.
$( 'input#quick-search' ).autocomplete( 'option', { source: results });
What am I doing wrong?
I just had to change:
searchTimeoutID = window.setTimeout(LiveSearch, 100);
to:
LiveSearch();

DataTables sAjaxSource Json higlight search data

I am trying to implement search highlight on data table ( JSON data is coming and filling up the table from serverside through "sAjaxSource"), Please see the below code for details.
search is working by default, BUT highlight is not working at all.
I alerted data of searchTxt+=$('#search_input').val(); alert("txt" + searchTxt);
and alert is displaying search input box text.
Alert for " alert(""+ aData[j]); " displaying "undefined rather than column data and highlight is not working.
Could anyone shed some light on this ?
Thank you,
Sri
jQuery(document).ready(function() {
var oTable = jQuery('#example').dataTable({
"sDom": '<"#table_header"<"#inner_table_header"<"filtertx">fCT<"filterbtn">>>tipl',
"sAjaxSource": ajaxURL,
"bDeferRender": true,
"bProcessing" : true,
"bJQueryUI": true,
"sScrollY": 500,
"aaSorting": [[0, 'desc']],
"aoColumns": [
{ "mData": "name" },
{ "mData": "flag" }
],
"oSearch": {"sSearch": "",
"bSmart": true,
"bRegex": false},
"sPaginationType": "paginate",
"fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
$(nRow).addClass('clickable');
$(nRow).attr('onClick', "editPopup(" + aData['conditionId'] + ")");
},
"fnDrawCallback": function( oSettings ) {
$(expandWrapper);
}
});
$("#example_filter label").attr("for", "search_input");
$("#example_filter input").attr({
"id": "search_input",
"placeholder" : 'search'
});
oTable.fnSearchHighlighting();
});
jQuery.fn.dataTableExt.oApi.fnSearchHighlighting = function(oSettings) {
oSettings.oPreviousSearch.oSearchCaches = {};
oSettings.oApi._fnCallbackReg( oSettings, 'aoRowCallback', function( nRow, aData, iDisplayIndex, iDisplayIndexFull) {
var searchStrings = [];
var oApi = this.oApi;
var cache = oSettings.oPreviousSearch.oSearchCaches;
// Global search string
// If there is a global search string, add it to the search string array
if (oSettings.oPreviousSearch.sSearch) {
searchStrings.push(oSettings.oPreviousSearch.sSearch);
}
// Individual column search option object
// If there are individual column search strings, add them to the search string array
searchTxt=$('#filter_input input[type="text"]').val();
searchTxt+=$('#search_input').val();
alert("txt" + searchTxt);
if ((oSettings.aoPreSearchCols) && (oSettings.aoPreSearchCols.length > 0)) {
for (var i in oSettings.aoPreSearchCols) {
if (oSettings.aoPreSearchCols[i].sSearch) {
searchStrings.push(searchTxt);
}
}
}
// Create the regex built from one or more search string and cache as necessary
if (searchStrings.length > 0) {
var sSregex = searchStrings.join("|");
if (!cache[sSregex]) {
// This regex will avoid in HTML matches
cache[sSregex] = new RegExp("("+escapeRegExpSpecialChars(sSregex)+")(?!([^<]+)?>)", 'i');
}
var regex = cache[sSregex];
}
// Loop through the rows/fields for matches
jQuery('td', nRow).each( function(i) {
// Take into account that ColVis may be in use
var j = oApi._fnVisibleToColumnIndex( oSettings,i);
// Only try to highlight if the cell is not empty or null
alert(""+ aData[j]);
if (aData[j]) {
// If there is a search string try to match
if ((typeof sSregex !== 'undefined') && (sSregex)) {
alert("here");
this.innerHTML = aData[j].replace( regex, function(matched) {
return "<span class='filterMatches'>"+matched+"</span>";
});
}
// Otherwise reset to a clean string
else {
this.innerHTML = aData[j];
}
}
});
return nRow;
}, 'row-highlight');
return this;
};
Wherever the search functionality is and if you are using mData to populate json data, use mData information to retrieve the column data and highlight ( DO NOT use indexes to retrieve column data for search and highlight)
var colProp = oSettings.aoColumns[i].mData;
jQuery('td', nRow).each( function(i) {
/* Take into account that ColVis may be in use
var j = oApi._fnVisibleToColumnIndex( oSettings,i);
Only try to highlight if the cell is not empty or null
*/
var colProp = oSettings.aoColumns[i].mData;
if (aData[colProp] !== undefined && aData[colProp] !== null && aData[colProp] !== "") {
// If there is a search string try to match
if ((typeof sSregex !== 'undefined') && (sSregex)) {
var mapObj = {
'®' : "\u00AE",
'™' : "\u2122",
'"' : "\u201C",
' ' : " "
};
aData[colProp] = aData[colProp].replace(/(®)|(™)|(")|( )/gi, function(matched){
return mapObj[matched];
});
this.innerHTML = aData[colProp].replace( regex, function(matched) {
return "<span class='filterMatches'>"+matched+"</span>";
});
}
else {
this.innerHTML = aData[colProp];
}
}
});
return nRow;
}, 'row-highlight');
return this;

Removing duplicates from autocomplete results Json

I have an issue where I have added two feature classes and it means that I sometimes get results which are duplicated in the autosuggest. I wondered if there is a way I can some how check for duplicates and fetch an alternative instead of showing the same result twice.
This is my code here (working): http://jsfiddle.net/spadez/nHgMX/4/
$(function() {
jQuery.ajaxSettings.traditional = true;
function log( message ) {
$( "<div>" ).text( message ).prependTo( "#log" );
$( "#log" ).scrollTop( 0 );
}
$( "#city" ).autocomplete({
source: function( request, response ) {
$.ajax({
url: "http://ws.geonames.org/searchJSON",
dataType: "jsonp",
data: {
featureClass: ["A","P"],
style: "full",
maxRows: 7,
name_startsWith: request.term,
country: "UK"
},
success: function( data ) {
response( $.map( data.geonames, function( item ) {
return {
label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
value: item.name
}
}));
}
});
},
minLength: 1,
select: function( event, ui ) {
log( ui.item ?
"Selected: " + ui.item.label :
"Nothing selected, input was " + this.value);
},
open: function() {
$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
},
close: function() {
$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
}
});
});
Any help or information would be much appreciated
Hard to tell exactly what you're asking. But to remove duplicates from an array of objects, you can use underscore's _.uniq()
$.map( _.uniq(data.geonames, false, function(o){return o.adminName1})
Here's a jsfiddle that doesn't show duplicates. But again, it's hard to tell what a duplicate really is from your structure, but this code should move you in the right direction
You don't have use underscore, it's really easy to implement uniq on your own, just look at azcn2503's answer
I modified the code slightly so that it does the following:
Puts all the autocomplete entries in to an object, with the autocomplete value as the key
Converts this object back in to an array and returns it
By doing this, any duplicate keys simply overwrite the previous one.
The success function now looks like this:
success: function( data ) {
var x = $.map( data.geonames, function( item ) {
return {
label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
value: item.name
}
});
// Create an object to easily filter out duplicates (key of same name will simply be reused)
var x2 = {};
for(var i in x) {
x2[x[i].value] = x[i];
}
// Create a new array that simply converts the object in to a de-duplicated array
var x3 = [];
for(var i in x2) {
x3.push(x2[i]);
}
// Return the array
response(x3);
}
I have tested it and it seems to be working, although your issue with the duplicates appearing in the first place is not something I can replicate.
Updated fiddle: http://jsfiddle.net/nHgMX/8/
If your ajax call is returning an array with the response value, you can run it through a plugin to remove duplicate entries. Here's a plugin that I found on another SO thread somewhere a while back.
function ArrayNoDupes(array) {
var temp = {};
for (var i = 0; i < array.length; i++)
temp[array[i].value] = true;
var r = [];
for (var k in temp)
r.push(k);
return r;
}
I may be mistaken, but you would implement it into your existing code by changing the following line:
source: function( ArrayNoDupes(request), response )
EDIT: Updated function per Juan Mendes' comment

jQuery UI AutoComplete: Only allow selected valued from suggested list

I am implementing jQuery UI Autocomplete and am wondering if there is any way to only allow a selection from the suggested results that are returned as opposed to allowing any value to be input into the text box.
I am using this for a tagging system much like the one used on this site, so I only want to allow users to select tags from a pre-populated list returned to the autocomplete plugin.
You could also use this:
change: function(event,ui){
$(this).val((ui.item ? ui.item.id : ""));
}
The only drawback I've seen to this is that even if the user enters the full value of an acceptable item, when they move focus from the textfield it will delete the value and they'll have to do it again. The only way they'd be able to enter a value is by selecting it from the list.
Don't know if that matters to you or not.
I got the same problem with selected not being defined. Got a work-around for it and added the toLowerCase function, just to be safe.
$('#' + specificInput).autocomplete({
create: function () {
$(this).data('ui-autocomplete')._renderItem = function (ul, item) {
$(ul).addClass('for_' + specificInput); //usefull for multiple autocomplete fields
return $('<li data-id = "' + item.id + '">' + item.value + '</li>').appendTo(ul);
};
},
change:
function( event, ui ){
var selfInput = $(this); //stores the input field
if ( !ui.item ) {
var writtenItem = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val().toLowerCase()) + "$", "i"), valid = false;
$('ul.for_' + specificInput).children("li").each(function() {
if($(this).text().toLowerCase().match(writtenItem)) {
this.selected = valid = true;
selfInput.val($(this).text()); // shows the item's name from the autocomplete
selfInput.next('span').text('(Existing)');
selfInput.data('id', $(this).data('id'));
return false;
}
});
if (!valid) {
selfInput.next('span').text('(New)');
selfInput.data('id', -1);
}
}
}
http://jsfiddle.net/pxfunc/j3AN7/
var validOptions = ["Bold", "Normal", "Default", "100", "200"]
previousValue = "";
$('#ac').autocomplete({
autoFocus: true,
source: validOptions
}).keyup(function() {
var isValid = false;
for (i in validOptions) {
if (validOptions[i].toLowerCase().match(this.value.toLowerCase())) {
isValid = true;
}
}
if (!isValid) {
this.value = previousValue
} else {
previousValue = this.value;
}
});
This is how I did it with a list of settlements:
$("#settlement").autocomplete({
source:settlements,
change: function( event, ui ) {
val = $(this).val();
exists = $.inArray(val,settlements);
if (exists<0) {
$(this).val("");
return false;
}
}
});
i just modify to code in my case & it's working
selectFirst: true,
change: function (event, ui) {
if (ui.item == null){
//here is null if entered value is not match in suggestion list
$(this).val((ui.item ? ui.item.id : ""));
}
}
you can try
Ajax submission and handling
This will be of use to some of you out there:
$('#INPUT_ID').autocomplete({
source: function (request, response) {
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
url: autocompleteURL,
data: "{'data':'" + $('INPUT_ID').val() + "'}",
dataType: 'json',
success: function (data) {
response(data.d);
},
error: function (data) {
console.log('No match.')
}
});
},
change: function (event, ui) {
var opt = $(this).val();
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
url: autocompleteURL,
data: "{'empName':'" + name + "'}",
dataType: 'json',
success: function (data) {
if (data.d.length == 0) {
$('#INPUT_ID').val('');
alert('Option must be selected from the list.');
} else if (data.d[0] != opt) {
$('#INPUT_ID').val('');
alert('Option must be selected from the list.');
}
},
error: function (data) {
$(this).val('');
console.log('Error retrieving options.');
}
});
}
});
I'm on drupal 7.38 and
to only allow input from select-box in autocomplete
you only need to delete the user-input at the point,
where js does not need it any more - which is the case,
as soon as the search-results arrive in the suggestion-popup
right there you can savely set:
**this.input.value = ''**
see below in the extract from autocomplete.js ...
So I copied the whole Drupal.jsAC.prototype.found object
into my custom module and added it to the desired form
with
$form['#attached']['js'][] = array(
'type' => 'file',
'data' => 'sites/all/modules/<modulname>_autocomplete.js',
);
And here's the extract from drupal's original misc/autocomplete.js
modified by that single line...
Drupal.jsAC.prototype.found = function (matches) {
// If no value in the textfield, do not show the popup.
if (!this.input.value.length) {
return false;
}
// === just added one single line below ===
this.input.value = '';
// Prepare matches.
=cut. . . . . .
If you would like to restrict the user to picking a recommendation from the autocomplete list, try defining the close function like this. The close function is called when the results drop down closes, if the user selected from the list, then event.currentTarget is defined, if not, then the results drop down closed without the user selecting an option. If they do not select an option, then I reset the input to blank.
//
// Extend Autocomplete
//
$.widget( "ui.autocomplete", $.ui.autocomplete, {
options: {
close: function( event, ui ) {
if (typeof event.currentTarget == 'undefined') {
$(this).val("");
}
}
}
});
You can actually use the response event in combination to the change event to store the suggested items like so:
response: function (event, ui) {
var list = ui.content.map(o => o.value.toLowerCase());
},
change: function (event, ui) {
if (!ui.item && list.indexOf($(this).val().toLowerCase()) === -1 ) { $(this).val('');
}

Categories

Resources