DEV Community

Cover image for Bootstrap Selectpicker with CodeIgniter — Dynamic Rows & Refresh
sunakshi Thakur
sunakshi Thakur

Posted on

Bootstrap Selectpicker with CodeIgniter — Dynamic Rows & Refresh

Fix the most common Bootstrap Selectpicker issues in CodeIgniter — dropdowns not initializing on dynamic rows, DataTables conflicts, AJAX-loaded data, and the refresh pattern that actually works.

Difficulty: Beginner–Intermediate | Read time: 9 min | Framework: CodeIgniter 4


The Problem Everyone Hits

Bootstrap Selectpicker (the bootstrap-select plugin) looks great — searchable dropdowns, multi-select, clean UI. Then you add it to a table that loads rows dynamically (via AJAX, DataTables, or a PHP loop after page load) and... nothing. The dropdown shows as a plain unstyled <select>.

This happens because Selectpicker only styles elements that exist when the page first loads. Anything added after that needs to be manually told to initialize.

I've hit this in almost every CRM and dashboard project — staff assignment dropdowns, status filters, multi-select tags. Here's every scenario and the fix for each.

What we'll cover: Basic setup, the core refresh problem, fixing it for AJAX-loaded rows, DataTables integration, multi-select with search, and a reusable helper function for any project.


Basic Setup

<!-- CDN includes -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.18/dist/css/bootstrap-select.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.18/dist/js/bootstrap-select.min.js"></script>
Enter fullscreen mode Exit fullscreen mode
<!-- Basic select -->
<select class="selectpicker" data-live-search="true" title="Choose staff...">
    <?php foreach ($staff as $s): ?>
        <option value="<?= $s['staffid'] ?>"><?= esc($s['name']) ?></option>
    <?php endforeach; ?>
</select>

<script>
$(document).ready(function() {
    $('.selectpicker').selectpicker();
});
</script>
Enter fullscreen mode Exit fullscreen mode

This works fine for static content. The trouble starts the moment rows are added dynamically.


The Core Problem — Why Refresh Is Needed

Selectpicker converts your <select> into a styled <div> structure once, at initialization. If you then:

  • Add new <select> elements via AJAX
  • Change <option> values inside an existing select with JS
  • Reload a table with DataTables

...the new/changed elements are invisible to Selectpicker until you explicitly tell it to refresh.

// The fix — re-initialize after any DOM change
$('.selectpicker').selectpicker('refresh');
Enter fullscreen mode Exit fullscreen mode

This is the single most important line in this entire tutorial. Memorize it.


Scenario 1 — Rows Added via AJAX

Real example: assigning staff to tickets in a table, where rows are loaded by AJAX.

<!-- app/Views/tickets/index.php -->
<table id="ticketsTable" class="table">
  <thead>
    <tr>
      <th>Subject</th>
      <th>Assign To</th>
    </tr>
  </thead>
  <tbody id="ticketsBody">
    <!-- Rows injected here via AJAX -->
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode
function loadTickets() {
    $.get('<?= base_url('tickets/list') ?>', function(html) {
        $('#ticketsBody').html(html);

        // CRITICAL: refresh selectpicker after injecting new HTML
        $('.selectpicker').selectpicker('refresh');
    });
}

loadTickets();
Enter fullscreen mode Exit fullscreen mode
<!-- app/Views/tickets/_rows.php (returned by AJAX) -->
<?php foreach ($tickets as $ticket): ?>
<tr>
    <td><?= esc($ticket['subject']) ?></td>
    <td>
        <select class="selectpicker assign-staff"
                data-ticket="<?= $ticket['id'] ?>"
                data-live-search="true"
                title="Assign...">
            <?php foreach ($staff as $s): ?>
                <option value="<?= $s['staffid'] ?>"><?= esc($s['name']) ?></option>
            <?php endforeach; ?>
        </select>
    </td>
</tr>
<?php endforeach; ?>
Enter fullscreen mode Exit fullscreen mode

Key point: if Selectpicker hasn't been initialized on these elements at all yet (first load), call .selectpicker() not .selectpicker('refresh'). Refresh only works on already-initialized elements.

