Milk Admin

This section describes how to add actions to tables such as edit and delete or CSV download.

Register Hook

In tables you can create actions and register them in JavaScript using the registerHook method.

1. JavaScript

For example:


registerHook('table-action-table_posts-edit', function (id) {
    window.location.href = milk_url + '?page=posts&action=edit&id=' + id;
    return false;
});

registerHook('table-action-table_posts-delete', function (id) {
    return confirm('Delete this post?');
});

The registerHook receives as the first parameter the string 'table-action-{table_id}-{action}'.
It returns a boolean. If true, it makes the fetch call and updates the table; if false, it doesn't make the fetch call. In this example, edit redirects to the edit page and delete makes the fetch call and updates the table.

2. Backend PHP

In the router, the delete calls the same function that is called when generating the table. If you are extending the AbstractController, you just need to write:

 $this->callTableAction($table_id, 'delete', 'table_action_delete');

and then create a new function

protected function tableActionDelete($id, $request) {
    if ($this->model->delete($id)) {
        return true;
    } else {
        MessagesHandler::addError($this->model->getLastError());
        return false;
    }
}

For edit, instead, it redirects to a new page so it's handled normally in the router by writing a new action_edit function

protected function actionEdit() {
    $id = _absint($_REQUEST['id'] ?? 0);
    $data = $this->model->getByIdForEdit($id,  Route::getSessionData()); 
    Response::themePage('default', __DIR__ . '/Views/edit.page.php',  ['id' => _absint($_REQUEST['id'] ?? 0), 'data' => $data, 'page' => $this->page, 'url_success'=>'?page='.$this->page, 'action_save'=>'save']);
}

CSV Export with Table Filters

Tutorial for implementing CSV download of filtered table data using the table_action system.

1. Export Button Setup

Open the list.page.php file and add the export button in the title section:


    'btns' => [ ['title'=>'Add New', 'color'=>'primary', 'link'=>'?page='.$page.'&action=edit'], ['title'=>'Export CSV', 'color'=>'success', 'class'=>'js-export-csv', 'link'=>'#'] ]    
    

2. JavaScript - Export Function

Create the JavaScript function to handle the download:

// Initialize export button
    // Initialize export button
document.addEventListener('DOMContentLoaded', function() {
    document.querySelector('.js-export-csv').addEventListener('click', function() {
        exportData();
    });
});

/**
 * Export table data to CSV
 */
function exportData() {
    const btnExport = document.querySelector('.js-export-csv');
    if (btnExport.classList.contains('disabled')) {
        return;
    }
    btnExport.classList.add('disabled');
    
    // Get table component
    const table = getComponent('table_posts');
    table.setActionFields('export-csv');
    table.setPage(1);
    
    // Submit form to trigger download
    const form = table.getForm();
    form.submit();
    
    // User feedback
    window.toasts.show();
    window.toasts.body('Export started, download will begin shortly...', 'primary');
    
    // Re-enable button
    setTimeout(() => {
        btnExport.classList.remove('disabled');
        window.toasts.hide();
    }, 3000);
}

3. Backend PHP

In the router, add the logic to handle the export before HTML generation:

protected function actionHome() {
     // At the end of the function before output_table_response add:

        // Table form parameters are of the type {table_id}[param]. So to get them easily you can use the get_request_params function inside the AbstractController class
        $request = $this->getRequestParams($table_id);
        if (isset($request['table_action']) && $request['table_action'] == 'export-csv') {
            $this->exportCsv($modellist_data['rows']);
            return;
        }
    
}

private function exportCsv($rows) {
    $timestamp = date('Y-m-d_H-i-s');
    $filename = "posts_export_{$timestamp}.csv";
    
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    
    $output = fopen('php://output', 'w');
    
    // Headers
    fputcsv($output, ['ID', 'Title', 'Author', 'Status', 'Created'], ',', '"', '\\');
    
    // Data
    foreach ($rows as $row) {
        fputcsv($output, [
            $row->id ?? '',
            $row->title ?? '',
            $row->author ?? '',
            $row->status ?? '',
            (is_a($row->created_at, 'DateTime') ? $row->created_at->format('Y-m-d H:i:s') : $row->created_at) ?? ''
        ], ',', '"', '\\');
    }
    
    fclose($output);
    exit;
}
Loading...