bootstrap-select
bootstrap-select copied to clipboard
Dynamically adding new items to select when live searching - offer GUI option
I know it seems strange because select should offer a controlled list but I found one use case.
My use case:
- replace multiple input fields with dropdown
- use checked mark to show selected items
- user can toggle items and reconsider
- user can add new items
I think it would be useful to have a feature alongside live search where one could add new items to dropdown list when search does not find requested term. Steps:
- search something
- zero results - did not find anything
- offer plus/add button in GUI to add new item to select
- refresh select
Slim Select can do this with it's addable
option: https://slimselectjs.com/options
Would be great to see it come to bootstrap-select too.
I have used this workaround to get "add new" functionality inside the dropdown: Feel free to get inspired :)
HTML
<select name="location" id="location" class="form-control selectpicker" data-live-search="true" data-live-search-normalize="true" data-sanitize="false" data-live-search-placeholder="Search locations..." data-size="15" title="Choose location..." required>
<option class="add-item" data-content="<input type='text' class='new-loc-input my-1' onKeyDown='event.stopPropagation();' onKeyPress='addSelectInpKeyPress(this,event)' onClick='event.stopPropagation()' placeholder='Create new location'> <i class='fa fa-plus add-new-icon px-1' aria-hidden='true' onClick='addSelectItem(this,event,1);'></i>"></option>
<option data-divider="true"></option>
</select>
CSS:
a.add-item {
cursor: default !important;
pointer-events: none;
}
a.add-item .text {
display: block !important;
}
a.add-item.active, a.add-item:active {
background-color: transparent;
}
.new-loc-input {
border:0;
outline: none;
width: 40%;
pointer-events: auto;
}
.new-loc-input:hover {
background-color: #f5f5f5;
}
.add-new-icon {
color: #aaa;
cursor: pointer;
pointer-events: auto;
}
.add-new-icon:hover {
color: #222;
}
javascript (jqeury)
$(function() {
// data-sanitize="false" on the select element doesn't seem to work so we go for js initialization os selectpicker
$('.selectpicker').selectpicker({
sanitize: false,
});
});
function addSelectItem(option, event) {
event.stopPropagation();
let $bootstrap_select = $(option).closest('.bootstrap-select');
let $select = $bootstrap_select.find('select');
let $input = $bootstrap_select.find('.new-loc-input');
let new_location_name = $input.val();
if ($.trim(new_location_name) === '') {
return;
}
$input.prop('disabled', true);
let $icon = $bootstrap_select.find('.add-new-icon').removeClass('fa-plus').addClass('fa-spin fa-spinner');
SOME_AJAX_CALL({
name: new_location_name,
}, function(data) {
$icon.removeClass('fa-spin fa-spinner').addClass('fa-plus');
if (data.success) {
let $new_option = $("<option>", {
selected: true,
text: new_location_name,
value: data.group_id,
});
$new_option.insertAfter($select.find('option:nth-child(3)'));
$select.selectpicker('refresh');
} else {
let $error_message = $('.error-message').hide().removeClass('d-none');
$error_message.find('span').text(data.error_message);
$error_message.slideDown();
}
});
}
function addSelectInpKeyPress(option, event) {
event.stopPropagation();
// enter character submits the new option
if (event.which == 13) {
event.preventDefault();
addSelectItem($(option).next(),event);
}
}