Another jQuery autocomplete issue - javascript

So, i have read at least 20-30 auto complete problems here on so and i cannot find any solutions. For some odd reason i keep getting value = undefined. Here is my code.
//Cycles through each input and turns it into a person searcher.
$.each(settings.input, function() {
var input = $(this);
input.autocomplete({
delay: 70,
minLength: 2,
source: function(req, add) {
var val = input.val();
$.post(VUI.SITE_URL + "scripts/autocomplete/_AutoComplete.php", {q: val, display_count: settings.displayCount, action: "user"}, function(data) {
data = eval("(" + data + ")");
if (data.length > 0) {
var results = new Array(data.length);
$.each(data, function(key, value) {
results[key] = {desc: value, value: value.firstname + " " + value.lastname};
});
add(results);
} else {
add(["No results..."]);
}
});
},
select: function(event, ui) {
alert(ui.item ? ("Selected: " + ui.item.value + " aka " + ui.item.id) : "Nothing selected, input was " + this.value);
}
}) // end auto complete.
.data("autocomplete")._renderItem = function($ul, item) {
var $li = $("<li></li>"),
$inner = $("<div class='st-display side-content clearfix'style='padding-top:6px'></div>"),
$a = $("<a></a>"),
$img = $("<div class='image fl'></div>").html(ST.Image.getImage({
uid: item.desc.uid,
type: ST.ST_IMAGE_TYPE_THUMBNAIL_SMALL
})),
$content = $("<div class='content fl'></div>").html(
item.desc.firstname + " " + item.desc.lastname + "<br/>" +
"<span class='color:#979797;font-weight:bold'>" + item.desc.city + ", " + item.desc.state + "</span>"
);
$inner.append($img).append($content);
$a.append($inner);
$li.append($a);
$ul.append($li);
return $ul;
} // end _renderItem */
I tried to make it so that its very straight forward. But it wont work! (its facebook like auto complete). The auto complete displays properly (item does not equal undefined at that point), but when i highlight it, item becomes undefined so item.value (line 6347 of jquery.ui.1.8.13) throws exception!
Anyone see problems?
Here is something interesting... When i do not use data("autocomplete")._renderItem (for custom completion) the selecting works! ... So why does overriding the custom rendering cause issues? I am even returning the UL.

The only thing in your code that's different from a working version I've got of something very similar is that I initialise $li with:
var $li = $( '<li></li>' ).data('item.autocomplete', item);
That attaches the data to the list item which I think the autocomplete plugin uses to get the value at selection time.
Hope it helps

Related

How to create new Tags from results containing delimiter " USE "?

Updated Question
So I am running a query and some of the results have the structure "keyword USE 1 or more keywords". When a user selects entries like this, I want the input field to show the keyword(s) to the right of USE. I got it to work for the first select thanks to #DavidDomain, but now I have a new Problem. The selects goes wild after the first selection. I tried to create a Jsfiddler, but I can't seem to get it to work correctly. I copied code directly from my IDE. Here is the original project. If you type in USE and select one of the options, it works perfectly. If you try another selection then it goes crazy. Here is the JSFiddle I tried to create that shows what I did to get to this point.
$('.productName').select2({
ajax: {
url: "https://api.myjson.com/bins/9t7gz",
dataType: 'json',
type: "GET",
delay: 250,
data: function(params) {
return {
key: params.term // search term
};
},
processResults: function(data) {
for (var d = 0; d < data.length; d++) {
if (data[d].text.includes(" USE ")) {
var dataItems = data[d].text.split(" USE ");
if (dataItems[1].toString().includes(";")) {
var dataKeywordItems = dataItems[1].toString().split(";");
for (var ii = 0; ii < dataKeywordItems.length; ii++) {
var option3 = new Option(dataKeywordItems[ii].toString().trim(), dataKeywordItems[ii].toString().trim(), true);
$('.productName').append(option3);
}
} else {
var option = new Option(dataItems[1], dataItems[1], true);
$('.productName').append(option);
}
}
}
return {
results: data
};
},
cache: true
},
placeholder: 'Keyword/keyphrase search...',
minimumInputLength: 2,
tags: true
}).on("select2:select", function(e) {
var splitValues = $('.productName').val().toString().split(" USE ");
if (splitValues[1].includes("; ")) {
var splitKeywords = splitValues[1].toString().split("; ");
$('.productName').val(splitKeywords).trigger("change");
alert(splitKeywords.toString());
// for(var i = 0; i < splitKeywords.length; i++)
// {
// alert(splitKeywords[i].toString().trim());
// $('.productName').val(splitKeywords[i].toString().trim()).trigger("change");
// }
} else {
$('.productName').val(splitValues[1]).trigger("change");
}
});
.select2-selection__rendered {
line-height: 32px !important;
}
.select2-selection {
height: 34px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://npmcdn.com/tether#1.2.4/dist/js/tether.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<div class="container">
<div class="row">
<span class='input-group-btn col-lg-12 col-md-12 col-sm-12'>
<select style="width:70%;" class='productName ' id='productName' width=>
</select>
</span>
</div>
</div>
The two important parts of my code are below:
ProcessResults:
If a keyword contains " USE " this takes the one or more keywords to the right of " USE " and dynamically adds them to the dropdown list.
processResults: function (data) {
for(var d = 0; d < data.length; d++)
{
if(data[d].text.includes(" USE "))
{
var dataItems = data[d].text.split(" USE ");
if(dataItems[1].toString().includes(";"))
{
var dataKeywordItems = dataItems[1].toString().split(";");
for(var ii = 0; ii < dataKeywordItems.length; ii++)
{
var option3 = new Option(dataKeywordItems[ii].toString().trim(), dataKeywordItems[ii].toString().trim(), true);
$('.productName').append(option3);
}
}
else
{
var option = new Option(dataItems[1], dataItems[1], true);
$('.productName').append(option);
}
}
}
return {
results: data
};
},
On select:
This takes a selected keyword that contains " USE " and extracts the 1 or more keywords to the right of " USE " and diplays them in the input field.
.on("select2:select", function(e) {
var splitValues = $('.productName').val().toString().split(" USE ");
if(splitValues[1].includes("; "))
{
var splitKeywords = splitValues[1].toString().split("; ");
$('.productName').val(splitKeywords).trigger("change");
alert(splitKeywords.toString());
// for(var i = 0; i < splitKeywords.length; i++)
// {
// alert(splitKeywords[i].toString().trim());
// $('.productName').val(splitKeywords[i].toString().trim()).trigger("change");
// }
}
else
{
$('.productName').val(splitValues[1]).trigger("change");
}
});
A screenshot of the first select:
A screenshot of a potential second select:
The question is how can I keep the first select results and add the new second select results?
You could use the formatSelection method to change how the selected option should be displayed.
Here is an example:
function format(state) {
if (state.text.indexOf('USE') !== -1) {
return state.text.substring(state.text.indexOf('USE') + 4, state.text.length);
}
return state.text;
}
$('#test').select2({
data:[
{id:0,text:"enhancement"},
{id:1,text:"bug"},
{id:2,text:"duplicate USE copy"},
{id:3,text:"invalid USE wrong; incorrect"},
{id:4,text:"wontfix"}
],
multiple: true,
width: "300px",
formatSelection: format,
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.2/select2.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.2/select2.min.js"></script>
<input type="hidden" id="test" />
I can't get the crappy JsFiddles to work, so I am going to post my answer from my original problem. The process is the same. After a lot of searching and mixing different answers together, I came up with this solution.
$('.productName').select2({
ajax: {
url: "DBHandler.php",
dataType: 'json',
type: "GET",
delay: 250,
data: function (params) {
return {
key: params.term // search term
};
},
processResults: function (data) {
return {
results: data
};
},
cache: true
},
placeholder: 'Keyword/keyphrase search...',
minimumInputLength: 2,
tags: true
}).on("select2:select", function(e) {
var valueToRemove = e.params.data.id;
if(valueToRemove.toString().includes(" USE "))
{
var splitValues = valueToRemove.toString().split(" USE ");
if(!splitValues[1].toString().includes(";"))
{
alert("value does not contain ;");
new_data = $.grep($('.productName').val(), function(id){return id !== valueToRemove;});
alert("new data: " + new_data);
$('.productName > option').prop("selected", false);
$('.productName').val(new_data).trigger('change');
$('.productName').append("<option value = '" + splitValues[1].toString().trim() + "' selected>" + splitValues[1].toString().trim() + "</option>");
}
else
{
var splitKeys = splitValues[1].toLocaleString().split(";");
new_data = $.grep($('.productName').val(), function(id){return id !== valueToRemove;});
$('.productName > option').prop("selected", false);
$('.productName').val(new_data).trigger('change');
splitKeys.forEach(function(item)
{
alert(item);
$('.productName').append("<option value = '" + item.toString().trim() + "' selected>" + item.toString().trim() + "</option>");
});
}
}
});
The onSelect code is the key to solving this problem.
on("select2:select", function(e) {...});
I started by getting the value that is being selected. If this value contains " USE ", I do not want it to be included in the InputField values.
var valueToRemove = e.params.data.id;
I then split this value using " USE " as the delimiter. If the keyword(s) to the right of " USE " do not contain a semi-colon ;, I create an array new_data that holds all of the InputField's current values except the value that is being selected. I then, deselect all of the current selected values using $('.productName > option').prop("selected", false);. Next, I added all of the old selected values back using $('.productName').val(new_data).trigger('change');. Finally, I append the new keyword that was extracted from the original selected value using $('.productName').append("<option value = '" + splitValues[1].toString().trim() + "' selected>" + splitValues[1].toString().trim() + "</option>");. This handles the case of having only one keyword after " USE ". Example keyword: Not smart USE dumb. When this is select only dumb shows up as a keyword in the InputField.
if(valueToRemove.toString().includes(" USE "))
{
var splitValues = valueToRemove.toString().split(" USE ");
if(!splitValues[1].toString().includes(";"))
{
alert("value does not contain ;");
new_data = $.grep($('.productName').val(), function(id){return id !== valueToRemove;});
alert("new data: " + new_data);
$('.productName > option').prop("selected", false);
$('.productName').val(new_data).trigger('change');
$('.productName').append("<option value = '" + splitValues[1].toString().trim() + "' selected>" + splitValues[1].toString().trim() + "</option>");
}
else{
.
.
.
}
}
In the case where the keyword(s) to the right of " USE " contains a semi-colon ;, I first split the string to the right of " USE " on the semi-colon ; using var splitKeys = splitValues[1].toLocaleString().split(";");. This gives me all of the keywords that should be added to the InputField. Next, I take the exact same step to repopulate the InputField's values.
new_data = $.grep($('.productName').val(), function(id){return id !== valueToRemove;});
$('.productName > option').prop("selected", false);
$('.productName').val(new_data).trigger('change');
I then use a loop to add all of the new keywords that should be added to the input field using:
splitKeys.forEach(function(item)
{
alert(item);
$('.productName').append("<option value = '" + item.toString().trim() + "' selected>" + item.toString().trim() + "</option>");
});
This handles the case of having more than one keyword after " USE ". Example keyword: Not smart USE dumb; stupid. When this is select dumb and stupid show up as keywords in the InputField.
if(valueToRemove.toString().includes(" USE "))
{
var splitValues = valueToRemove.toString().split(" USE ");
if(!splitValues[1].toString().includes(";"))
{
.
.
.
}
else{
var splitKeys = splitValues[1].toLocaleString().split(";");
new_data = $.grep($('.productName').val(), function(id){return id !== valueToRemove;});
$('.productName > option').prop("selected", false);
$('.productName').val(new_data).trigger('change');
splitKeys.forEach(function(item)
{
alert(item);
$('.productName').append("<option value = '" + item.toString().trim() + "' selected>" + item.toString().trim() + "</option>");
});
}
}

JQuery Ajax button isn't working

I am extremely new at writing ajax and working with a restful api... so, bear with me.
I have a Laravel 5.2 RESTful API that I am using on the backend, and I'm attempting to simply load a list of categories using Jquery / Ajax. As you click through the categories, each child category loads fine, but I cannot seem to get the "back" button to work (by this, I mean the LI I am generating, not the browser back button). When you click it, it shows the alert - and the data is correct, but that's it. The list doesn't refresh and populate with the appropriate items.
EDIT
There are no errors being thrown to the javascript console either. It just won't populate from the ajax call.
EDIT
I removed the request.abort() right after I made the original post.
EDIT
Here is the JSON returned from the URL api/categories/4 - as an example.
[{"id":6,"parent":4,"name":"sub_subcat4_1","slug":"sub_subcat4_1","description":null,"created_at":null,"updated_at":null},{"id":7,"parent":4,"name":"sub_subcat4_2","slug":"sub_subcat4_2","description":null,"created_at":null,"updated_at":null}]
EDIT
Here is the HTML for the #categories
<div class="row">
<div class="col-sm-12">
<ul id="categories">
</ul>
</div>
The Javascript
<script>
/*
* This loads the default / root categories.
*/
function getRootCategories() {
$.getJSON("api/categories", function(data) {
var categories = [];
$("#categories").html("");
$.each(data, function(key, val) {
$("#categories").append("<li class='subcat' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>');
});
});
}
/*
* This loads the sub categories if there's any data returned. Otherwise, just leave the user where they are.
*/
function getSubcats(cat) {
var dataID = cat.getAttribute("data-id");
alert(dataID);
if(dataID == "null") {
getRootCategories();
}
else {
$.getJSON("api/categories/" + dataID, function (data) {
if (data.length != 0) {
$("#categories").html("");
var newCats = '';
var parent = '';
$.each(data, function (key, val) {
parent = "<li class='subcat' data-id='" + val.parent + "' onClick='getSubcats(this);'>Back</li>";
newCats += "<li class='subcat' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>';
});
$("#categories").append(parent + newCats);
}
});
}
}
$(document).ready(function() {
$.ajaxSetup({ cache:false });
getRootCategories();
});
</script>
Ok, I just had my variables all mixed up. I wasn't setting the correct parent id.
The new script looks like this -
<script>
var previous = null;
/*
* This loads the default / root categories.
*/
function getRootCategories() {
$.getJSON("api/categories", function(data) {
var categories = [];
$("#categories").html("");
$.each(data, function(key, val) {
$("#categories").append("<li class='subcat' data-parent='" + val.parent + "' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>');
previous = val.parent;
});
});
}
/*
* This loads the sub categories if there's any data returned. Otherwise, just leave the user where they are.
*/
function getSubcats(cat) {
var dataID = cat.getAttribute("data-id");
previous = cat.getAttribute("data-parent");
if(dataID == "null") {
getRootCategories();
}
else {
$.getJSON("api/categories/" + dataID, function (data) {
if (data.length != 0) {
$("#categories").html("");
var newCats = '';
var parent = '';
$.each(data, function (key, val) {
parent = "<li class='subcat' data-id='" + previous + "' onClick='getSubcats(this);'>Back</li>";
newCats += "<li class='subcat' data-parent='" + val.parent + "' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>';
});
$("#categories").append(parent + newCats);
}
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + " - " + error);
});
}
}
$(document).ready(function() {
$.ajaxSetup({ cache:false });
getRootCategories();
});
</script>

How to replace appendto to something else to update the data

I am listing AJAX data in cards using the below code. It works well, but if I run it with setinterval with other function with some condition, if that becomes true it calls the below function to update the listed data.
It append all the new data to the existing listing data and duplicates it. I know this is because I am using the appendTo function, I tried to replace it with HTML but that did not work, it didn't list the data at all.
I want to update the data when this function is called again, rather than appending data. What should I use for this? Thanks.
function orderlist() {
return $.getJSON( "/restaurant/order/list/100/1",
function( orderdata )
{
var items = [];
$.each( orderdata, function( key, val ) {
var $o_on = val.ordernumber;
var $o_odate = val.bizorderdate;
var $o_userid = val.userid;
var $o_tnumber = val.tablenumber;
var $o_a = "<div class='card' id="+$o_on+">"
+ "<div class='title'>"
+ "Order No." + $o_on + "</div>"
+ "Date & Time: " + $o_odate + " </br>"
+ "User: " + $o_userid + " </br>"
+ "Table No: " + $o_tnumber + " </br>"
+ "</div>";
items.push($o_a);
})
$( "<div/>",
{
"class": "row",
html: items.join( "" )
}).appendTo( "#list_of_orders" );
});
}
Use empty() to clear out the list and then append your new stuff.
$('#list_of_orders').empty().append($( "<div/>",
{
"class": "row",
"html": items.join( "" )
}

jQuery getting value of updated select input

I update the value of a select input like so:
$('.filter').change(function() {
$.post('/schedules', { sid: $(this).val() }, function(result) {
$.each(result, function(k, v) {
var least = 0;
if(v.sort_c > least) {
$('.filter2').append('<option value="' + v.id + '.' + 'test_value' + '">' + v.name + '</option>');
least = v.sort_c;
}
});
});
});
After this jQuery runs I need to then get the value of $('.filter2'). When I try to do $('.filter2').val() it returns nothing.
Why is this happening?
You probably want to find the value of the selected option inside your select named filter2. Try this:
$('.filter2 option:selected').val();
After this jQuery runs seems to imply that you're not taking into account the asynchronous(AJAX) request involved. The following should give you the correct value of .filter2:
$('.filter').change(function() {
$.post('/schedules', { sid: $(this).val() }, function(result) {
$.each(result, function(k, v) {
var least = 0;
if(v.sort_c > least) {
$('.filter2').append('<option value="' + v.id + '.' + 'test_value' + '">' + v.name + '</option>');
least = v.sort_c;
}
});
console.log( $('.filter2').val() ); //<========
});
});
However, since I don't see you setting any of the new options with a selected attribute, I wonder what value you expect to get that you would not get before the change.

search with an array associate with javascript?

I want to do a search by name and surname with an array javascript, and the results in a div. for example: I write Ali in input, an it shoul show me Alison and Alibaba.
this is my code, but it's giving errors; are there other ways to do it?:
<input type='text' id='filter' placeholder='search'>
<div id='output' style='margin-top:50px '></div>
my array
var arrayD =[
{"Name":"Alison","Surname":"Kenn","Mobile":529129293},
{"Name":"Ashton","Surname":"Jhojan","Mobile":529129293},
{"Name":"Bith","Surname":"Klint","Mobile":129129293},
{"Name":"Ana","Surname":"Clow","Mobile":229129293},
{"Name":"Geoge","Surname":"Rich","Mobile":329129293},
{"Name":"kenneth","Surname":"Cooler","Mobile":329129}
]
var $result = $('#output');
$('#filter').on('keyup', function () {
var $fragment = $('<div />');
var val = this.value.toLowerCase();
$.each(arrayD, function (i, item) {
console.log( item[0].toLowerCase().indexOf(val));
if ( item[0].toLowerCase().indexOf(val) == 0 ) {
$fragment.append('<li>' + item[0] + ' ' + item[1] + '</li>');
}
});
$result.html( $fragment.children() );
});
http://jsfiddle.net/henrykend/ChpgZ/4/
The main problem with your code is that you're trying to reference fields in the object by ordinal position rather than name. There is nothing automagic in JavaScript which will read item.Name (or item["Name"]) from item[0].
There is also no need to build up a "false element" (in your case $fragment) and then append its children to the output area - you may as well do this in one go (remembering to .empty() it between calls).
Your corrected code:
var $result = $('#result');
$('#output').on('keyup', function () {
$result.empty();
var val = this.value.toLowerCase();
$.each(arrayD, function (i, item) {
if ( item.Name.toLowerCase().indexOf(val) == 0 ) {
$result.append('<li>' + item.Name + ' ' + item.Surname + '</li>');
}
});
});
And a live example: http://jsfiddle.net/ChpgZ/6/
You had couple of problems in your code.
Names of the elements we're wrongly placed (which you've fixed with the edit)
In the .each, you've used item[0] instead of item.Name (also surname)
See the following code
var arrayD =[
{"Name":"Alison","Surname":"Kenn","Mobile":529129293},
{"Name":"Ashton","Surname":"Jhojan","Mobile":529129293},
{"Name":"Bith","Surname":"Klint","Mobile":129129293},
{"Name":"Ana","Surname":"Clow","Mobile":229129293},
{"Name":"Geoge","Surname":"Rich","Mobile":329129293},
{"Name":"kenneth","Surname":"Cooler","Mobile":329129}
]
var $result = $('#result');
$('#output').on('keyup', function () {
var $fragment = $('<div />');
var val = this.value.toLowerCase();
$.each(arrayD, function (i, item) {console.log( item.Name.toLowerCase().indexOf(val) );
if ( item.Name.toLowerCase().indexOf(val) == 0 ) {
$fragment.append('<li>' + item.Name + ' ' + item.Surname + '</li>');
}
});
$result.html( $fragment.children() );
});

Categories