I have a json named names.json and I need to do an input with autocomplete that looks for 'name' values inside the json.
How do I do that?
I Tried:
$(function () {
var getData = function (request, response) {
$.getJSON(
"/cities.json" + request.term,
function (data) {
response(data);
});
};
var selectItem = function (event, ui) {
$("#myInput").val(ui.item.value);
return false;
}
$("#myInput").autocomplete({
source: getData,
select: selectItem,
minLength: 2,
change: function() {
$("#myInput").val("").css("display", 2);
}
});
});
But I'm doing something wrong in my code.
I get a json from an external file
JSON is exactly from this format, I need to return the values of 'names' when I type in the input:
[
{
"id":25,
"name":"locale name test 2",
"state_id":6
},
{
"id":667,
"name":"locale name test 3",
"state_id":24
},
{
"id":331,
"name":"locale name test 4",
"state_id":13
},
{
"id":776,
"name":"locale name test 5",
"state_id":26
},
{
"id":680,
"name":"locale name test 6",
"state_id":26
}
]
Here is base working autocomplete example based on the data you gave.
HTML:
<input type="text" id="suggestion" />
Jquery:
var data = [
{
"id":25,
"name":"locale name test 2",
"state_id":6
},
{
"id":667,
"name":"locale name test 3",
"state_id":24
},
{
"id":331,
"name":"locale name test 4",
"state_id":13
},
{
"id":776,
"name":"locale name test 5",
"state_id":26
},
{
"id":680,
"name":"locale name test 6",
"state_id":26
}
]
var data_arr = data.map(function(val){
return val.name;
}). //get all the val.names on an array to make
// it easier when it comes setting autocomplete source
console.log(data_arr)
$("#suggestion").autocomplete({
source: data_arr,
minLength: 2
});
Here is the working version of the above code hosted on jsFiddle
In addition:
if you have to get the data from external source, here is how I would do it
HTML:
<input type="text" id="suggestion" />
Jquery:
// I have hosted the same data you provided on myjson.com
$.getJSON( "https://api.myjson.com/bins/1gkh25", function( data ) {
var data_arr = data.map(function(val){
return val.name;
})
auto(data_arr)
});
function auto(data_arr){
$("#suggestion").autocomplete({
source: data_arr,
minLength: 2
});
}
try it on jsFiddle
Related
I am using "jQuery UI Autocomplete" to filter the JSON data, I am using following code for it
<input type="text" name="searchKeywords" id="ninecSearchKeywords" placeholder="How To...">
and then JS as
jQuery(document).ready(function($){
$.getJSON("apiUrl", function(data){
$.each(data, function(key, value){
$("#ninecSearchKeywords").autocomplete({
source: value.keys,
autoFocus: true,
select: function (event, ui) {
window.location = value.pageLink;
}
});
});
});
});
and JSON Data is
[
{
pageID: "454",
pageLink: "url",
sectionID: "a599d36c4c7a71ddcc1bc7259a15ac3a",
anchorLink: "anchor1",
keys: [
"Result 1",
"Result 2",
"Result 3"
]
},
{
pageID: "455",
pageLink: "url",
sectionID: "8d993394c892dcaa8683dc4ba4fae21d",
anchorLink: "anchor2",
keys: [
"Result 4",
"Result 5",
"Result 6"
]
},
{
pageID: "456",
pageLink: "url",
sectionID: "dce6920a3408ae9a8e61b75a4e5fd6ca",
anchorLink: "anchor3",
keys: [
"Result 7",
"Result 8",
"Result 9"
]
}
]
This is working fine for #2 and #3 iteration and I am able to search for Result 4 to Result 9 but for the first iteration i.e. Result 1,2 and 3 no results are showing in dropdown.
Can anyone knows what went wrong here?
The autocomplete source will not get updated inside loop. Create the data first and then add the source to autocomplete.
jQuery(document).ready(function($){
$.getJSON("apiUrl", function(data){
var keys = [];
var keyLinkMap = {};
$.each(data, function(key, value){
for(let i = 0; i <= value.keys.length; i++) {
keys.push({label: value.keys[i], value:value.pageLink});
}
});
$("#ninecSearchKeywords").autocomplete({
source: keys,
autoFocus: true,
select: function (event, ui) {
window.location = value.pageLink;
}
});
});
});
I am using Typeahead (with default suggestions) with Bloodhound and everything works fine so far. However, I have some problems when I try to dynamically change the values of the suggestions.
For example, I have an array of available suggestions like [ "A", "B", "C"] when I select one of those elements it is added to a combo box. But I want to ensure that each element is only selected once. That's why I want to remove the element from the list. So if a user chooses the element "B" the list of available suggestions should look like: ["A", "C"].
Here is the code that I try:
var available_items = [ "Item 1", "Item 2", ... , "Item N" ];
var my_bloodhound = new Bloodhound(
{
local: available_items,
queryTokenizer: Bloodhound.tokenizers.whitespace,
datumTokenizer: Bloodhound.tokenizers.whitespace
)};
$( "#my-typeahead-field" ).typeahead(
{
minLength: 0,
highlight: true
},
{
name: 'items',
limit: 10,
source: search_function,
});
var f = function( )
{
return available_categories.filter( element => !selected_items.includes( element ) );
}
function search_function( query, sync, async )
{
if( "" === query )
{
sync( f )
}
else
{
my_bloodhound.search( query, sync);
}
}
Please note that the array "selected_items" is filled when a user select an element of the suggestion list. I try many different approachs like this:
http://jsfiddle.net/likeuntomurphy/tvp9Q/
or the one where I use the typeahead:selected event:
$("#my-typeahead-field").bind('typeahead:select', function( event, item )
{
console.log('Selection: ' + item);
selected_items.push( item );
available_categories = available_categories.filter( element => !selected_items.includes( element ) );
});
But none of them works. Does anyone have an idea how to fix this problem?
It's a solution. You can refer it. Hope to help, my friend :))
var selected = [];
var available_items = [ "Item 1", "Item 2", "Item 3" ];
var select = function(e, datum, dataset) {
selected.push(datum);
$("#selected").text(JSON.stringify(selected));
$("input.typeahead").val("");
}
var filter = function(suggestions) {
return $.grep(suggestions, function(suggestion) {
return $.inArray(suggestion, selected) === -1;
});
}
var data = new Bloodhound({
name: 'animals',
local: available_items,
datumTokenizer: function(d) {
return Bloodhound.tokenizers.whitespace(d);
},
queryTokenizer: Bloodhound.tokenizers.whitespace
});
data.initialize();
$('input.typeahead').typeahead(null,
{
name: 'animals',
displayKey: function(item){
return item;
},
/* don't use
source: data.ttAdapter(), */
source: function(query, cb) {
data.get(query, function(suggestions) {
cb(filter(suggestions));
});
},
templates: {
empty: '<div class="empty-message">No matches.</div>'
}
}
).bind('typeahead:selected', select);
http://jsfiddle.net/mtLkns0e/
A company email-generating application I'm working on has an autocomplete input to autofill email theme data into a form. The data is returned as a JSON object, but a couple of the object values extraps and extraul contain multidimensional arrays. I'm able to get the plain key:value data just fine out in the response, but I can't seem to figure out how to pull the arrays in so I can loop over them to update certain sections of the form.
Here's a look at some of the JSON code coming in:
0:
emaildate: "2019-01-10"
extraps: Array(2)
0: {extrap: "test paragraph", position: 1}
1: {extrap: "another paragraph", position: 3}
length: 2
__proto__: Array(0)
extraul: Array(4)
0: {ulid: 1, position: 2, li: "list item 1", liposition: 1}
1: {ulid: 1, position: 2, li: "list item 2", liposition: 2}
2: {ulid: 1, position: 2, li: "list item something new", liposition: 3}
3: {ulid: 1, position: 2, li: "A new list item", liposition: 4}
length: 4
__proto__: Array(0)
id: 44
label: "Some Kind of Email Theme - 2019-01-10"
lastupdated: "2019-01-06 02:00:04"
store: "Premier"
themedesc: "Here's a description of the theme."
themeimage: null
themeincludeextrap: 1
themeincludeul: 1
themelink: "some-kind-of-email-theme"
themelinkinclude: 1
themename: "Some Kind of Email Theme"
themenotes: "Some notes about it"
themesortorder: 0
value: "Some Kind of Email Theme"
__proto__: Object
length: 1
__proto__: Array(0)
And here's a look at the javascript to bring it in from autotheme.php:
//Autofill Theme Info based on text entry
$( "#themename" ).autocomplete({
source: function( request, response ) {
$.ajax({
url: "autotheme.php",
type: "GET",
dataType: "json",
data: {
q: request.term
},
success: function(data) {
console.log(data);
response($.map(data, function(item) {
return {
id: item.id,
value: item.value,
label: item.label,
themename: item.themename,
themenotes: item.themenotes,
themedesc: item.themedesc,
themeimage: item.themeimage,
themeincludeextrap: item.themeincludeextrap,
themeincludeul: item.themeincludeul,
themelinkinclude: item.themelinkinclude,
themelink: item.themelink,
themeextraps: item.extraps,
themeextraul: item.extraul
}
}))
},
error: function(errorThrown){
console.log(errorThrown);
console.log("There is an error with theme autocomplete.");
}
});
},
minLength: 2,
select: function(event, ui) {
if (ui.item) {
$this = $(this);
$('#themeid').val('');
$('#extratext').html('');
$('#themename').val(ui.item.themename);
$('#themenotes').val(ui.item.themenotes);
$('#themedesc').val(ui.item.themedesc);
var themeimage = ui.item.themeimage;
var themeincludeextrap = ui.item.themeincludeextrap;
var themeincludeul = ui.item.themeincludeul;
var themelinkinclude = ui.item.themelinkinclude;
var themeextraps = ui.item.extraps;
var themeextraul = ui.item.extraul;
if(themeextraps !== undefined) {
var extrapcount = themeextraps.length;
}
if(themeextraul !== undefined) {
var extraulcount = themeextraul.length;
}
if((themeextraps !== undefined) || (themeextraul !== undefined)) {
var extratextpositions = {};
$.each(themeextraps, function(i, themeextraps) {
extratextpositions[themeextraps.position] = 'p';
})
$.each(themeextraul, function(i, themeextraul) {
extratextpositions[themeextraul.position] = 'ul';
})
$.each(extratextpositions, function(key, value) {
if(extratextpositions[key] == 'p') {
addExtraP.call(this);
} else {
addExtraUl.call(this);
}
});
$('#themelink').val(ui.item.themelink);
if(themelinkinclude == 1) {
$('#themelinkinclude').prop("checked", true);
} else {
$('#themelinkinclude').prop("checked", false);
}
event.preventDefault();
}
},
open: function(event, ui) {
$(".ui-autocomplete").css("z-index", 1000);
},
complete: function(){
$("#themename").removeClass("ui-autocomplete-loading");
}
}
});
I'm able to get the simple key:value values just fine, but I get undefined for the arrays. I'm sure there's a different way I need to pull those in, but I don't know how and can't seem to find the answer in other threads on here. Any help would be greatly appreciated!
Figured out a way to get around this problem, thanks to some help from #Bibberty. I'm not sure if this is the most graceful or easy way to solve it, but it worked for me. I created an array from the JSON data values, then created variables from the arrays within the data array and added them to the response return value. Here's the new functional code (or, at least, the part that matters):
//Autofill Theme Info based on text entry
$( "#themename" ).autocomplete({
source: function( request, response ) {
$.ajax({
url: "autotheme.php",
type: "GET",
dataType: "json",
data: {
q: request.term
},
success: function(data) {
const results = data.map(function (value, label) {
return [value];
})
var extraps = results[0][0]['extraps'];
var extraul = results[0][0]['extraul'];
response($.map(data, function(item) {
return {
id: item.id,
value: item.value,
label: item.label,
themename: item.themename,
themenotes: item.themenotes,
themedesc: item.themedesc,
themeimage: item.themeimage,
themeincludeextrap: item.themeincludeextrap,
themeincludeul: item.themeincludeul,
themelinkinclude: item.themelinkinclude,
themelink: item.themelink,
extraps: extraps,
extraul: extraul
}
}))
$("#themename").removeClass("ui-autocomplete-loading");
},
error: function(errorThrown){
console.log(errorThrown);
console.log("There is an error with theme autocomplete.");
}
});
},
minLength: 2,
select: function(event, ui) {
if (ui.item) {
$this = $(this);
console.log(ui.item.extraps);
$('#themeid').val('');
$('#extratext').html('');
$('#themename').val(ui.item.themename);
$('#themenotes').val(ui.item.themenotes);
$('#themedesc').val(ui.item.themedesc);
var themeimage = ui.item.themeimage;
var themeincludeextrap = ui.item.themeincludeextrap;
var themeincludeul = ui.item.themeincludeul;
var themelinkinclude = ui.item.themelinkinclude;
var themeextraps = ui.item.extraps;
var themeextraul = ui.item.extraul;
if(themeextraps !== undefined) {
var extrapcount = themeextraps.length;
}
if(themeextraul !== undefined) {
var extraulcount = themeextraul.length;
}
...
I have to code to get source from different endpoints for typeahead based on number of characters entered in input field. However the suggestions from new source are displayed only after entering extra character. Suggestions that should show after input length is 3 are showing up on entering 4 chraracters
I have created sample of problem in jsfiddle
http://jsfiddle.net/yj7hdzka/
In the sample new suggestion from new data source with title "some title here3" should show as soon as I entered 3 characters but doesnt show until 4 characters are entered in input field.
Here is html and javascript
<input type="text" id="search-input">
<button id="switch">Switch Data Source</button>
<span id="sourceSelected"></span>
var data1 = [{
label: "some title here1",
desc: "some option here1",
category: [{
name: "category 1"
}, {
name: "categoy 2"
}]
}, {
label: "some title here2",
desc: "some option here2",
category: [{
name: "category 1"
}, {
name: "categoy 2"
}]
}];
var data2 = [{
label: "some title here3",
desc: "some option here3",
category: [{
name: "category 1"
}, {
name: "categoy 2"
}]
}, {
label: "some title here4",
desc: "some option here4",
category: [{
name: "category 1"
}, {
name: "categoy 2"
}]
}];
var titles = new Bloodhound({
datumTokenizer: function (data) {
return Bloodhound.tokenizers.whitespace(data.label);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data1
});
titles.initialize();
$('#search-input').typeahead({
highlight: true
}, {
name: 'titles',
displayKey: 'label',
source: titles.ttAdapter()
});
var sourceSelected = $('#sourceSelected');
var toggle = false;
$('#search-input').keyup(function(){
if($('#search-input').val().length > 2){
titles.local = data2;
sourceSelected.text('Data Source 2');
} else {
titles.local = data1;
sourceSelected.text('Data Source 1');
}
titles.initialize(true);
});
sourceSelected.text('Data Source 1');
I faced two different problems while trying to find a solution:
the latest typeahead version seems to be less stable than the previous version 0.10.2 (and the Original twitter project is considered dead, some community forks exist and are maintained).
a bound data source does not react to updates properly.
What I changed:
Switched to the 0.10.2 typeahead bundle.
manually added Bloodhound search result.
Updated code:
var filter = function(suggestions) {
return $.grep(suggestions, function(suggestion) {
return -1;
});
}
var titles = new Bloodhound({
name: 'titles',
datumTokenizer: function(data) {
return Bloodhound.tokenizers.whitespace(data.label);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data1
});
titles.initialize();
$('#search-input').typeahead({
highlight: true
}, {
name: 'titles',
displayKey: 'label',
source: function(query, callbackFunc) {
titles.clear();
if ($('#search-input').val().length > 2) {
titles.local = data2;
sourceSelected.text('Data Source 2');
} else {
titles.local = data1;
sourceSelected.text('Data Source 1');
}
titles.initialize(true);
titles.get(query, function(suggestions) {
callbackFunc(filter(suggestions));
});
}
});
Part of my answer has been taken from this SO answer and to be honest, I don't exactly know how the get() method of the typeahead plugin was implemented and why it requires a callback function as seen in my solution.
Here's a working jsfiddle, I hope that's what you were looking for.
I have a jQuery script that will get a JSON response and create as many "player" objects as there are in the response.
It will then add to availablePlayers which I then use as the variable for the source: field of autocomplete
When a user selects a player name and clicks the "add" button it will, at the moment, just display the guid and name of a player.
However, no matter what letters I type, all the players are given as an option. To illustrate this, if I type "Z" and none of the players have Z in their name, they options are still displayed.
How can I refine this functionality?
HTML
<div class="player-widget">
<label for "players">Players</label>
<input id="player" />
<input id="playerGUID" hidden />
<button id="add">Add</button>
</div>
jQuery
$(document).ready(function(){
var availablePlayers = []; // BLANK ARRAY OF PLAYERS
$("#player").autocomplete({
source: availablePlayers,
response: function (event, ui) {
ui.content = $.map(ui.content, function(value, key) {
return {
label: value.name,
value: value.guid
}
});
},
focus: function(event, ui) {
$("#player").val(ui.item.label);
return false;
},
select: function (event, ui) {
$("#player").val(ui.item.label); // display the selected text
$("#playerGUID").val(ui.item.value); // save selected id to hidden input
return false;
}
});
$.getJSON("http://localhost/Websites/Player-Widgets/service.php", function(data) {
var feedHTML = '';
// LOOP THROUGH EACH PLAYER
$.each(data.players, function(i, player) {
// DEFINE VARIABLES - BASED ON PLAYER ATTRIBUTES
var guid = player.guid;
var name = player.name;
var dob = player.date_of_birth;
var birth = player.birthplace;
var height = player.height;
var weight = player.weight;
var position = player.position;
var honours = player.honours;
// CREATE NEW PLAYER (OBJECT)
var player = {
guid: guid,
name: name,
position: position
};
// ADD TO PLAYER TAG ARRAY
availablePlayers.push(player);
});
console.log("User friendly array");
$.each(availablePlayers, function(i, val) {
console.log(val.guid + " - " + val.name + " [" + val.position + "]");
});
console.log("Array printout");
console.log(JSON.stringify(availablePlayers));
}).done(function(){
console.log("Done! Success!");
$("#player").autocomplete("option", "source", availablePlayers);
});
$("#add").click(function() {
alert($("#playerGUID").val() + " - " + $("#player").val());
});
});
Sample JSON response
{
"players": [
{
"guid": "1",
"name": "Matias Aguero",
"date_of_birth": "1981-02-13",
"birthplace": "San Nicolas, Argentina",
"height": "1.83m (6' 0\")",
"weight": "109kg (17st 2lb)",
"position": "Prop",
"honours": "40 caps"
},
{
"guid": "2",
"name": "George Catchpole",
"date_of_birth": "1994-02-22",
"birthplace": "Norwich, England",
"height": "1.85em (6ft 1\")",
"weight": "104kg (16st 5lb)",
"position": "Centre",
"honours": ""
}
]
}
Your problem is in the source function.
Source function uses request to pass term param to query, and you are ignoring it.
If you're using availablePlayers to query, you should use
source: availablePlayers
and your current function to map {label, text} object in response parameter.
response: function (event, ui) {
ui.content = $.map(ui.content, function(value, key) {
return {
label: value.name,
value: value.guid
}
});
}