Client‑Side Utility Library – pp Object
The pp global object provides modern, lightweight utilities that work everywhere in the framework — AJAX requests, dialog boxes, form helpers, and common functions like debounce and deep clone. It is loaded automatically on every project SPA page.
Dependencies: SweetAlert2 (must be loaded before pp.js).
Contents
- pp.ajax – HTTP Requests
- pp.dialog – User Dialogs
- pp.form – Form Utilities
- pp.util – General Helpers
- Real‑World Examples
pp.ajax – HTTP Requests
Thin wrappers around the Fetch API with built‑in JSON handling and a loading spinner helper.
GET request
const users = await pp.ajax.get('/api/users');
POST request (JSON)
const result = await pp.ajax.post('/api/save', {
name: 'Alice',
email: 'alice@example.com'
});
console.log(result.success); // true/false
File upload with progress
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const response = await pp.ajax.upload('/api/upload', formData, (percent) => {
console.log(`Uploading: ${percent}%`);
});
GET with automatic loading spinner
const data = await pp.ajax.load('/api/slow-endpoint', 'Fetching records…');
// Shows a SweetAlert2 spinner while loading, then auto‑closes
Adding custom headers
const data = await pp.ajax.get('/api/secure', {
headers: { 'X-CSRF-Token': csrfToken }
});
pp.dialog – User Dialogs
Unified SweetAlert2 shortcuts that keep every module's UI consistent.
Toast notification
pp.dialog.toast('success', 'Record saved!');
pp.dialog.toast('error', 'Something went wrong.');
pp.dialog.toast('warning', 'Please check your input.');
pp.dialog.toast('info', '3 new notifications.');
Confirmation dialog
const confirmed = await pp.dialog.confirm(
'Delete this record?',
'This action cannot be undone.'
);
if (confirmed) {
// proceed with deletion
}
Custom confirmation buttons
const yes = await pp.dialog.confirm('Archive?', 'Move to archive.', {
confirmText: 'Archive',
cancelText: 'Keep',
confirmColor: '#0d6efd'
});
Text prompt
const folderName = await pp.dialog.prompt('New folder', 'Enter folder name');
if (folderName) {
// create folder
}
Simple alert
await pp.dialog.alert('Done', 'All files processed.', 'success');
pp.form – Form Utilities
Quick value access and simple validation without heavyweight plugins.
Get / Set a form value
const email = pp.form.getValue('#email');
pp.form.setValue('#name', 'John Doe');
Checkbox and radio
const active = pp.form.getValue('#activeCheckbox'); // true/false
pp.form.setValue('#activeCheckbox', true);
const plan = pp.form.getValue('input[name="plan"]'); // 'basic'
pp.form.setValue('input[name="plan"]', 'premium');
Validate a field
const { valid, message } = pp.form.validate('#email', {
required: true,
email: true,
requiredMessage: 'Email is required.'
});
if (!valid) {
pp.dialog.toast('error', message);
}
Validate with minlength and pattern
const check = pp.form.validate('#username', {
required: true,
minlength: 3,
pattern: /^[a-zA-Z0-9_]+$/,
patternMessage: 'Only letters, numbers, and underscores allowed.'
});
Serialise a form to an object
const data = pp.form.toObject('#myForm');
// { name: "Alice", email: "alice@example.com", subscribe: "on" }
await pp.ajax.post('/api/submit', data);
pp.util – General Helpers
Debounce (search input)
const doSearch = pp.util.debounce((query) => {
fetch(`/api/search?q=${query}`).then(res => res.json()).then(renderResults);
}, 400);
document.getElementById('searchBox').addEventListener('input', (e) => {
doSearch(e.target.value);
});
Throttle (scroll handler)
window.addEventListener('scroll', pp.util.throttle(() => {
console.log('User is scrolling...');
}, 200));
Format a date
pp.util.formatDate('2025-06-15'); // "Jun 15, 2025, 12:00 am"
pp.util.formatDate('2025-06-15', 'F j, Y'); // "June 15, 2025"
pp.util.formatDate('2025-06-15 14:30:00', 'H:i'); // "14:30"
Deep clone an object
const original = { a: 1, b: { c: 2 } };
const copy = pp.util.deepClone(original);
copy.b.c = 99;
console.log(original.b.c); // 2 (unchanged)
Generate a UUID
const id = pp.util.uuid(); // "c9b5a2e4-1234-4abc-5678-def012345678"
Escape HTML
const safe = pp.util.escapeHtml('<script>alert("xss")</script>');
// "<script>alert("xss")</script>"
Real‑World Examples
Example 1 – Save form with loading spinner
async function saveRecord() {
const data = pp.form.toObject('#recordForm');
const result = await pp.ajax.load('/api/save', 'Saving…', {
method: 'POST',
body: JSON.stringify(data)
});
if (result.success) {
pp.dialog.toast('success', 'Record saved!');
} else {
pp.dialog.toast('error', result.message);
}
}
Example 2 – Delete with confirmation
async function deleteRecord(id) {
const ok = await pp.dialog.confirm('Delete?', 'Record #' + id + ' will be permanently removed.');
if (!ok) return;
const result = await pp.ajax.post('/api/delete', { id });
if (result.success) {
pp.dialog.toast('success', 'Deleted.');
}
}
Example 3 – Live search with debounce
const search = pp.util.debounce(async (query) => {
const results = await pp.ajax.get(`/api/search?q=${encodeURIComponent(query)}`);
renderResults(results);
}, 300);
document.getElementById('searchInput').addEventListener('input', e => search(e.target.value));
Example 4 – Form validation before submit
document.getElementById('saveBtn').addEventListener('click', async () => {
const emailCheck = pp.form.validate('#email', { required: true, email: true });
const nameCheck = pp.form.validate('#name', { required: true, minlength: 2 });
if (!emailCheck.valid) return pp.dialog.toast('error', emailCheck.message);
if (!nameCheck.valid) return pp.dialog.toast('error', nameCheck.message);
// All good – submit
await pp.ajax.post('/api/save', pp.form.toObject('#myForm'));
pp.dialog.toast('success', 'Saved!');
});