PVR Tech Studio

JavaScript Helpers

What app.js does on every page and the shared helpers it provides.

3 min read
Updated June 21, 2026

assets/js/core/app.js is loaded on every page. It does two things:

  1. Auto-initializes the common UI on document.ready — you don't wire these up.
  2. Exposes a small API (app.*, API_CONFIG, window.i18n) your page scripts can call.

Page scripts live at assets/js/pages/<feature>/<page>.js and are included at the very end of the page's <body>.

Auto-initialized on load

When the page loads, app.js sets up:

  • Tooltips and popovers
  • The sidebar (accordion menus, slim-scroll, minify toggle, mobile drawer)
  • The header (search, fullscreen, notifications/chat offcanvas)
  • Date / datetime pickers, dropdowns
  • The theme toggle and the language switcher
  • The loading screen (hides it once ready)

So a typical page script only adds page-specific behavior (e.g. building a DataTable).

Toasts

app.toast.success('Saved successfully');
app.toast.error('Something went wrong');
app.toast.warning('Please confirm before continuing');
app.toast.info('Heads up — this is informational');
 
// optional custom heading / full options
app.toast.success('Saved', 'Done');
app.toast.show({ heading: 'Custom', text: 'Message', icon: 'success' });

Demo: toastNotifications.html.

Form validation helper

app.validation wraps jQuery Validate with the kit's defaults (Bootstrap is-invalid / is-valid styling, error placement inside .form-group):

app.validation.init('#myForm', {
    rules:    { email: { required: true, email: true } },
    messages: { email: { required: 'Email is required' } },
    submitHandler: function (form) { /* collect + submit */ }
});

You can also call jQuery Validate's $('#form').validate({...}) directly — that's what the formValidation.html demo does. See 04 — Forms › Validation.

DataTables helpers

Used by every list page (see 05 — Tables for the full recipe):

HelperDescription
app.datatables.getDom()Returns the standard dom layout string (length menu, filter, table, info, paging).
app.datatables.initDefaults()Applies global DataTables defaults.
app.datatables.initToolbar(api, table, opts)Builds the table toolbar. opts: addButton: {text, href}, expandButton: true, filterButton: true.
app.datatables.renderers.actionButtons([{className, icon, title}, …])Returns HTML for row action icon buttons.
app.datatables.renderSerialNumbers(api, colIndex)Fills a running serial-number column.
app.datatables.initProcessingState(selector)Shows the themed processing/loading state.
app.datatables.initExpandEvents(table, formatFn)Wires expandable child rows; formatFn(rowData) returns the child HTML.
$('#initDataTable').DataTable({
    dom: app.datatables.getDom(),
    columns: [ /* … */ ],
    columnDefs: [{
        targets: -1,
        render: () => app.datatables.renderers.actionButtons([
            { className: 'btn-edit', icon: 'edit',       title: 'Edit' },
            { className: 'btn-view', icon: 'visibility', title: 'View' }
        ])
    }],
    initComplete: function () {
        app.datatables.initToolbar(this.api(), table, {
            addButton: { text: 'Add', href: 'addMyPage.html' }, filterButton: true
        });
    },
    drawCallback: function () { app.datatables.renderSerialNumbers(this.api(), 0); }
});

Utilities

// Build DOM safely (returns a real element)
app.utils.createElement('div', {
    classes: ['btn', 'btn-primary'],
    attrs:   { id: 'saveBtn', type: 'button' },
    text:    'Save',
    children: [ /* more elements */ ]
});
 
// Safe nested lookup with optional fallback
app.utils.getValue(obj, 'a.b.c');        // undefined-safe
app.utils.getValue(value, '—');          // fallback when empty
 
// Short number formatting
app.formatNumberShort(1500000);          // → "1.5M"
app.formatNumberShort(2500);             // → "2.5K"

Inline editing

// Triggered by data-editable attributes in the markup (see 04 — Forms)
app.inlineEditable /* …popup / inline edit handlers… */

API_CONFIG — data source (live API or static JSON)

API_CONFIG in app.js centralizes where data comes from. It has two modes via staticMode:

  • staticMode: false (the source/live demo default) — calls a real API at baseUrl (https://api.pvrtechstudio.com/taxi-crm/api, or http://localhost:8080/taxi-crm/api locally).
  • staticMode: true — reads bundled JSON from dataBase (assets/data/). The ThemeForest download is shipped this way, so the template runs on any static server with no backend.
// Pages call getUrl(); DataTables uses the result as its ajax URL:
$('#initDataTable').DataTable({
    ajax: { url: API_CONFIG.getUrl(API_CONFIG.endpoints.RoleMaster.getRoleMaster), dataSrc: 'data' }
});
// staticMode:true  → 'assets/data/RoleMaster/getRoleMaster.json'      (bundled)
// staticMode:false → baseUrl + '/RoleMaster/getRoleMaster'            (your API)
MemberWhat it is
API_CONFIG.staticModetrue reads bundled JSON from dataBase; false calls a live API at baseUrl.
API_CONFIG.dataBaseFolder holding the bundled demo JSON (assets/data).
API_CONFIG.baseUrlServer base URL — used only when staticMode is false.
API_CONFIG.endpointsA map of named endpoint paths grouped by feature (e.g. RoleMaster.getRoleMaster).
API_CONFIG.headersDefault request headers sent with each call.
API_CONFIG.getUrl(path)In static mode → dataBase + path + '.json'; otherwise → baseUrl + path.

Both modes return the same envelope {status, code, message, data}, and DataTables reads data. To point at your own API, set API_CONFIG.staticMode = false and API_CONFIG.baseUrl, and return that shape. To add an endpoint, add it to the endpoints map in the API CONFIG section of app.js. DataTables list pages pass getUrl(...) straight into the table's ajax option (see Tables).

i18n engine

app.js also boots the translation engine. The essentials:

window.i18n.setLocale('fr');     // switch language at runtime
window.i18n.getLocale();         // current language
window.i18n.t('roleMaster.mainPanelTitle');   // look up a key in code

Markup uses data-i18n attributes — full details in 09 — i18n.

Was this page helpful?