I am new to drupal and currently using Drupal 8.1.8, so forgive me if the question is not in the correct format.
I have a database table with vehicles and their details which is presented to the user as sortable Tableselect table in a “vehicle update” form. When the user selects (select/update) a row in the table an Ajax call (ajaxUpdateCall) updates the relevant fields to allow the user to edit and re-submit the values.
The user can reduce the number of results in the table by entering a search phrase (search/filter) that is then used in a LIKE query, after pressing the “Search” or “Reset Search” buttons a Ajax (search_ajax_callback) call is run to update the table.
If the table is not or has not been filtered (search/filter), then the (select/update) and sorting table by the HEADER links works fine (header/sort).
The problem occurs when the table is filtered and updated with Ajax(search/filter), if I now try to sort the table (header/sort) I get an error, but (select/update) still works. The error is presented on a blank and is as follows.
[{"command":"add_css","data":"\u003Clink rel=\u0022stylesheet\u0022 href=\u0022\/sites\/fleetmanagement.dd\/files\/css\/css_eWmbbi3frMJPauCYHygIVEjcDmNqivacE1SJjDW017s.css?od92zv\u0022 media=\u0022all\u0022 \/\u003E\n\u003Clink rel=\u0022stylesheet\u0022 href=\u0022\/core\/themes\/bartik\/css\/components\/messages.css?od92zv\u0022 media=\u0022all\u0022 \/\u003E\n"},{"command":"insert","method":"replaceWith","selector":null,"data":"\n \n \u003Cdiv class=\u0022messages__wrapper layout-container\u0022\u003E\n \u003Cdiv role=\u0022contentinfo\u0022 aria-label=\u0022Error message\u0022 class=\u0022messages messages--error\u0022\u003E\n \u003Cdiv role=\u0022alert\u0022\u003E\n \u003Ch2 class=\u0022visually-hidden\u0022\u003EError message\u003C\/h2\u003E\n An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (128 MB) that this server supports.\n \u003C\/div\u003E\n \u003C\/div\u003E\n \n \u003C\/div\u003E\n ","settings":null}]
This error seems to be related to https://www.drupal.org/node/2686005 where the table header links are “broken” after ajax. One of the suggestions was to diable the Devel Web Profiler, but this did not solve my problem.
Before (search/filter) the header links are http:// fleetmanagement.dd:8083/manage_vehicle/update?sort=desc&order=Reg%20Number and the $_GET variable contains the following:
$_GET = array(
sort => "asc"
order => "Reg Number");
After (search/filter) the header links are http:// fleetmanagement.dd:8083/manage_vehicle/update?ajax_form=1&_wrapper_format=drupal_ajax&sort=asc&order=Reg%20Number and the $_GET variable contains:
$_GET = array(
ajax_form => "1"
_wrapper_format => "drupal_ajax"
sort => "asc"
order => "Reg Number");
You can see that after search_ajax_callback, “ajax_form=1&_wrapper_format=drupal_ajax&” has been added to the header links and I don’t know how to edit it after the fact since I think this is the problem.
I attempted to edit $_GET to influence the creation of the header links, but this was unsuccessful.
My question is, how do you I fix my code to allow for (header/sort) after (search/filter) Ajax has been run? Or is this a core problem and I should just disable (header/sort) altogether?
Here is most of my code, starting with the form.
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\manage_vehicle\manage_vehicle_storage;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\AjaxResponse;
class vehicle_updateform extends FormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$database = Database::getConnection();
$query = $database->select('a_vehicle', 'rv')
->extend('Drupal\Core\Database\Query\TableSortExtender')
->extend('Drupal\Core\Database\Query\PagerSelectExtender')//->limit(1)
->fields('rv', ['vehicle_id', 'registration_number', 'make', 'model', 'vin_number', 'model_year', 'start_year', 'mileage', 'capacity', 'status', 'next_service_date', 'deleted']);
$query->condition('rv.deleted','no', '=');
// Attempt to change the $_GET values so that when table HEADER links are generated
// after AJAX Filter table call, the link does not contain "ajax_form=1&_wrapper_format=drupal_ajax&"
// Did not work.
if (!empty($_GET['sort'])) {
$sort = $_GET['sort'];
$order = $_GET['order'];
unset($_GET);
$_GET['sort'] = $sort;
$_GET['order'] = $order;
}
$UserInput = $form_state->getUserInput();
if($UserInput['_triggering_element_value'] == 'Search') {
$search_phrase = $UserInput['search']['search_phrase'];
}else if($UserInput['_triggering_element_value'] == 'Reset Search'){ // triggering_element is the Reset Search BUTTON -> SHOW ALL
$UserInput['search']['search_phrase'] = "";
$form_state->setUserInput($UserInput);
$search_phrase = "";
}else{
$search_phrase = $UserInput['search']['search_phrase'];
}
$DB_OR = $query->orConditionGroup()
->condition('registration_number', '%' . $database->escapeLike($search_phrase) . '%', 'LIKE')
->condition('status', '%' . $database->escapeLike($search_phrase) . '%', 'LIKE')
->condition('make', '%' . $database->escapeLike($search_phrase) . '%', 'LIKE')
->condition('model', '%' . $database->escapeLike($search_phrase) . '%', 'LIKE');
$query->condition($DB_OR);
$header = array(
'vehicle_id' => array('data' => t('Vid'), 'field' => 'rv.vehicle_id'),
'registration_number' => array('data' => t('Reg Number'), 'field' => 'rv.registration_number'),
'make' => array('data' => t('Make'), 'field' => 'rv.make'),
'vin_number' => t('Vin Number'),
'capacity' => array('data' => t('Capacity'), 'field' => 'rv.capacity'),
'status' => array('data' => t('Status'), 'field' => 'rv.status',)// 'sort' => 'desc')
);
$result = $query
->orderByHeader($header)
->execute()
->fetchAll();
$options = array();
// This ensures that the pager uses the correct options after ajaxUpdateCall
if (empty($form_state->getCompleteForm())) {
// Populate Table
foreach ($result as $row) {
$options[$row->vehicle_id] = array(
'vehicle_id' => $row->vehicle_id,
'registration_number' => $row->registration_number,
'make' => $row->make,
'vin_number' => $row->vin_number,
'capacity' => $row->capacity,
'status' => $row->status,
);
$keyed_entries[$row->vehicle_id] = $row;
}
}else{
$options = $form_state->getCompleteForm();
$options = $options['filter']['table']['results']['#options'];
}
$selected = $UserInput['filter']['table']['results']; // Vehicle_ID
if (!empty($selected)){
$selected = array('vehicle_id' => $selected);
$lastResult = manage_vehicle_storage::load($selected); // expect only one value to be returned
$default_entry = $lastResult[0];
}
$form_state->setCached(FALSE);
$form['#tree'] = TRUE;
$form['actions'] = [
'#type' => 'actions',
];
$form['search'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Search'),
);
$form['search']['search_phrase'] = array(
'#type' => 'textfield',
'#title' => $this->t("Search for a vehicle"),
'#size' => 8,
'#default_value' => "",
'#prefix' => '<div id="search_phrase-div">',
'#suffix' => '</div>',
);
$form['search']['actions']['search_button'] = array(
'#type' => 'button',
'#value' => t('Search'),
'#ajax' => array(
'callback' => '::search_ajax_callback',
'wrapper' => 'table-div',
'method' => 'replace',
)
);
$form['search']['actions']['clear_button'] = array(
'#type' => 'button',
'#value' => t('Reset Search'),
'#ajax' => array(
'callback' => '::search_ajax_callback',
'wrapper' => 'table-div',
'method' => 'replace',
)
);
$form['filter'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Available Vehicles'),
);
$form['filter']['table']['results'] = array(
'#theme' => 'table',
//'#theme' => 'pager',
'#type' => 'tableselect',
'#header' => $header,
'#options' => $options,
'#multiple' => FALSE, // Radios
'#prefix' => '<div id="table-div">',
'#suffix' => '</div>',
'#empty' => t('No content available.'),
'#submit' => array(':updateCallback:'),
'#ajax' => array(
'callback' => '::ajaxUpdateCall',
),
);
$form['filter']['table']['pager'] = [
'#type' => 'pager',
'#result' => $result,
];
$form['edit'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Selected Vehicle'),
'#prefix' => '<div id="edit-box-div">',
'#suffix' => '</div>',
);
$form['edit']['edit_registration_number'] = array(
'#type' => 'textfield',
'#title' => t('registration_number'),
'#size' => 9,
'#maxlength' => 8,
'#attributes' => array(
'placeholder' => 'abc123EC',
),
'#default_value' => isset($default_entry) ? $default_entry->registration_number : "",
);
/* The rest of the text/number/date fields that follow
* are the same as edit_registration_number so I left them out
* i.e. edit_make, edit_model, edit_vin_number, edit_mileage.....
*/
$form['actions']['submit']= array(
'#type' => 'submit',
'#value' => $this->t('Submit Update'),
'#button_type' => 'primary',
);
return $form;
}
Following is the Ajax callback that updates the form fields after a row in the table has been selected.
/**
* AJAX callback handler for the vehicle_id select.
* When a row in the table is selected, this function
* then updates the related text fields so that they can be edited.
*/
public function ajaxUpdateCall(array $form, FormStateInterface &$form_state){ //
//$selected = $_POST['filter']['table']['results']; // Row ID
$UserInput = $form_state->getUserInput();
$selected = $UserInput['filter']['table']['results']; // Row ID
if (!empty($selected)){
$rows = array('vehicle_id' => $selected);
$lastResult = manage_vehicle_storage::load($rows);
$row = $lastResult[0];
$form['edit']['edit_registration_number']['#value'] = $row->registration_number;
$form['edit']['edit_make']['#value'] = $row->make;
$form['edit']['edit_model']['#value'] = $row->model;
$form['edit']['edit_vin_number']['#value'] = $row->vin_number;
$form['edit']['edit_mileage']['#value'] = $row->mileage;
$form['edit']['edit_capacity']['#value'] = $row->capacity;
$form['edit']['edit_status']['#value'] = $row->status;
$form['edit']['edit_model_year']['#value'] = $row->model_year;
$form['edit']['edit_start_year']['#value'] = $row->start_year;
$form['edit']['edit_next_service_date']['#value'] = $row->next_service_date;
}
$response = new AjaxResponse();
$response->addCommand(new ReplaceCommand('#edit-box-div', ($form['edit'])));
return $response;
}
The last code is for the Ajax callback that updates the table based on a search phrase to limit the dispayed table options. Here is one of the places I tried to edit the $_GET variable.
/**
* AJAX callback handler for Search phrase filtering.
* When search phrase is entered and Search button clicked,
* the table updates showing only relavant values.
*/
public function search_ajax_callback(array $form, FormStateInterface &$form_state){
$form = $form_state->getCompleteForm();
$response = new AjaxResponse();
$response->addCommand(new ReplaceCommand('#table-div', ($form['filter']['table']['results'])));
$UserInput = $form_state->getUserInput();
$trigger = $UserInput['_triggering_element_value'];// == 'Reset Search'
// If Reset button was clicked, then display all rows from database
// and clear search phrase textfield.
if($trigger == 'Reset Search'){
$form['search']['search_phrase']['#value'] = "";
$response->addCommand(new ReplaceCommand('#search_phrase-div', ($form['search']['search_phrase'])));
}
// Attempt to change the $_GET values so that when table HEADER links are generated
// after AJAX Filter table call, the link does not contain "ajax_form=1&_wrapper_format=drupal_ajax&"
// Did not work.
if (!empty($_GET['sort'])) {
$sort = $_GET['sort'];
$order = $_GET['order'];
unset($_GET);
$_GET['sort'] = $sort;
$_GET['order'] = $order;
}
return $response;
}
Thanks in advance for your help!!