jQuery Autocomplete: How to enable cache? - jquery-ui

This is my source code that use a function to push the suggestion array:
jQuery(document).ready(function ($){
var cache = {};
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$("#ctags-input")
.bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
source: function(req, add){
var ctags_action = 'suggest_tags';
var term = req.term;
if (term in cache) {
add(cache[term]);
return;
}
$.getJSON(SuggestTags.url+'?callback=?&action='+ctags_action, req, function(data) {
var suggestions = [];
$.each(data, function(i, val){
suggestions.push({
label: val.name,
count: val.count
});
});
cache[term] = suggestions;
add(suggestions);
});
},
focus: function() {
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
terms.pop();
terms.push( ui.item.value );
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
})
.data( "autocomplete" )._renderItem = function( ul, item ) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + " (" + item.count+ ")</a>")
.appendTo(ul);
};
});
To add cache ability, jQ UI site demo directly uses response for data:
source: function( request, response ) {
var term = request.term;
if ( term in cache ) {
response( cache[ term ] );
return;
}
lastXhr = $.getJSON( "search.php", request, function( data, status, xhr ) {
cache[ term ] = data;
if ( xhr === lastXhr ) {
response( data );
}
});
}
How to implement this cache demo in my code?

Put suggestions in the cache.
var term = req.term;
if (term in cache) {
add(cache[term]);
return;
}
...
cache[term] = suggestions;
add(suggestions);

Related

jQuery UI Autocomplete Multiple Values in Textbox

I need a simple autocomplete search functionality but also allowing users to type more than one value. I'm using jQuery UI's autocomplete widget (http://jqueryui.com/autocomplete/) and so far I've set the source to only search for the first letter in the suggestions. What I'd like to add now is the ability for users to search for multiple items from the same textbox. (i.e. after a comma suggestions are shown again)
I have been trying to search on how this could be done. The only thing I've managed to find is an option that could be added multiple: true (http://forum.jquery.com/topic/multiple-values-with-autocomplete). Thing is that it's not even listed in the documentation anymore so I don't know if the option has changed or doesn't exist anymore.
This is my code:
var items = [ 'France', 'Italy', 'Malta', 'England',
'Australia', 'Spain', 'Scotland' ];
$(document).ready(function () {
$('#search').autocomplete({
source: function (req, responseFn) {
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp('^' + re, 'i');
var a = $.grep(items, function (item, index) {
return matcher.test(item);
});
responseFn(a);
}
});
});
What I tried:
var items = [ 'France', 'Italy', 'Malta', 'England',
'Australia', 'Spain', 'Scotland' ];
$(document).ready(function () {
$('#search').autocomplete({
source: function (req, responseFn) {
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp('^' + re, 'i');
var a = $.grep(items, function (item, index) {
return matcher.test(item);
});
responseFn(a);
},
multiple: true
});
});
Try this:
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$( "#search" )
.autocomplete({
minLength: 0,
source: function( request, response ) {
response( $.ui.autocomplete.filter(
items, extractLast( request.term ) ) );
},
focus: function() {
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
terms.pop();
terms.push( ui.item.value );
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
});
SEE DEMO
To solve the issue of multiple strings in the same textbox AND include a regex to only show suggestions matching the start of the string I did the following:
$('#search').autocomplete({
minLength: 1,
source: function (request, response) {
var term = request.term;
// substring of new string (only when a comma is in string)
if (term.indexOf(', ') > 0) {
var index = term.lastIndexOf(', ');
term = term.substring(index + 2);
}
// regex to match string entered with start of suggestion strings
var re = $.ui.autocomplete.escapeRegex(term);
var matcher = new RegExp('^' + re, 'i');
var regex_validated_array = $.grep(items, function (item, index) {
return matcher.test(item);
});
// pass array `regex_validated_array ` to the response and
// `extractLast()` which takes care of the comma separation
response($.ui.autocomplete.filter(regex_validated_array,
extractLast(term)));
},
focus: function () {
return false;
},
select: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push('');
this.value = terms.join(', ');
return false;
}
});
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}
If you want to implement the focus function instead of returning false, it's:
focus: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
this.value = terms.join(', ');
return false;
},
If you do this though, you should probably extract commas from the values.
Also, you can replace lines 7-10 with a call to extractLast. And then you can get rid of your other extractLast because you already called it on term.
With all my changes:
$('#search').autocomplete({
minLength: 1,
source: function (request, response) {
var term = extractLast(request.term),
re = $.ui.autocomplete.escapeRegex(term),
matcher = new RegExp('^' + re, 'i'),
regex_validated_array = $.grep(items, function (item, index) {
return matcher.test(item);
}),
mapped_array = regex_validated_array.map(function (item) {
return value.replace(/,/g, '');
});
response($.ui.autocomplete.filter(mapped_array, term));
},
focus: function () {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
this.value = terms.join(', ');
return false;
},
select: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push('');
this.value = terms.join(', ');
return false;
}
});
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}

