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;
}
...
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/
debugging screenshot
$.ajax({
url: postUrl,
type: 'GET',
dataType: 'json',
data: { "id": num },
contentType: "application/json; charset=utf-8",
success: function (data) {
$.each(data, function (id, allFollowers) {
result += 'Title : ' + **data** + '<br/>';
});
I've tried: data.allFollowers[0].screeName, data[0].allFollowers[0].screeName...
I can see these values exist here in debug mode, however it returns a null error..?
Based on your screenshot, I'm assuming the data somewhat looks like this:
//data is an object, with an array of allFollowers objects
var data = {
"allFollowers": [{
"AlternateText": "no photo",
"profileImage": "http://foo.com/foo",
"screenName": "foo",
"userID": 15785100
},
{
"AlternateText": "no photo",
"profileImage": "http://bar.com/bar",
"screenName": "bar",
"userID": 12345678
}
]
};
You're iterating on data only/instead of its child array (allFollowers). So you'll have to go one level deeper:
$.each(data, function(key, obj) {
$.each(obj, function(i, value){
console.log("screen name %i: %o, User ID: %o", i, value.screenName, value.userID);
})
})
Console:
screen name 0: "foo", User ID: 15785100
screen name 1: "bar", User ID: 12345678
Hth...
I think your mistake is about using $.each function. You should refer to your data using some code like:
$.each(data, function (id, follower) {
result += 'Title : ' + follower + '<br/>';
});
For more info refer to this jQuery API Documentation.
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
}
});
}
I am trying to reformat a dynamically created JSON output into a format that can be consumed by the x-editable select type source[]. I need help building the array so that the re-formated JSON output looks like this:
{value: 2, name: 'Maintenance'},
Below is a sample original JSON which I am consuming:
{"COLUMNS":["SECTIONCOMMONNAME"],"DATA":[["Aircraft Overview"],["Email Server Settings"],["Maintenance"],["Page Sections"],["WOW"]]}
The code I am using is:
$(document).ready(function () {
var myURL = 'https://api.myjson.com/bins/3nzdj';
var myarray = [];
$.ajax({
url: myURL,
dataType: 'json',
success: function (e) {
console.log('My created console output:' +'<br>');
$.each(e.DATA, function (i, jsonDataElem) {
console.log("{value: " + i + ', ' + "name: " + '"'+this+"'}");
var item = {
"value": i,
"name": this
};
myarray.push(item);
});
var newJson = JSON.stringify(myarray);
console.log('My stringify output:' +'<br>' +newJson);
}
});
$('.sectionsAvailable').editable({
name: 'template',
type: 'select',
placement: 'right',
send: 'always',
value: 1,
source: [], //newJson (my new var)
/* should be in this format:
source: [{
value: 1,
text: 'text1'
}, {
value: 2,
text: 'text2'
}]*/
});
};
});
After the stringify, the output is close, but wont work. It looks like this:
{"value":2,"name":["Maintenance"]}
and needs to look like thisL
{value:2,name:'Maintenance'},
Here is a JSfiddle showing the output here.
it seems you are assigning complete array instead of value at index 0 try this
var item = {
"value": i,
"name": this[0] // gives elemnt at index 0
};
myarray.push(item);
FIDDLE
I was able to answer my own question. There might be a better way, but this works:
var myURL = 'https://api.myjson.com/bins/3nzdj';
$.getJSON(myURL, function(data) {
var output = '';
$.each(data.DATA, function(key, val) {
output +='{value: ';
output += "'"+key+"'";
output +=',text:';
output += "'"+val+"'";
output +='}';
output +=',';
});
var outputAdapted = '['+output+']'
$('.sectionsAvailable').editable({
name: 'template',
type: 'select',
placement: 'right',
send: 'always',
value: 1,
// should be in this format:
source:
function() {
return outputAdapted;
},
});
});
My FIDDLE I hope this can help someone else.