jBob
Opinionated utilities for jQuery and Bootstrap.
Here you can find a demo for most features: https://www.madbob.org/jbob/demo.html
Usage
require('jbob');
let j = new jBob();
j.init();
Features
Most of features in jBob are implicitly activated adding specific CSS classes directly into the HTML. The init()
function provides to attach all the proper jQuery handlers, and manage initialization of other components fetched asynchronously.
Async Modals
When clicked, an .async-modal
button will fetch a Bootstrap modal from a given URL and will display it. When closed, the modal is destroyed and removed from the DOM (this is valid for all modals with the CSS class .delete-on-close
, which is automatically added to all modals fetched in this way). The URL can be both in the data-modal-url
attribute or, if the trigger is an anchor, in the href
attribute.
<button class="btn btn-primary async-modal" data-modal-url="/my/endpoint">Click Me</button>
<a class="btn btn-primary async-modal" href="#" data-modal-url="/my/endpoint">Click Me</a>
<a class="btn btn-primary async-modal" href="/my/endpoint">Click Me</a>
Modal Form
A form within a Bootstrap modal and having the .modal-fom
CSS class, when submitted is serialized, submitted to the given action
URL using his own method
, and - on success - the parent modal is closed.
<div class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form action="/my/endpoint" method="POST" class="modal-form">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="example" class="form-label">Email address</label>
<input type="email" class="form-control" id="example">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
Async Tabs
A tab having the .async-tab
CSS class will fetch his contents from the given URL when activated. When the tab is no longer active, his contents are removed again from the DOM.
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link active" data-bs-toggle="tab" data-bs-target="#first" type="button" role="tab">First</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link async-tab" data-tab-url="/my/endpoint" data-bs-toggle="tab" data-bs-target="#second" type="button" role="tab">Second</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="first" role="tabpanel">
<!-- Contents of the first active tab -->
</div>
<div class="tab-pane fade" id="second" role="tabpanel">
<!-- This is left empty: the contents of the tab are fetched when the tab itself is activated -->
</div>
</div>
Async Accordions
An accordion having the .async-accordion
CSS class will fetch his contents from the given URL when activated.
<div class="accordion">
<div class="accordion-item async-accordion" data-accordion-url="/my/endpoint/1">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#first">First</button>
</h2>
<div id="first" class="accordion-collapse collapse">
<div class="accordion-body">
<!-- This is left empty: the contents of the accordion are fetched when the item itself is activated -->
</div>
</div>
</div>
<div class="accordion-item async-accordion" data-accordion-url="/my/endpoint/2">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#second">Second</button>
</h2>
<div id="second" class="accordion-collapse collapse">
<div class="accordion-body">
<!-- Same as above -->
</div>
</div>
</div>
</div>
Async Popovers
A .async-popover
button has a popover which contents as dinamycally fetched from the given URL when activated. On the contrary of other components, an async popover keeps its contents even when closed (so are fetched just once). Remember that Bootstrap popovers have to be explicitely inited in your own JS (it is not automatically managed to avoid conflicts with other popovers not handled with jBob).
<button type="button" class="btn btn-light async-popover" data-contents-url="/my/endpoint" data-bs-toggle="popover" data-bs-content="placeholder" data-bs-html="true" data-bs-trigger="hover">Hover Me!</button>
Dynamic Table
A dynamic table permits to add and remove rows dynamically. The contents of tfoot
are used as template for newly added contents: remember to hide it, using a specific CSS rule or with a hidden
attribute.
<table class="table dynamic-table">
<tbody>
<tr>
<td>First row: something</td>
<td>First row: something else</td>
<td><button class="btn btn-danger remove-row">Remove</button></td>
</tr>
<tr>
<td>Second row: something</td>
<td>Second row: something else</td>
<td><button class="btn btn-danger remove-row">Remove</button></td>
</tr>
<tr>
<td colspan="3"><button class="btn btn-info add-row">Add</button></td>
</tr>
</tbody>
<tfoot hidden>
<tr>
<td><input type="text" placeholder="A new row's something!"></td>
<td><input type="text" placeholder="A new row's something else!"></td>
<td><button class="btn btn-danger remove-row">Remove</button></td>
</tr>
</tfoot>
</table>
Functions
There are a few functions you can use, even if just init()
is required. All of the above described behaviors are handled automatically.
init(params)
Accepts an optional object for parameters:
-
initFunction
: a callback to be called on all HTML fragments fetched asynchronously, to provide your own extra initialization on new HTML nodes injected into the page. A parameters is passed to the function, which is the new HTML node itself.
j.init({
initFunction: function(container) {
$('#myselector', container).myfunction();
}
});
-
fixBootstrap
: an array of Bootstrap's jQuery plugins for which enforce initialization. "Modal" and "Popover" are handled by default, you can add others. This may be required under certain situations (e.g. you have to bundle your stuff using Vite), where Bootstrap fails to identify jQuery and do not inits his own plugins. In this case, you have to explicitely import Boostrap and make it globally accessible from thewindow
object under the namebootstrap
.
import * as bootstrap from 'bootstrap';
window.bootstrap = bootstrap;
j.init({
fixBootstrap: ['Tooltip', 'Toast']
});
assignIDs(selector, container)
For each node matching the jQuery selector
found in container
, generates a random ID attribute (if none is already found).
j.assignIDs('.my-button', $('body'));
fetchNode(url, node)
Fetches HTML from the given url
and replaces the contents of node
in DOM.
j.fetchNode('/my/endpoint', $('.target-node'));
reloadNode(node)
Almost like fetchNode()
, but node
must have a data-reload-url
attribute with the URL from where get the new HTML. node
is replaced with the new HTML (not only his contents). If applied on a modal, the full modal is reloaded (to be used with Async Modals).
<div class="target-node" data-reload-url="/my/endpoint"></div>
j.reloadNode($('.target-node'));
submitButton(form)
Utility intended to easily retrieve the submit button of a form; it may be both within the form itself (button[type=submit]
) or external (having a form
attribute which value matches the id
of the intended form).
j.submitButton(form).prop('disabled', true);
serializeForm(form)
Like the jQuery's native serialize()
, but skips elements having the .skip-on-submit
CSS class.
<form>
<input type="hidden" class="skip-on-submit" name="will_not_be_serialized" value="1">
<input type="text" name="will_be_serialized">
</form>
j.serializeForm($('form'));