Fast Add
fastadd is a table button that lets the user append a new editable row to an inline table,
without leaving the current page.
Fast elements are always used with a table. You build a table with magic->get_table($table),
bind it to a database table (the detail/child records you want to manage), and enable fastadd through
$table['tb_button']. When the user clicks the add button, the framework requests a fresh row from
the AJAX handler named in $table['tb_get'] and appends it to the table body.
Use fastadd when:
- You need to add child/detail rows inline (e.g., branch products, related parties, rate rows).
- The rows belong to a parent record that is being edited on the same page.
- You want add + delete row management without a dedicated page.
Enable fastadd on a table
Real example from installment/company_branch.module.php — an inline table of
company_branch_product rows. tb_get points to the AJAX handler that builds a new row, and
tb_button enables the fastadd button.
- Table config
- PHP (module)
- PHP (AJAX row)
{
"tb_id": "tb_company_branch_product",
"tb_get": "add_company_branch_product",
"tb_header": ["product_category", "max_quantity", "allow_quantity_excess_on_edit"],
"tb_button": { "fastadd": true }
}
// Build the inline detail table
$table = [];
$table['tb_id'] = 'tb_company_branch_product';
$table['tb_get'] = 'add_company_branch_product'; // -> ax_add_company_branch_product()
$table['tb_header'] = [
$this->app->language('product_category'),
$this->app->language('max_quantity'),
$this->language('allow_quantity_excess_on_edit'),
];
$table['tb_body'] = [];
// ... fill tb_body with existing rows ...
$table['tb_button'] = ['fastadd' => true];
$conf['block'][0]['group'][5]['html'] = $this->addons->magic->get_table($table);
// ax_add_company_branch_product() — returns the HTML for one new row
public function ax_add_company_branch_product(): array
{
$response = ['success' => '0', 'message' => '', 'error' => '', 'data' => ''];
if ($this->app->request_method() != 'POST') {
$response['error'] = $this->app->language('error_message_not_post');
return $response;
}
// CSRF protection
$posted_token = $this->lib->filter->post('_token');
if (!$this->lib->csrf->validate('company_branch', $posted_token, false)) {
$response['error'] = $this->app->language('Security_token_mismatch');
return $response;
}
$magic = $this->addons->magic;
$data_id = 'tb_' . $this->lib->file->uname(); // unique row id
$response['data'] .= '<tr id="' . $data_id . '">';
$response['data'] .= '<td>' . $magic->get_select_option(
'product_category_id[' . $data_id . ']', [''],
['title' => $this->app->language('product_category'),
'list' => $this->addons->manage->get_simple_list('product_category', 'title', false)]
) . '</td>';
$response['data'] .= '<td>' . $magic->get_input_number(
'max_quantity[' . $data_id . ']', '',
['title' => $this->app->language('max_quantity')]
) . '</td>';
$response['success'] = '1';
$response['data'] .= '<td><div class="tc">';
$response['data'] .= '<a class="ei-delete save fastdelete" data-id="' . $data_id . '"></a>';
$response['data'] .= '</div></td>';
$response['data'] .= '</tr>';
return $response;
}

Behavior
- Bound to a table:
fastaddonly works inside a table built withmagic->get_table(). - Row source: Each new row is requested from the AJAX handler named in
$table['tb_get'](handler method =ax_<tb_get>), which returns the row<tr>as$response['data']. - Unique names: Inputs are namespaced with a unique
data_id(name="field[tb_xxxxx]") so multiple added rows do not collide on submit. - Delete icon: Generated rows usually include a
fastdeleteicon so the user can remove a row again.
Usage Notes
- Always set
tb_getwhenfastaddis enabled — it names the row-builder AJAX method. - Combine with Fast Delete per row, and Full Fast Edit to also load existing rows as editable.
- Validate CSRF in the AJAX handler (
$this->lib->csrf->validate(...)) as shown above.