// Safer pattern — handles both first-time init AND refresh
function initSelectpickers() {
    $('.selectpicker').each(function() {
        if ($(this).data('selectpicker')) {
            $(this).selectpicker('refresh');
        } else {
            $(this).selectpicker();
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

Scenario 2 — DataTables Integration

This is where it gets tricky. DataTables redraws rows on pagination, search, and sort — Selectpicker needs to reinitialize on every redraw.

var table = $('#ticketsTable').DataTable({
    ajax: '<?= base_url('tickets/datatable') ?>',
    columns: [
        { data: 'subject' },
        { data: 'assign_dropdown' }  // server returns HTML for the select
    ],
    drawCallback: function() {
        // Runs after every redraw — pagination, search, sort
        $('.selectpicker').selectpicker('refresh');
    }
});
Enter fullscreen mode Exit fullscreen mode

If you're building the dropdown HTML server-side (common in CI4 with columns.render), make sure each row has a unique identifier:

columns: [
    { data: 'subject' },
    {
        data: null,
        render: function(data, type, row) {
            return '<select class="selectpicker assign-staff" data-ticket="' + row.id + '">' +
                   '<option value="">Unassigned</option>' +
                   staffOptionsHtml +  // pre-built options string
                   '</select>';
        }
    }
],
drawCallback: function() {
    $('.selectpicker').selectpicker('refresh');
}
Enter fullscreen mode Exit fullscreen mode

Scenario 3 — Changing Options Dynamically (Cascading Dropdowns)

Common pattern: selecting a State filters the City dropdown. This needs refresh too — not just on the changed select, but sometimes you need a full re-render with selectpicker('destroy') first if option count changes drastically.

$('#state').on('change', function() {
    var stateId = $(this).val();

    $.get('<?= base_url('ajax/cities') ?>/' + stateId, function(cities) {
        var $citySelect = $('#city');

        // Clear and rebuild options
        $citySelect.empty();
        $citySelect.append('<option value="">Select City</option>');

        $.each(cities, function(i, city) {
            $citySelect.append(
                $('<option>', { value: city.id, text: city.name })
            );
        });

        // Refresh AFTER options are rebuilt
        $citySelect.selectpicker('refresh');
    });
});
Enter fullscreen mode Exit fullscreen mode

If refresh alone doesn't reflect the changes properly (rare, but happens with some Selectpicker versions), use the nuclear option:

$citySelect.selectpicker('destroy').selectpicker();
Enter fullscreen mode Exit fullscreen mode

Scenario 4 — Multi-Select With Search (Common in Filters)

Used heavily for store/region filters in dashboards:

<select class="selectpicker" multiple
        data-live-search="true"
        data-selected-text-format="count > 3"
        title="Select Stores...">
    <?php foreach ($stores as $store): ?>
        <option value="<?= $store['id'] ?>"><?= esc($store['name']) ?></option>
    <?php endforeach; ?>
</select>
Enter fullscreen mode Exit fullscreen mode
$('.selectpicker').selectpicker({
    liveSearch: true,
    selectedTextFormat: 'count > 3',  // shows "5 selected" instead of listing all
    actionsBox: true                  // adds "Select All / Deselect All" buttons
});
Enter fullscreen mode Exit fullscreen mode

To pre-select values when editing a record (e.g. edit form):

// Set multiple selected values dynamically and refresh
var assignedStoreIds = [12, 45, 78]; // from PHP/JSON
$('.selectpicker').val(assignedStoreIds).selectpicker('refresh');
Enter fullscreen mode Exit fullscreen mode

Reusable Helper — Drop This in Every Project

This pattern handles 90% of real-world cases safely:

/**
 * Universal Selectpicker initializer/refresher.
 * Safe to call after ANY DOM change.
 */
function refreshSelectpickers(selector) {
    selector = selector || '.selectpicker';

    $(selector).each(function() {
        var $el = $(this);
        if ($el.data('selectpicker')) {
            $el.selectpicker('refresh');
        } else {
            $el.selectpicker();
        }
    });
}

// Call this after:
// - AJAX content load
// - DataTables drawCallback
// - Modal opening (Bootstrap modal 'shown.bs.modal' event)
// - Tab switching ('shown.bs.tab' event)

$(document).on('shown.bs.modal', '.modal', function() {
    refreshSelectpickers();
});

$(document).on('shown.bs.tab', 'a[data-bs-toggle="tab"]', function() {
    refreshSelectpickers();
});
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls

⚠️ 1. Calling .selectpicker() again on already-initialized elements

This causes duplicate dropdowns to stack visually. Always use refresh, not re-init, unless it's truly the first time.

⚠️ 2. Selectpicker inside a hidden element (modal, tab)

If the <select> is inside a display: none container when initialized, Selectpicker calculates wrong widths. Always refresh after the container becomes visible:

$('#myModal').on('shown.bs.modal', function() {
    $(this).find('.selectpicker').selectpicker('refresh');
});
Enter fullscreen mode Exit fullscreen mode

⚠️ 3. Selectpicker breaking inside Bootstrap tabs

Same root cause as modals — hidden tab content has zero width when Selectpicker initializes. Use the shown.bs.tab event shown above.

⚠️ 4. Values not syncing with the actual <select> element

If you're using a JS framework alongside jQuery, remember Selectpicker creates a visual clone — the underlying <select> element still holds the real value. Always read/write via jQuery ($('.selectpicker').val()), not by manipulating the DOM directly.


What to Read Next

  • CodeIgniter 4 DataTables Server-Side Processing — pairs perfectly with this for filterable tables
  • CodeIgniter 4 Custom Validation Rules — validate selectpicker values server-side
  • Role-Based Access Control in CodeIgniter 4 — hide dropdown options based on permissions

Conclusion

Bootstrap Selectpicker is a great UI upgrade, but it has one rule you must never forget: anything that changes the DOM needs a refresh call afterward. Build the habit of calling refreshSelectpickers() after every AJAX load, modal open, or tab switch, and you'll never see a plain unstyled dropdown again.

Follow me for more CodeIgniter production tutorials — 3 new articles every week. 🙌


Senior PHP Developer · 12+ years building production systems on CodeIgniter, Laravel & WordPress

Top comments (1)

Collapse
 
frank_signorini profile image
Frank

I'm curious how you're handling the re