I would like to have a drop-down with multiple search queries for one item.
I am using jQuery UI Combobox.
Example: In the drop-down you see 'USD' but if you type 'dollar' it will also show 'USD'
<div class="ui-widget">
<label>Currency: </label>
<select id="comboboxCurrency">
<option></option>
<option value"dollar">USD</option>
<option label"dollar">EUR</option>
<option>AUD</option>
<option>BRL</option>
<option>CAD</option>
I have tried both 'value' and 'label' both are not working.
What am I missing here?
I'm assuming you are using jQuery widget factory to create custom ui for dropdown menu.
You can modify _source method of $.widget factory in such a way that it will search on the basis of option value instead of option text
_source: function(request, response) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
response(this.element.children("option").map(function() {
// get text of the option
var text = $(this).text();
// get value of the option
var value = $(this).val();
// check is value is set and pass value to matcher.test() method
if (this.value && (!request.term || matcher.test(value)))
return {
label: text,
value: text,
option: this
};
}));
}
$(function() {
$.widget("custom.combobox", {
_create: function() {
this.wrapper = $("<span>")
.addClass("custom-combobox")
.insertAfter(this.element);
this.element.hide();
this._createAutocomplete();
this._createShowAllButton();
},
_createAutocomplete: function() {
var selected = this.element.children(":selected"),
value = selected.val() ? selected.text() : "";
this.input = $("<input>")
.appendTo(this.wrapper)
.val(value)
.attr("title", "")
.addClass("custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left")
.autocomplete({
delay: 0,
minLength: 0,
source: $.proxy(this, "_source")
})
.tooltip({
classes: {
"ui-tooltip": "ui-state-highlight"
}
});
this._on(this.input, {
autocompleteselect: function(event, ui) {
ui.item.option.selected = true;
this._trigger("select", event, {
item: ui.item.option
});
},
autocompletechange: "_removeIfInvalid"
});
},
_createShowAllButton: function() {
var input = this.input,
wasOpen = false;
$("<a>")
.attr("tabIndex", -1)
.attr("title", "Show All Items")
.tooltip()
.appendTo(this.wrapper)
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass("ui-corner-all")
.addClass("custom-combobox-toggle ui-corner-right")
.on("mousedown", function() {
wasOpen = input.autocomplete("widget").is(":visible");
})
.on("click", function() {
input.trigger("focus");
// Close if already visible
if (wasOpen) {
return;
}
// Pass empty string as value to search for, displaying all results
input.autocomplete("search", "");
});
},
_source: function(request, response) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
response(this.element.children("option").map(function() {
var text = $(this).text();
var value = $(this).val();
if (this.value && (!request.term || matcher.test(value)))
return {
label: text,
value: text,
option: this
};
}));
},
_removeIfInvalid: function(event, ui) {
// Selected an item, nothing to do
if (ui.item) {
return;
}
// Search for a match (case-insensitive)
var value = this.input.val(),
valueLowerCase = value.toLowerCase(),
valid = false;
this.element.children("option").each(function() {
if ($(this).text().toLowerCase() === valueLowerCase) {
this.selected = valid = true;
return false;
}
});
// Found a match, nothing to do
if (valid) {
return;
}
// Remove invalid value
this.input
.val("")
.attr("title", value + " didn't match any item")
.tooltip("open");
this.element.val("");
this._delay(function() {
this.input.tooltip("close").attr("title", "");
}, 2500);
this.input.autocomplete("instance").term = "";
},
_destroy: function() {
this.wrapper.remove();
this.element.show();
}
});
$("#comboboxCurrency").combobox();
});
.custom-combobox {
position: relative;
display: inline-block;
}
.custom-combobox-toggle {
position: absolute;
top: 0;
bottom: 0;
margin-left: -1px;
padding: 0;
}
.custom-combobox-input {
margin: 0;
padding: 5px 10px;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="ui-widget">
<label>Currency: </label>
<select id="comboboxCurrency">
<option></option>
<option value = "dollar usd">USD</option>
<option value = "euro eur">EUR</option>
<option value = "aud">AUD</option>
<option value = "brl">BRL</option>
<option value = "cad">CAD</option>
Related
I came across an assignment that requires us to highlight multiple matching substrings in jQuery's UI Autocomplete widget.
UPDATE: New problem
Now I have a second problem: when the textbox is empty and I type a letter, the drop-down menu shows all the right highlights and items.
But when I put a comma after the first query, the second search shows the correct menu items, but it does NOT show any highlights:
Input 1: b
Drop-down menu: Bulbasaur
Textbox after selecting menu item: Bulbasaur,
Input 2: c
Drop-down menu: Charmander
Textbox after selecting menu item: Bulbasaur, Charmander,
What I want
Input 2: c
Drop-down menu: Charmander
Any help would be appreciated!
My code
The categories is also part of the requirements.
<script>
var pokemonList = [ ... ];
function widgetConstr()
{
this._super();
};
function renderPokemons(ul, item)
{
terms = this.term.split(',');
term = this.element.val().trim();
var result = new RegExp(term, "gi");
var newTerm = item.label
.replace(result, "<span class='match-character'>" + term + "</span>");
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + newTerm + "</a>")
.appendTo(ul);
};
function renderPokemonList(ul, items)
{
var that = this;
currentCategory = "";
$.each(
items, function(index, item)
{
var li;
if (item.category != currentCategory)
{
ul.append("<li class='ui-autocomplete-category'>" + item.category + "</li>");
currentCategory = item.category;
}
li = that._renderItemData(ul, item);
if (item.category)
li.attr("aria-label", item.category + " : " + item.label);
}
);
};
$.widget(
"custom.PokemonSearch", $.ui.autocomplete,
{
_create: widgetConstr,
_renderItem: renderPokemons,
_renderMenu: renderPokemonList
}
);
function split(val)
{
return val.split(/,\s*/);
};
function extractLast(term)
{
return split(term).pop();
};
$("search").on("keydown", function(event)
{
if (event.keyCode == $.ui.keyCode.TAB && $(this).autocomplete("instance").menu.active)
event.preventDefault();
}
);
function onDocumentReady()
{
$("#search").PokemonSearch(
{
delay: 0,
max: 10,
scroll: true,
source: function(request, response)
{
response($.ui.autocomplete.filter(
pokemonList, 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;
}
}
)
};
$(document).ready(onDocumentReady);
</script>
Relevant CSS
.match-character {
font-weight: bold;
font-style: italic;
color: blue;
}
SOLVED: Problem 1
Update: Thanks so much for the help!!
What I want
Whether the input query is upper or lowercase, the drop-down menu displays uppercase and lowercase results as highlighted:
Input: b
Drop-down menu: Bulbasaur
Reality
My drop-down menu displays matching uppercase letters to lowercase, but after selecting a menu item, it displays the uppercase letter correctly:
Input: b
Drop-down menu: bulbasaur
Textbox after selecting menu item: Bulbasaur,
What I've tried
If I remove the i tag in var result = new RegExp(term, "gi");, the menu shows results with capital letters, but they don't show as highlighted.
The lecture notes and labs didn't mention or suggest how to do both upper and lowercase highlighting with a lowercase query.
I tried looking online but either the solutions don't work, or are too complicated for me to understand (I've only been coding in JavaScript for a few weeks). 99% of the code here are copied directly from various sources.
I've only just understood what RegExp() does, but I have no idea where to go to achieve what I want.
Any guidance is appreciated!
You could pass the Regexp variable in replace and access the match in a function callback:
var result = new RegExp(term, "gi");
var newTerm = item.label
.replace(result, function(match) {
return "<span class='match-character'>" + match + "</span>"
});
var pokemonList = ['Bulbasaur'];
fetch("https://pokeapi.co/api/v2/pokemon/?limit=50").then(a => a.json().then(b => {
pokemonList = b.results.map(({
name,
...obj
}) => name.charAt(0).toUpperCase() + name.slice(1))
}));
function widgetConstr() {
this._super();
};
function renderPokemons(ul, item) {
terms = this.term.split(',');
term = this.element.val().trim();
var result = new RegExp(term, "gi");
var newTerm = item.label
.replace(result, function(match) {
return "<span class='match-character'>" + match + "</span>"
});
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + newTerm + "</a>")
.appendTo(ul);
};
function renderPokemonList(ul, items) {
var that = this;
currentCategory = "";
$.each(
items,
function(index, item) {
var li;
if (item.category != currentCategory) {
ul.append("<li class='ui-autocomplete-category'>" + item.category + "</li>");
currentCategory = item.category;
}
li = that._renderItemData(ul, item);
if (item.category)
li.attr("aria-label", item.category + " : " + item.label);
}
);
};
$.widget(
"custom.PokemonSearch", $.ui.autocomplete, {
_create: widgetConstr,
_renderItem: renderPokemons,
_renderMenu: renderPokemonList
}
);
function split(val) {
return val.split(/,\s*/);
};
function extractLast(term) {
return split(term).pop();
};
$("search").on("keydown", function(event) {
if (event.keyCode == $.ui.keyCode.TAB && $(this).autocomplete("instance").menu.active)
event.preventDefault();
});
function onDocumentReady() {
$("#search").PokemonSearch({
delay: 0,
max: 10,
scroll: true,
source: function(request, response) {
response($.ui.autocomplete.filter(
pokemonList, 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;
}
})
};
$(document).ready(onDocumentReady);
.match-character {
font-weight: bold;
font-style: italic;
color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<input id="search" />
UPDATE
for comma seperated take the latest of the bunch:
term = terms[terms.length -1].trim();
var pokemonList = ['Bulbasaur'];
fetch("https://pokeapi.co/api/v2/pokemon/?limit=50").then(a => a.json().then(b => {
pokemonList = b.results.map(({
name,
...obj
}) => name.charAt(0).toUpperCase() + name.slice(1))
}));
function widgetConstr() {
this._super();
};
function renderPokemons(ul, item) {
terms = this.term.split(',');
term = terms[terms.length -1].trim();
var result = new RegExp(term, "gi");
var newTerm = item.label
.replace(result, function(match) {
return "<span class='match-character'>" + match + "</span>"
});
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + newTerm + "</a>")
.appendTo(ul);
};
function renderPokemonList(ul, items) {
var that = this;
currentCategory = "";
$.each(
items,
function(index, item) {
var li;
if (item.category != currentCategory) {
ul.append("<li class='ui-autocomplete-category'>" + item.category + "</li>");
currentCategory = item.category;
}
li = that._renderItemData(ul, item);
if (item.category)
li.attr("aria-label", item.category + " : " + item.label);
}
);
};
$.widget(
"custom.PokemonSearch", $.ui.autocomplete, {
_create: widgetConstr,
_renderItem: renderPokemons,
_renderMenu: renderPokemonList
}
);
function split(val) {
return val.split(/,\s*/);
};
function extractLast(term) {
return split(term).pop();
};
$("search").on("keydown", function(event) {
if (event.keyCode == $.ui.keyCode.TAB && $(this).autocomplete("instance").menu.active)
event.preventDefault();
});
function onDocumentReady() {
$("#search").PokemonSearch({
delay: 0,
max: 10,
scroll: true,
source: function(request, response) {
response($.ui.autocomplete.filter(
pokemonList, 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;
}
})
};
$(document).ready(onDocumentReady);
.match-character {
font-weight: bold;
font-style: italic;
color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<input id="search" />
I want use a autocomplete/ComboBox like a filter. I customize the code from jqueryUI to give same form like a selectMenu. And I want use select and change event and triger change event on Enter keypress.
Here my code :
$.widget("custom.TFOAutoCombo", {
_create: function () {
var nam = this.element.attr("id").split("lstFiltreAuto");
this.element.hide();
this.wrapper = $("<span>", { "class": "ui-state-default TFOcustom-combobox SizCol" + nam[1] }).appendTo($('#acc-container' + nam[1]));
this._createAutocomplete(nam[1]);
this._createShowAllButton(nam[1]);
},
_createAutocomplete: function (nam) {
var selected = this.element.children(":selected"),
value = selected.val() ? selected.text() : "";
this.input = $('<input class="ui-state-default TFOcustom-combobox-Input ui-corner-all" placeholder="TOUS">').appendTo(this.wrapper).val(value)
.autocomplete({ delay: 0, minLength: 0, source: $.proxy(this, "_source"), appendTo: '#acc-container' + nam })
.tooltip({ classes: { "ui-tooltip": "ui-state-highlight" } });
this._on(this.input, {
autocompleteselect: function (event, ui) { ui.item.option.selected = true; this._trigger("select", event, { item: ui.item.option }); },
autocompletechange: function (event, ui) { var ret = this._removeIfInvalid(event, ui); if (ret != null) { this._trigger("change", event, { item: ret }); } }
});
this.input.keypress(function (e,ui) {
if (e.which == 13) {
var ret = this._removeIfInvalid(e, ui); if (ret != null) { this._trigger("change", event, { item: ret }); }
}
});
},
_createShowAllButton: function (nam) {
var input = this.input, wasOpen = false;
$('<span class="ui-icon ui-icon-triangle-1-s TFOcustom-combobox-Fleche">').appendTo(this.wrapper)
.on("mousedown", function () { wasOpen = input.autocomplete("widget").is(":visible"); })
.on("click", function () {
input.trigger("focus");
if (wasOpen) { return; }// Close if already visible
input.autocomplete("search", "");// Pass empty string as value to search for, displaying all results
});
},
_source: function (request, response) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
response(this.element.children("option").map(function () {
var text = $(this).text();
if (this.value && (!request.term || matcher.test(text))) return { label: text, value: text, option: this };
}));
},
_removeIfInvalid: function (event, ui) {
if (ui.item) { return null; }// Selected an item, nothing to do
// Search for a match (case-insensitive)
var value = this.input.val(), valueLowerCase = value.toLowerCase(), valid = false; var Koi = null;
this.element.children("option").each(function () { if ($(this).text().toLowerCase() === valueLowerCase) { this.selected = valid = true; Koi = this; return false; } });
if (valid) { return Koi; } // Found a match, nothing to do
// Remove invalid value
this.input.val("").attr("title", "Aucun enregistrement correspondant à " + value).tooltip("open");
this.element.val("");
this._delay(function () { this.input.tooltip("close").attr("title", ""); }, 2500);
this.input.autocomplete("instance").term = "";
return Koi;
},
_destroy: function () { this.wrapper.remove(); this.element.show(); }
});
TO create my custom autocomplete I use thsi function
function CustomComboAuto($r, q) {
var s = (q == null ? "select.TFOAutoCombo" : q); $r.find(s).TFOAutoCombo({
select: function (event, ui) {
alert("select:" + ui.item.value);
},
change: function (event, ui) {
alert("Change" + ui.item.value);
}
});
}
And my CSS:
.TFOcustom-combobox {
position: relative;
display: inline-block;
vertical-align:middle;
padding: 0 10px 0 0;
border:none !important;
background:none !important;
}
.TFOcustom-combobox-Fleche {
position:absolute;
right:0.5em;
top:50%;
margin-top:-8px;
z-index:100;
}
.TFOcustom-combobox-Input{
width:95%;
font-size:small !important;
padding:0.7em 0 0.7em 1em;
line-height:1.4;
}
And I've 2 Problems/
The first is when I select with mouse it's fired select event (good)
When I use up/down and press entrer to select an item, it's fired change event and after select event. And I just need change not the select)
The second problem and I want fire autocompletechange event when I write directly in my autocomplete and press enter key. I've capture the event enterkeypress but I can't fired the research properly.
If someone can help me. I work on that since 3 days, passed lot of problem but now I've no more idea to solve this 2 points.
Finnally I solved the first big part of problems.
$.widget("custom.TFOAutoCombo", {
_create: function () {
var nam = this.element.attr("id").split("lstFiltreAuto");
this.element.hide();
this.wrapper = $("<span>", { "class": "ui-state-default TFOcustom-combobox SizCol" + nam[1] }).appendTo($('#acc-container' + nam[1]));
this._createAutocomplete(nam[1]);
this._createShowAllButton(nam[1]);
},
_createAutocomplete: function (nam) {
var selected = this.element.children(":selected"),
value = selected.val() ? selected.text() : "";
var selectedName = '';
this.input = $('<input class="ui-state-default TFOcustom-combobox-Input ui-corner-all" placeholder="TOUS">').appendTo(this.wrapper).val(value)
.autocomplete({ delay: 0, minLength: 0, source: $.proxy(this, "_source"), appendTo: '#acc-container' + nam })
.keypress(function (e, ui) {
if (e.which == 13) {
e.preventDefault(); $(this).autocomplete("close"); var inputs = $(this).closest('body').find(':focusable'); inputs.eq(inputs.index(this) + 1).focus();
}
})
.tooltip({ classes: { "ui-tooltip": "ui-state-highlight" } });
this._on(this.input, {
autocompleteselect: function (event, ui) { if (selectedName === ui.item.value) { return; } else { selectedName = ui.item.value; ui.item.option.selected = true; this._trigger("select", event, { item: ui.item.option }); } },
autocompletechange: function (event, ui) { if (selectedName === this.input.val()) { return; } else { var ret = this._removeIfInvalid(event, ui); if (ret != null) { selectedName = this.input.val(); this._trigger("select", event, { item: ret }); } } }
});
},
_createShowAllButton: function (nam) {
var input = this.input, wasOpen = false;
$('<span class="ui-icon ui-icon-triangle-1-s TFOcustom-combobox-Fleche">').appendTo(this.wrapper)
.on("mousedown", function () { wasOpen = input.autocomplete("widget").is(":visible"); })
.on("click", function () {
input.trigger("focus");
if (wasOpen) { return; }// Close if already visible
input.autocomplete("search", "");// Pass empty string as value to search for, displaying all results
});
},
_source: function (request, response) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
response(this.element.children("option").map(function () {
var text = $(this).text();
if (this.value && (!request.term || matcher.test(text))) return { label: text, value: text, option: this };
}));
},
_removeIfInvalid: function (event, ui) {
if (ui.item) { return null; }// Selected an item, nothing to do
// Search for a match (case-insensitive)
var value = this.input.val(), valueLowerCase = value.toLowerCase(), valid = false; var Koi = null;
this.element.children("option").each(function () { if ($(this).text().toLowerCase() === valueLowerCase) { this.selected = valid = true; Koi = this; return false; } });
if (valid) { return Koi; } // Found a match, nothing to do
// Remove invalid value
this.input.val("").attr("title", "Aucun enregistrement correspondant à " + value).tooltip("open");
this.element.val("");
this._delay(function () { this.input.tooltip("close").attr("title", ""); }, 2500);
this.input.autocomplete("instance").term = "";
return Koi;
},
_destroy: function () { this.wrapper.remove(); this.element.show(); }
});
The solution is simple, when I capture Enter KeyPress I close autocomplete and put focus otherthere :-) to trigger autocompletechange event.
Now JUST stay the problem of double fired event when I use up/down and selecting by EnterKeyPress on list
UPDATE
I change the _createAutocomplete with a variable to memorize the last value... Too simple that I can see it.
All Resolved. Enjoy a good autocomplete combobox seems selectmenu
Need some help.
Can I set the custom value to the combobox, the value which is not present in the list.
It means like my own value which is not listed in the list
Here is the code.
(function( $ ) {
$.widget( "ui.combobox", {
_create: function() {
this.wrapper = $( "<span>" )
.addClass( "custom-combobox" )
.insertAfter( this.element )
.attr('id', this.element[0].id+"_combobox");
this.element.hide();
this._createAutocomplete();
this._createShowAllButton();
},
_createAutocomplete: function() {
var selected = this.element.children(":selected");
this.input = $( "<input>" )
.appendTo( this.wrapper )
.attr( "title", '<fmt:message key="page.claim.personalclaimnotification.injury.select_info" />' )
.val(selected.text())
.css({
color: function( index, value ) {
if (this.value == '<fmt:message key="page.claim.search.object.name" />') {
return "#777";
}
},
fontStyle: function( index, value ) {
if (this.value == '<fmt:message key="page.claim.search.object.name" />') {
return "italic";
}
},
width: "286px"
})
.attr("maxlength", 256)
.addClass( "custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left" )
.autocomplete({
delay: 0,
minLength: 3,
source: $.proxy( this, "_source" )
})
// executes when user selects illness from list
this._on( this.input, {
autocompleteselect: function( event, ui ) {
ui.item.option.selected = true;
this._trigger( "select", event, {
item: ui.item.option
});
},
autocompletechange: "_addIfInvalid"
});
}, /* _createAutocomplete close */
_createShowAllButton: function() {
var input = this.input,
wasOpen = false;
$( "<a>" )
.attr( "tabIndex", -1 )
.appendTo( this.wrapper )
.attr( "title", '<fmt:message key="page.claim.personalclaimnotification.injury.select_info" />' )
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass( "ui-corner-all" )
.addClass( "custom-combobox-toggle ui-corner-right" )
.mousedown(function() {
wasOpen = input.autocomplete( "widget" ).is( ":visible" );
})
.click(function() {
// Close if already visible
if ( wasOpen ) {
return;
}
// Pass triple spaces as value to search for, displaying all results (each has triple spaces at the end)
input.autocomplete( "search", " " );
});
}, /* _createShowAllButton close */
_source: function( request, response ) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
response( this.element.children( "option" ).map(function() {
var text = $( this ).text();
if ( this.value && ( !request.term || matcher.test(text) ) )
return {
label: text,
value: text,
option: this
};
}) );
},
_addIfInvalid: function( event, ui ) {
// Selected an item, nothing to do
if ( ui.item ) {
return;
}
// Search for a match (case-insensitive)
var value = this.input.val(),
valueLowerCase = value.toLowerCase(),
valid = false;
this.element.children( "option" ).each(function() {
if ( $( this ).text().toLowerCase() === valueLowerCase ) {
this.selected = valid = true;
return false;
}
});
// Found a match, nothing to do
if ( valid ) {
return;
}
alert("value "+ value +" this.element "+ this.element[0].id );
// Remove invalid value
this.input
.val(value)
.attr( "title", value + " didn't match any item" )
.tooltip( "open" );
//this.element.val(value);
//this.input.val(value);
$('select').val(value);
this._delay(function() {
this.input.tooltip( "close" ).attr( "title", "" );
}, 2500 );
this.input.autocomplete( "instance" ).term = "";
},
_destroy: function() {
this.wrapper.remove();
this.element.show();
}
}); /* widget close */
})( jQuery ); /* function close */
$(function() {
$( ".objectComboBox" ).combobox();
});
If the element is not listed in the drop down, that user entered element should be taken as the value and should stay in the combobox field.
Adding the field
I made a script for you. May be it will work for you.
<select id="combobox" >
<option>abc</option>
<option>deg</option>
<option>gcc</option>
</select>
<input type="text" id="addfieldtoddl" /><input type="button" value="add" id="add" onclick="addfieldtoddl()" />
<script>
$(document).ready(function(){
$("#combobox").combobox();
});
function addfieldtoddl() {
var YourValue = $("#addfieldtoddl").val();
$('#combobox').append('<option val="'+ YourValue +'">'+ YourValue +'</option>');
$("#combobox").combobox();
}
</script>
here is fiddle link http://jsfiddle.net/RDd3A/506/
Trying to help...!!!
In creating a table cells with very cool options I need to take two steps. First I create the table cell as a DOM object in javascript with all the 'normal' functionality, like is it a checkbox, a select, an input, a link, etc.
Then I need to put the table on the page to do the next step, which I consider advanced functionality like jqueryui's autocomplete and date select. It is awesome to have these drop downs for the user.
I do have this working, however, I do need to make two calls. The first to createTableCell, then I render, then I need to make another call to postRenderTableFunctions to get the autocomplete functionality working. So the question is, why the second call, what is it about jqueryui that will not work on the first call. You can see the commented section under input creation where I tried to get the autocomplete working.
function createTableCell(name, td_def)
{
var cell=document.createElement('td');
if(td_def['type'] == 'date')
{
var element = document.createElement('input');
element.name = name;
element.id = name;
cell.appendChild(element);
$('#' + element.id).datepicker(
{
dateFormat: 'yy-mm-dd',
onSelect: function ()
{
$(this).focus();
},
onClose: function (dateText, inst)
{
$(this).select();
}
});
}
else if(td_def['type'] == 'checkbox')
{
element = document.createElement('input');
element.type = 'checkbox';
element.name = name;
element.id = name;
/*if(this.tdo[r][td_def['db_field']]['data'] == 1)
{
element.checked = true;
}*/
cell.appendChild(element);
}
else if (td_def['type'] == 'select')
{
element = document.createElement('select');
element.name = name;
element.id = name;
var option = document.createElement('option');
option.value = 'NULL';
option.appendChild(document.createTextNode("Select..."));
element.appendChild(option);
for (var j in td_def['select_names'])
{
option = document.createElement('option');
option.value = td_def['select_values'][j];
option.appendChild(document.createTextNode(td_def['select_names'][j]));
element.appendChild(option);
}
cell.appendChild(element);
}
else if (td_def['type'] == 'tree_select')
{
element = document.createElement('select');
element.id = name;
element.name = name;
var option = document.createElement('option');
option.value = 'NULL';
option.appendChild(document.createTextNode("Select..."));
element.appendChild(option);
var level = 0;
//console.log(td_def['select_array']);
this.addNestedSelectOptions(element, td_def['select_array'], level);
if (typeof td_def['properties'] !== 'undefined')
{
for (var index in td_def['properties'])
{
eval('element.' + index + '= ' + td_def['properties'][index] + ';');
}
}
cell.appendChild(element);
}
else if (td_def['type'] == 'input')
{
element = document.createElement('input');
element.type = 'text';
element.id = name;
element.name = name;
cell.appendChild(element);
/*
if(typeof td_def['autoComplete'] != 'undefined')
{
console.log('attempting Autocomplete');
$( "#" + name ).autocomplete({
source: function( request, response )
{
$.ajax(
{
url: td_def['autoComplete']['url'],
type: 'GET',
async: true,
data:
{
ajax_request: td_def['autoComplete']['ajax_request'],
featureClass: "P",
style: "full",
maxRows: 12,
search_terms: request.term
},
success: function( data )
{
console.log(data);
parsed_autocomplete_data = parseJSONdata(data);
response( parsed_autocomplete_data);
}
});
},
search: function()
{
// custom minLength
var term = this.value;
//console.log(term);
if(typeof td_def['minLength'] != 'undefined')
{
var minL = td_def['minLength'];
}
else
{
var minL = 1;
}
if ( term.length < minL )
{
return false;
}
},
focus: function()
{
// prevent value inserted on focus
return false;
},
open: function(event, ui)
{
var dialog = $(this).closest('.ui-dialog');
if(dialog.length > 0){
$('.ui-autocomplete.ui-front').zIndex(dialog.zIndex()+1);
}
},
select: function( event, ui )
{
selected_autocomplete_index = $.inArray(ui.item.value, parsed_autocomplete_data);
}
});
}
*/
}
else if (td_def['type'] == 'textarea')
{
element = document.createElement('TEXTAREA');
element.id = name;
element.name = name;
cell.appendChild(element);
}
else if (td_def['type'] == 'td')
{
cell.innerHTML = 'TBD';
cell.name = name;
cell.id = name;
}
else
{
alert(td_def['type'] + ' have not coded that.....');
}
return cell;
function addNestedSelectOptions(element, category_array, level)
{
for (var key in category_array)
{
option = document.createElement('option');
option.value = key;
name = category_array[key]['name'];
for(i=0;i<level;i++)
{
name = "\u00A0" + name;
name = "\u00A0" + name;
}
option.appendChild(document.createTextNode(name));
element.appendChild(option);
if(!$.isEmptyObject(category_array[key]['children']))
{
addNestedSelectOptions(element, category_array[key]['children'], level+1);
}
}
}
}
//this function needs to be called separately.
function postRenderTableFunctions(table_div_id, table_def)
{
//extra jquery functionality -- needs to go after stuff is rendered
for(var i=0;i<table_def.length;i++)
{
if(typeof table_def[i]['autoComplete'] != 'undefined')
{
var id = table_div_id + '_' + table_def[i]['db_field'];
console.log(id);
//is the auto complete open?
/*$("#" + id ).bind('autocompleteopen', function(event, ui)
{
$(this).data('is_open',true);
});
$("#" + id ).bind('autocompleteclose', function(event, ui)
{
$(this).data('is_open',false);
});*/
/*$( "#" + id ).bind( "keydown", function( event )
{
//what is this for ?
if ( event.keyCode === $.ui.keyCode.TAB && $(this).data('is_open') )
{
event.preventDefault();
}
if ( event.keyCode === $.ui.keyCode.ENTER && !$(this).data('is_open'))
{
//do what?
}
});*/
var i2 = i;
var me = table_def;
$( "#" + id ).autocomplete({
source: function( request, response )
{
$.ajax(
{
url: me[i2]['autoComplete']['url'],
type: 'GET',
async: true,
data:
{
ajax_request: me[i2]['autoComplete']['ajax_request'],
featureClass: "P",
style: "full",
maxRows: 12,
search_terms: request.term
},
success: function( data )
{
console.log(data);
parsed_autocomplete_data = parseJSONdata(data);
response( parsed_autocomplete_data);
}
});
},
search: function()
{
// custom minLength
var term = this.value;
//console.log(term);
if(typeof table_def[i2]['minLength'] != 'undefined')
{
var minL = table_def[i2]['minLength'];
}
else
{
var minL = 1;
}
if ( term.length < minL )
{
return false;
}
},
focus: function()
{
// prevent value inserted on focus
return false;
},
open: function(event, ui)
{
var dialog = $(this).closest('.ui-dialog');
if(dialog.length > 0){
$('.ui-autocomplete.ui-front').zIndex(dialog.zIndex()+1);
}
},
select: function( event, ui )
{
selected_autocomplete_index = $.inArray(ui.item.value, parsed_autocomplete_data);
}
});
}
}
}
My original comment to your question -
I suspect i may work if you replace
$( "#" + name ).autocomplete({
with
$(element).autocomplete({
though I don't currently have means to test it.
My response -
Basically using $("#name") looks for an element with the ID name in the DOM. When you are running your code element has not been added to the DOM yet so the autocomplete cannot be attached to to your element.
Surrounding element with $() converts it to a jQuery variable which you can attach the autocomplete to before it is added to the DOM.
So here is my autocomplete functionality:
var selected;
var itemAdded = false;
$('.js-main-search').autocomplete({
minLength: 3,
source: function(request, response) {
$.getJSON('/dashboard/searchDocumentsAndCompanies.do',
{ q: request.term},
function(data) {
if(data.length == 0){
data = [
{name: 'No matches found', resultType: 'COMPANY', noResults: true},
{name: 'No matches found', resultType: 'BRANCHES', noResults: true},
];
}
data.unshift({name: 'Search from documents »', reqQuery: request.term, docSearch:true});
response(data);
});
},
select: function( event, ui ) {
event.preventDefault();
selected = true;
if(ui.item.docSearch && !itemAdded){
$(".textbox.ui-front li:eq(1)").before('<li class="search-category ui-menu-item">Documents</li>');
itemAdded = true;
}
}
});
$('.js-main-search').data("uiAutocomplete").close = function(event) {
if (!selected){
$('.js-main-search').data("uiAutocomplete").close.apply( this, arguments );
}
selected = false;
};
$('.js-main-search').data('uiAutocomplete')._renderItem = function( ul, item ) {
itemAdded = false;
item.value = item.name;
var $el = $( "<li>" ).append(item.value);
if(item.docSearch){
$el.addClass( "search-documents-btn" );
$el.one('click', function (e) {
e.preventDefault();
console.log(ul.children());
});
}
if(!item.noResults && !item.docSearch){
$el.append('<div class="meta">Documents | Company page</div>');
}
$el.appendTo( ul );
return $el;
};
$('.js-main-search').data('uiAutocomplete')._renderMenu = function(ul, items) {
var companiesResults = true;
var branchesResults = true;
var that = this,currentCategory = '';
$.each(items, function(index, item) {
var li;
if (item.resultType != currentCategory && !item.docSearch) {
var categoryTitle = '';
if(item.resultType == 'COMPANY'){
categoryTitle = 'Companies';
companiesResults = false;
} else{
categoryTitle = 'Branches'
branchesResults = false;
}
ul.append('<li class="search-category">'+categoryTitle+'</li>');
currentCategory = item.resultType;
}
li = that._renderItemData(ul, item);
if (item.resultType) {
item.value = item.name;
li.attr('aria-label', item.resultType + ' : '+ item.value);
}
});
if(companiesResults && branchesResults){
ul.append('<li class="search-show-more-btn">Show more</li>');
}
};
When I am starting to enter search keyword sometimes it gives me the following error in console: "Too much recursion", but I don't understand why.
Any suggestions are welcome.
Usually when you get a stack overflow error, it is because you have a recursion for which no exit condition exist or is triggered. Looking at your code, here's the function that causes the problem.
$('.js-main-search').data("uiAutocomplete").close = function (event) {
if (!selected) {
$('.js-main-search').data("uiAutocomplete").close.apply(this, arguments);
}
selected = false;
};
I guess the selected = false; should be inside the if statement before the recursive call like so:
$('.js-main-search').data("uiAutocomplete").close = function (event) {
if (!selected) {
selected = false;
$('.js-main-search').data("uiAutocomplete").close.apply(this, arguments);
}
};