← All documentation
Topics

- Working with data
- Designer components
- Field controls
- Search & filtering
- Calendars
- PDF & printing
- Email
- SMS
- Notifications
- Security
- Helper functions
- JavaScript API
- Performance

# 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>');
    // "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

## 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!');
    });

### 🔗 Related Help Topics

Database API Security API Search API