How can I add and show a new select value to a jquery combo box autocomplete

I'm using jquery UI autocomplete combobox which is populated with a select box.
Here is the code:
$.widget( "ui.combobox", {
_create: function() {
var input,
self = this,
select = this.element.hide(),
selected = select.children( ":selected" ),
value = selected.val() ? selected.text() : "",
wrapper = this.wrapper = $( "<span>" )
.addClass( "ui-combobox" )
.insertAfter( select );
input = $( "<input>" )
.appendTo( wrapper )
.val( value )
.addClass( "ui-state-default ui-combobox-input" )
.autocomplete({
delay: 0,
minLength: 0,
source: function( request, response ) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
response( select.children( "option" ).map(function() {
var text = $( this ).text();
if ( this.value && ( !request.term || matcher.test(text) ) )
return {
label: text.replace(
new RegExp(
"(?![^&;]+;)(?!<[^<>]*)(" +
$.ui.autocomplete.escapeRegex(request.term) +
")(?![^<>]*>)(?![^&;]+;)", "gi"
), "<strong>$1</strong>" ),
value: text,
option: this
};
}) );
},
select: function( event, ui ) {
ui.item.option.selected = true;
self._trigger( "selected", event, {
item: ui.item.option
});
},
change: function( event, ui ) {
if ( !ui.item ) {
var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( $(this).val() ) + "$", "i" ),
valid = false;
select.children( "option" ).each(function() {
if ( $( this ).text().match( matcher ) ) {
this.selected = valid = true;
return false;
}
});
if ( !valid ) {
// remove invalid value, as it didn't match anything
$( this ).val( "" );
select.val( "" );
input.data( "autocomplete" ).term = "";
return false;
}
}
}
})
.addClass( "ui-widget ui-widget-content ui-corner-left" );
input.data( "autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + item.label + "</a>" )
.appendTo( ul );
};
$( "<a>" )
.attr( "tabIndex", -1 )
.attr( "title", "Show All Items" )
.appendTo( wrapper )
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass( "ui-corner-all" )
.addClass( "ui-corner-right ui-combobox-toggle" )
.click(function() {
// close if already visible
if ( input.autocomplete( "widget" ).is( ":visible" ) ) {
input.autocomplete( "close" );
return;
}
// work around a bug (likely same cause as #5265)
$( this ).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete( "search", "" );
input.focus();
});
},
destroy: function() {
this.wrapper.remove();
this.element.show();
$.Widget.prototype.destroy.call( this );
}
});
Here is a screenshot showing the form:
When a user clicks 'add Author' a modal loads for them to create a new Author model object. I want to add and show the newly created author in the jquery UI combobox.
I'm using Rails 3.2 and use a create.js.erb file to control the response from creating the object.

jquery ui autocomplete pass a variable

I m using jquery UI for getting suggestions of friend names and id, but the problem is I am not able to pass user id using autocomplete json function .
$(function() {
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split(term).pop();
}
$( "#recipient" )
// don't navigate away from the field on tab when selecting an item
.bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
source: function( request, response ) {
var attm= $('.USERID').val();
$.getJSON( "modules/messages/sql.php", {
term: extractLast( request.term ),
}, response );
},
search: function() {
// custom minLength
var term = extractLast( this.value );
if ( term.length < 2 ) {
return false;
}
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
terms.push( "" );
this.value = terms.join( ", " );
var prollNos = $('#recipientid').val()
$('#recipientid').val(prollNos + ui.item.id + ", ");
return false;
}
});
});
in which i am trying to pass a: $('.USERID').val() as user id , can anyone help me out?
I achieve something similar by GET. I use jquery-ui-autocomplete, as source I use: "source.php?param=something". So the final request my source page gets is "source.php?param=something&term=blabla"

Add a additional <li> tag to the end of rails3-jquery-autocomplete plugin

