jquery autocomplete with external json source - javascript

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

Related

How do I add a second variable value to the jQuery widget 'Autocomplete'?

I have been using the jQuery ‘Autocomplete Widget’ for a number of years now. This has always been done but passing a value with ‘term’ to the PHP SQL code like this;
$( "#cs1" ).autocomplete({
autoFocus: true,
minLength: 3,
source: "gethint.php",
select: function( event, ui ) {
// This if undes the readonly on the Fname input field below
if ( ui.item.label == 'NONHAM' ) {$('#Fname').prop('readonly', false);}
$( "#cs1" ).val( ui.item.label );
$( "#hints" ).val( ui.item.value );
$( "#Fname" ).val( ui.item.desc );
var nc = $( "#thenetcallsign" ).html();
//return false;
}
})
.data( "ui-autocomplete" )._renderItem = function( ul, item ) {
return $( "<li>" )
.append( "<a>" + item.label + " ---> " + item.desc + "</a>" )
.appendTo( ul );
};
});
But now I have to add another condition to the SQL code to return a more detailed value. The value for this additional condition is;
var nc = $( "#thenetcallsign" ).html();
The problem is I don’t know how to add this to ‘term’ or a separate variable and pass it to gethint.php using the ‘Autocomplete’ widget.
Once I get the extra value to the PHP program I know what to do.
Would somebody please explain or show me how to do this?
You might have to stringify it but pass the extraParams
extraParams: { type: "CoolCode" },
var nc = $("#thenetcallsign").html();
$("#cs1").autocomplete({
autoFocus: true,
minLength: 3,
source: "gethint.php",
extraParams: {
nc: nc
},
select: function(event, ui) {
// This if undes the readonly on the Fname input field below
if (ui.item.label == 'NONHAM') {
$('#Fname').prop('readonly', false);
}
$("#cs1").val(ui.item.label);
$("#hints").val(ui.item.value);
$("#Fname").val(ui.item.desc);
var nc = $("#thenetcallsign").html();
//return false;
}
})
.data("ui-autocomplete")._renderItem = function(ul, item) {
return $("<li>")
.append("<a>" + item.label + " ---> " + item.desc + "</a>")
.appendTo(ul);
};
});
source could be a function in order to get more flexibility
$( "#cs1" ).autocomplete({
/* ... */
source: function(request, response) {
$.getJSON( "gethint.php", {
term: request.term ,
nc: $( "#thenetcallsign" ).html()
}, response );
},
/* ... */
});

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 ) { ... };

How to get JQuery Autocomplete to work with categories?

I have an input field like:
<input id="categoria" name="nome_categoria" type="text" required minlength="2">
In JS, I've got (from Jquery website):
$.widget( "custom.catcomplete", $.ui.autocomplete, {
_renderMenu: function( ul, items ) {
var that = this,
currentCategory = "";
$.each( items, function( index, item ) {
if ( item.category != currentCategory ) {
ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" );
currentCategory = item.category;
}
that._renderItemData( ul, item );
});
}
});
I'm getting the data from PHP, in valid JSON format:
[{"Label":"Vendas","Category":"Recebimentos"},{"Label":"Fornecedores","Category":"Pagamentos"}]
I've tried several things but none is making autocomplete to work with categories:
$('#categoria').catcomplete({
delay:0,
source: 'search.php',
});
I can see in the "Network" tab in Chrome Dev tools, that the letters I type in the input field are being searched, but nothing is displayed in the input form, so I tried:
$('#categoria').autocomplete({
minLength:1,
source: function(request, response) {
$.ajax({
url: 'search.php',
dataType: 'json',
data: { palavra : request.term },
success: function(result) {
response(result);
}
});
}
});
This second approach is filtering the JSON returned from PHP with the letters typed in the input, it seems OK but I get an empty dropdown box in the field.
I've seen similar questions, including this one but so far, nothing. How do I get autocomplete with categories?
Thanks for your help!
The first solution above works well, if instead of "Label", I use "label" and instead of "Category" I use "category".

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

Mystery ajax request occurring somehow

Whenever I type in the autocomplete field an ajax request is sent and there is no code I've written to do this. Checking the console I see it's a 400 GET request to the controller that loaded this view with param (json) appended to the url. I'm absolutely stumped.
<head>
<script data-main="<?=base_url()?>public/requirejs/main.js" src="<?=base_url()?>public/requirejs/require-jquery.js"></script>
<script>
requirejs(['a_mod'],
function(a_mod) {
$(document).ready(function() {
var param = [];
param = $('#elem').attr('value');
a_mod.foo(param, "#someElem");
});
});
<script>
main.js
require(["jquery",
"jquery-ui"],
function() {
}
);
The autocomplete function
'foo' : function(param, elementAutocomplete, elementTags) {
console.log("init ac");
$(elementAutocomplete).autocomplete({
source: param,
minLength: 1,
select: function (event, ui) {
event.preventDefault();
//
}
}).data( "autocomplete" )._renderItem = function( ul, item ) {
return $("<li></li>")
.data( "item.autocomplete", item )
.append( '<a>' + item.label + '</a>' )
.appendTo(ul);
}
},
Your source attribute for the autocompleter is a string:
param = $('#elem').attr('value');
And a string source means that it is a URL:
Autocomplete can be customized to work with various data sources, by just specifying the source option. A data source can be:
an Array with local data
a String, specifying a URL
a Callback
Saying var param = []; just means that param is initialized as an empty array, it doesn't mean that param will always be an array. You need to fix your param value to be an array.

Categories

Resources