My application pulls dropdown list options using an API and dynamically creates the dropdowns inline in the table when the user clicks an edit button. Everything was working as expected using jQuery's basic "Select" functionality. Aaaaand then I saw Select2 with all of its shininess and built in search boxes. Since my lists will become quite long in production, that's functionality I really should have. I've seen many snippets where people simply call .select2() on the select item and have it working out of the box. I get the box, but it's not working :) The Select2 box appears and has the correct dropdown item selected, but when I click on the box there are no dropdown options.
I've duplicated the basic functionality and structure of my application, including simulated API data responses. Is there a way to make the existing select function work or do I need to build it from the ground up using Select2? Further, based on my data structure, is that even possible?
Thanks for taking a look!
JS Fiddle includes the same code but is included for your editing convenience: https://jsfiddle.net/tekowalski/amrhjo6y/9/
$(document).ready(function () {
$('#edit_btn').click(function () {
let clickedRow = $($(this).closest('td')).closest('tr');
$(clickedRow).find('td').each(function () {
if ($(this).hasClass('edit_account')) {
fnCreateDropdown($(this), option_data);
}
});
});
function fnCreateDropdown(obj, options) {
let html = '<select type="dropdown-menu dropdown-menu-end">';
let account_type = '';
let grouped = false;
for (var idx in options) {
let my_act_type = options[idx]['account_type_name']; // Set Account Type
if(my_act_type !== account_type) {
if(grouped === true) { // Close out option group if one has been made
html = '</optgroup>'
}
html = '<optgroup label="' my_act_type '">'
grouped = true;
account_type = my_act_type; // Set account_type for next loop
}
if (options[idx]['id'] === 2) {
selected = ' selected ';
} else {
selected = '';
}
html = '<option ' selected 'id="' options[idx]['id'] '">' options[idx]['name'] '</option>';
}
html = '</optgroup></select>';
obj.html($(html));
$(obj).select2(); // Comment out this line for a functional select with dropdown options
}
option_data = [
{account_type_id: 1, account_type_name: 'Asset', id: 1, name: 'Asset Account'},
{account_type_id: 2, account_type_name: 'Expense', id: 2, name: 'Expense Account'}
]
});
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<table>
<thead>
<tr>
<th>Account Name</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td >
Expense Account
</td>
<td>
<button id='edit_btn'>Edit</button>
</td>
</tr>
</tbody>
</table>
CodePudding user response:
.select2() must be applied to a <select> element.
In this case, obj.select2() does not apply to a <select> as it's the container that the dynamically generated select is inserted into.
Change
$(obj).select2();
to
obj.find("select").select2()
to apply to the select inside the container.
Side note: obj is already a jquery object, so there's no need to wrap it again, but it does not harm other than a tiny overhead.
Updated snippet:
$(document).ready(function () {
$('#edit_btn').click(function () {
let clickedRow = $($(this).closest('td')).closest('tr');
$(clickedRow).find('td').each(function () {
if ($(this).hasClass('edit_account')) {
fnCreateDropdown($(this), option_data);
}
});
});
function fnCreateDropdown(obj, options) {
let html = '<select type="dropdown-menu dropdown-menu-end">';
let account_type = '';
let grouped = false;
for (var idx in options) {
let my_act_type = options[idx]['account_type_name']; // Set Account Type
if(my_act_type !== account_type) {
if(grouped === true) { // Close out option group if one has been made
html = '</optgroup>'
}
html = '<optgroup label="' my_act_type '">'
grouped = true;
account_type = my_act_type; // Set account_type for next loop
}
if (options[idx]['id'] === 2) {
selected = ' selected ';
} else {
selected = '';
}
html = '<option ' selected 'id="' options[idx]['id'] '">' options[idx]['name'] '</option>';
}
html = '</optgroup></select>';
obj.html($(html));
obj.find("select").select2();
}
option_data = [
{account_type_id: 1, account_type_name: 'Asset', id: 1, name: 'Asset Account'},
{account_type_id: 2, account_type_name: 'Expense', id: 2, name: 'Expense Account'}
]
});
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<table>
<thead>
<tr>
<th>Account Name</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td >
Expense Account
</td>
<td>
<button id='edit_btn'>Edit</button>
</td>
</tr>
</tbody>
</table>