I'm trying to add an addition tag to the end of the autocomplete list.
$('#address ul.ui-autocomplete').append("<li>Add Venue</li>");
I'm trying to figure out where I can place the code above to add the extra li to the autocomplete list.
Any help will be deeply appreciated.
This is the rails3-jquery-autocomplete file.
source: function( request, response ) {
$.getJSON( $(e).attr('data-autocomplete'), {
term: extractLast( request.term )
}, function() {
$(arguments[0]).each(function(i, el) {
var obj = {};
obj[el.id] = el;
$(e).data(obj);
});
response.apply(null, arguments);
});
},
open: function() {
// when appending the result list to another element, we need to cancel the "position: relative;" css.
if (append_to){
$(append_to + ' ul.ui-autocomplete').css('position', 'static');
}
},
search: function() {
// custom minLength
var minLength = $(e).attr('min_length') || 2;
var term = extractLast( this.value );
if ( term.length < minLength ) {
return false;
}
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
if (e.delimiter != null) {
terms.push( "" );
this.value = terms.join( e.delimiter );
} else {
this.value = terms.join("");
if ($(this).attr('data-id-element')) {
$($(this).attr('data-id-element')).val(ui.item.id);
}
if ($(this).attr('data-update-elements')) {
var data = $(this).data(ui.item.id.toString());
var update_elements = $.parseJSON($(this).attr("data-update-elements"));
for (var key in update_elements) {
$(update_elements[key]).val(data[key]);
}
}
}
var remember_string = this.value;
$(this).bind('keyup.clearId', function(){
if($(this).val().trim() != remember_string.trim()){
$($(this).attr('data-id-element')).val("");
$(this).unbind('keyup.clearId');
}
});
$(this).trigger('railsAutocomplete.select');
return false;
}
});
}
Solved it with this.
$('#address').bind('autocompleteopen', function(event,data){
$('<li id="ac-add-venue">Add venue</li>').appendTo('ul.ui-autocomplete');
});

jQuery Combobox unsafe HTML insertion

I tried to use jQuery combobox (fiddle) in my Mozilla Firefox addon. But AMO editors rejected my Addon after reviewing stating that my javascript does unsafe HTML insertion with unsanitized data. Parts of the code stated as unsafe all belong to the code on official jQuery Ui page for combobox. I am also writing the code below. Removing this piece of code throws error if I try to create a combobox.
It makes me wonder why combobox isn't already included in jQuery and why do I have to put this snippet inside my code? Am I doing anything wrong here. Alternatively Can someone suggest me how can I make this code taken from official jquery page safe and sanitized?
(function( $ ) {
$.widget( "ui.combobox", {
_create: function() {
var self = this,
select = this.element.hide(),
selected = select.children( ":selected" ),
value = selected.val() ? selected.text() : "";
var input = this.input = $( "<input>" )
.insertAfter( select )
.val( value )
.autocomplete({
delay: 0,
minLength: 0,
source: function( request, response ) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
response( select.children( "option" ).map(function() {
var text = $( this ).text();
if ( this.value && ( !request.term || matcher.test(text) ) )
return {
label: text.replace(
new RegExp(
"(?![^&;]+;)(?!<[^<>]*)(" +
$.ui.autocomplete.escapeRegex(request.term) +
")(?![^<>]*>)(?![^&;]+;)", "gi"
), "<strong>$1</strong>" ),
value: text,
option: this
};
}) );
},
select: function( event, ui ) {
ui.item.option.selected = true;
self._trigger( "selected", event, {
item: ui.item.option
});
},
change: function( event, ui ) {
if ( !ui.item ) {
var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( $(this).val() ) + "$", "i" ),
valid = false;
select.children( "option" ).each(function() {
if ( $( this ).text().match( matcher ) ) {
this.selected = valid = true;
return false;
}
});
if ( !valid ) {
// remove invalid value, as it didn't match anything
$( this ).val( "" );
select.val( "" );
input.data( "autocomplete" ).term = "";
return false;
}
}
}
})
.addClass( "ui-widget ui-widget-content ui-corner-left" );
input.data( "autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + item.label + "</a>" )
.appendTo( ul );
};
this.button = $( "<button type='button'> </button>" )
.attr( "tabIndex", -1 )
.attr( "title", "Show All Items" )
.insertAfter( input )
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass( "ui-corner-all" )
.addClass( "ui-corner-right ui-button-icon" )
.click(function() {
// close if already visible
if ( input.autocomplete( "widget" ).is( ":visible" ) ) {
input.autocomplete( "close" );
return;
}
// work around a bug (likely same cause as #5265)
$( this ).blur();
// pass empty string as value to search for, displaying all results
input.autocomplete( "search", "" );
input.focus();
});
},
destroy: function() {
this.input.remove();
this.button.remove();
this.element.show();
$.Widget.prototype.destroy.call( this );
}
});
})( jQuery );

Resources