Removing duplicates from autocomplete results Json - javascript

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

Related

Jquery autocomplete not filling textbox

I have an autocomplete function that filters through local json to return results to a textbox, however on selecting a location, the autocomplete does not fill the text box. I have tried to include a select method as per the docs but it breaks my functionality. Where should I include the select in my codebase?
Autocomplete function:
$('#autocomplete').autocomplete({
minLength: 1,
source: function(request, response) {
var data = $.grep(suggestion, function(value) {
return value.city.substring(0, request.term.length).toLowerCase() == request.term.toLowerCase(); // Here the suggestion array is filtered based on what the user has typed. User input will be captured in the request.term
});
response(data); // this will return the filtered data which will be attached with the input box.
}
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "ui-autocomplete-item", item )
.append( "<a>" + item.city + "," + item.country + "</a>" )
.appendTo( ul ); // here we are creating and appending appending element based on the response object we got after filtering
};
});
Data
var suggestion =
[
{"id":"1","name":"Goroka","city":"Goroka","country":"Papua New Guinea","iata":"GKA","icao":"AYGA","latitude":"-6.081689","longitude":"145.391881","altitude":"5282","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"2","name":"Madang","city":"Madang","country":"Papua New Guinea","iata":"MAG","icao":"AYMD","latitude":"-5.207083","longitude":"145.7887","altitude":"20","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"3","name":"Mount Hagen","city":"Mount Hagen","country":"Papua New Guinea","iata":"HGU","icao":"AYMH","latitude":"-5.826789","longitude":"144.295861","altitude":"5388","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"4","name":"Nadzab","city":"Nadzab","country":"Papua New Guinea","iata":"LAE","icao":"AYNZ","latitude":"-6.569828","longitude":"146.726242","altitude":"239","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"5","name":"Port Moresby Jacksons Intl","city":"Port Moresby","country":"Papua New Guinea","iata":"POM","icao":"AYPY","latitude":"-9.443383","longitude":"147.22005","altitude":"146","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
]
The select can be placed before or after the source in your case, as long as it stays in the autocomplete object as a property. You can follow this example:
$('#autocomplete').autocomplete({
minLength: 1,
source: function (request, response) { ... },
select: function (event, ui) {
event.preventDefault();
// [...] your code here
return false;
}
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) { ... };

jquery autocomplete with external json source

I have an autocomplete function that was working with a local json source. Given that it's 16k lines of code, I want to move this to an external json file. However I can't seem to get it working with the external source file. Can anyone point me in the right direction? At the moment this code does not work, but also does not return any errors to the console.
Autocomplete script
$(function() {
$.ajax({
url: "javascripts/airports.json",
dataType: "json",
success: function(request, response) {
var data = $.grep(suggestion, function(value) {
return value.city.substring(0, request.term.length).toLowerCase() == request.term.toLowerCase();
});
$('#autocomplete').autocomplete({
minLength: 1,
source: data,
focus: function(event, ui) {
$('#autocomplete').val(ui.item.city,ui.item.country);
return false;
},
select: function(event, ui) {
$('#autocomplete').val(ui.item.name);
return false;
}
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "ui-autocomplete-item", item )
.append( "<a>" + item.city + "," + item.country + "</a>" )
.appendTo( ul );
};
}
});
});
External data structure
var suggestion =
[
{"id":"1","name":"Goroka","city":"Goroka","country":"Papua New Guinea","iata":"GKA","icao":"AYGA","latitude":"-6.081689","longitude":"145.391881","altitude":"5282","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"2","name":"Madang","city":"Madang","country":"Papua New Guinea","iata":"MAG","icao":"AYMD","latitude":"-5.207083","longitude":"145.7887","altitude":"20","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"3","name":"Mount Hagen","city":"Mount Hagen","country":"Papua New Guinea","iata":"HGU","icao":"AYMH","latitude":"-5.826789","longitude":"144.295861","altitude":"5388","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"4","name":"Nadzab","city":"Nadzab","country":"Papua New Guinea","iata":"LAE","icao":"AYNZ","latitude":"-6.569828","longitude":"146.726242","altitude":"239","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"5","name":"Port Moresby Jacksons Intl","city":"Port Moresby","country":"Papua New Guinea","iata":"POM","icao":"AYPY","latitude":"-9.443383","longitude":"147.22005","altitude":"146","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
]
Your response should be a JSON object (array) where each item is an object with id, label and value keys.
The items in your json files doesn't have the label and value keys, so the autocomplete can't really show them.
Best solution - change the content of the file/response to follow the id/label/value structure.
If you can't do this - you can use the _renderItem function to create your own items in the autocomplete based on the content of the json file:
$('#autocomplete').autocomplete({
...
_renderItem: function( ul, item ) {
return $( "<li>" )
.append( item.name )
.appendTo( ul );
}
...
});

How do store API response into object so I can use it later in script?

I am using the Yelp API to get info on businesses. I plan to eventually map the response. So I need to store it somewhere in my script in order to access the lat/long
My Ajax request has worked judging by console.log of response. I cant seem to do the next step where I store yelp response into either a JSON or GeoJSON
$.ajax("/yelp", {
data: {
term: searchEstablishment,
location: selectedGeography
},
//this works:
success: function(response) {
console.log(response)
},
$.getJSON( "ajax/test.json", function( data ) {
var items = [];
$.each( data, function( key, val ) {
items.push( "<li id='" + key + "'>" + val + "</li>" );
});
$( "<ul/>", {
"class": "my-new-list",
html: items.join( "" )
}).appendTo( "body" );
});

Jquery remote completion, li's are not selectable

I'm trying to create a text input with text completion using a remote host.
I've been trying to use the example in the following URL: http://demos.jquerymobile.com/1.4.0/listview-autocomplete-remote/
this is the javascript code from the example:
$( document ).on( "pageinit", "#myPage", function() {
$( "#autocomplete" ).on( "filterablebeforefilter", function ( e, data ) {
var $ul = $( this ),
$input = $( data.input ),
value = $input.val(),
html = "";
$ul.html( "" );
if ( value && value.length > 2 ) {
$ul.html( "<li><div class='ui-loader'><span class='ui-icon ui-icon-loading'></span></div></li>" );
$ul.listview( "refresh" );
$.ajax({
url: "http://gd.geobytes.com/AutoCompleteCity",
dataType: "jsonp",
crossDomain: true,
data: {
q: $input.val()
}
})
.then( function ( response ) {
$.each( response, function ( i, val ) {
html += "<li>" + val + "</li>";
});
$ul.html( html );
$ul.listview( "refresh" );
$ul.trigger( "updatelayout");
});
}
});
});
so first of all I changed dataType from jsonp to json which makes the ajax call
return a proper json object and the unordered list is filled properly.
the problem that I encounter is that once I see the text completion (the li elements), I can't select any of the elements.
I tried browsing this example on my Galaxy Note 2 and I encountered the same problem, the elements are not selectable.
any ideas how to resolve the issue?
thanks
update
as to #Omar comment i changed the following line:
html += "<li>" + val + "</li>";
to
html += "<li><a href='#'>" + val + "</a></li>";
now i can click on an item but it doesn't do anything. it supposed to close the list and add to the text field the selected item.
You need to delegate an event to generated list items and then update input with the value.
$("#autocomplete").on("click", "li", function () {
/* text of clicked element */
var value = $(this).text();
/* update value of input */
$("#autocomplete-input").val(value);
/* optional - remove autocomplete result(s) */
$(this).parent().empty();
});
Demo

jQuery autocomplete selection event

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();
}
}

Categories

Resources