Projects Manage View - Part 2

To finalize the new view, both a data table and AJAX function need to be developed out. Follow the below instructions.

AJAX Function - add-assignee

Create the necessary AJAX function by running the following create ajax command within terminal:

apex create ajax disaster add_assignee

Open the newly generated file at /src/Disaster/Opus/Ajax/AddAssignee.php and replace its contents with:

declare(strict_types = 1);

namespace App\Disaster\Opus\Ajax;

use Apex\Svc\App;
use Apex\App\Base\Web\Ajax;
use App\Users\User;
use App\Disaster\Models\Assignee;
use Apex\App\Interfaces\Opus\AjaxInterface;

 * Ajax - AddAssignee
class AddAssignee extends Ajax implements AjaxInterface

    private App $app;

     * Process AJAX function
    public function process():void

        // Ensure user exists
        $uuid = $this->app->post('user_id', 'undefined');
        if (!$user = User::loadUuid($uuid)) {
            $this->alert("No user specified");

        // Add assignee
        $assignee = Assignee::insert([
            'is_active' => true,
            'project_id' => $this->app->post('project_id'), 
            'uuid' => $uuid

        // Get data row
        $row = $assignee->toArray();
        $this->addDataRows('tbldisasterAssignees', 'disaster.assignees', [$row]);


The above AJAX function utilizes the built-in Ajax library and simply adds a volunteer to the project being managed, then adds a row to the data table without the page being reloaded.

Data Table - disaster.Assignees

Last, create the new data table by running the following create table CLI command:

apex create table disaster assignees

Since data tables have already been covered within this training program, open the newly generated file at /src/Disaster/Opus/DataTables/Assignees.php and replace the contents with:

declare(strict_types = 1);

namespace App\Disaster\Opus\DataTables;

use Apex\Svc\{App, Db, Convert};
use App\Users\User;
use Apex\App\Interfaces\Opus\DataTableInterface;

 * Data Table - Assignees
class Assignees implements DataTableInterface

    // Columns
    public array $columns = [
        'id' => 'ID',
        'is_active' => 'Active',
        'user' => 'User',
        'created_at' => 'Date Created'
    public array $sortable = ['id', 'created_at'];

    // Other variables
    public int $rows_per_page = 25;
    public bool $has_search = false;

    // Form field (left-most column)
    public string $form_field = 'checkbox';
    public string $form_name = 'assignee_id';
    public string $form_value = 'id'; 

    // Delete button
    public string $delete_button = 'Delete Checked Assignees';
    public string $delete_dbtable = 'disaster_assignees';
    public string $delete_dbcolumn = 'id';

     * Constructor
     * All attributes within the <b>ERROR:</b> No 'alias' attribute exists within the function tag. tag are passed to this method during instantiation, 
     * and here you can define various properties (ie. userid, type, et al) to be used in below methods.
    public function __construct(
        private array $attr, 
        private App $app, 
        private Db $db,
        private Convert $convert
    ) { 
        $this->project_id = $attr['project_id'] ?? 0;

     * Get total rows in data set - used for pagination.
    public function getTotal(string $search_term = ''):int 

        // Get total
        $total = $this->db->getField("SELECT count(*) FROM disaster_assignees WHERE project_id = %i", $this->project_id);
        return (int) $total;

     * Get rows to display on current page.
     * Should return an array with each element being an associative array representing one table row.
    public function getRows(int $start = 0, string $search_term = '', string $order_by = 'id asc'):array 

        // Get rows
        $rows = $this->db->query("SELECT * FROM disaster_assignees WHERE project_id = %i ORDER BY $order_by LIMIT $start,$this->rows_per_page", $this->project_id);

        // Go through rows
        $results = [];
        foreach ($rows as $row) { 
            $results[] = $this->formatRow($row);

        // Return
        return $results;

     * Format individual row for display to browser.
    public function formatRow(array $row):array

        // Get user
        $user = User::loadUuid($row['uuid']);
        $row['user'] = $user->getUsername() . ' (' . $user->getFullName() . ')';

        // Format
        $row['is_active'] = $row['is_active'] == 1 ? 'Yes' : 'No';
        $row['created_at'] = $this->convert->date($row['created_at']);

        // Return
        return $row;


This data table class simply retrieves all assigned volunteers to the project and shows them within the table.


Now if you visit the Disaster Relief->Projects menu of the administration panel, you can click on the "Manage" button within any of the data tables and the newly developed projects_manage view will be displayed. This view contains one tab control with two pages, the second page allowing you to view and manage assigned volunteers. This tab page incorporates an auto-complete list allowing you to easily select a user from the database, and an AJAX function that will add the selected user as a volunteer to the project and automatically add the appropriate row to the data table without having to reload the page.