0

Have an ajax callback function within which the data gets generated dynamically based on the custom input from form fields.

//ajax callback submit
$form['action'] = [
'#type' => 'button',
'#value' => $this->t('Submit'),
'#ajax' => [
'callback' => '::getData',
'wrapper' => 'table-data',
'method' => 'replaceWith',
'effect' => 'fade', 
];

//ajax callback function
public function getData($form, FormStateInterface &$form_state) {
$table_data = $this->getTableData($form_state);  //getting the data dynamically
$form['section']['#attached']['drupalSettings']['table_data'] = $table_data; //assigning the data to drupalSettings
dpm($table_data); //to check if the assignment is updated
    return array($form['table_markup'],$form['section']);   //$form['table_markup'] is a markup used to display data in the table
   }

//javascript code
(function ($, Drupal, drupalSettings) { 
    Drupal.behaviors.display_data = {
    attach: function (context, settings) {
        alert(drupalSettings.table_data); 
        var table_data  = drupalSettings.table_data;  //inconsistency noticed in this assignment
    }
};

})(jQuery, Drupal, drupalSettings); 

Now whenever I click on the submit button, the $table_data gets updated and assigned to the drupalSettings dynamically, but passing its value to the javascript seems to be behaving inconsistent, meaning the drupalSettings.table_data within javascript does not get updated but shows the previous set values.

For it to work correctly I have to reload the page, change the form inputs and submit.

I've realized it may have to do with the cache and tried to avoid it by setting the routing.yml file as below:

  options:
    no_cache: 'TRUE'

Not sure how to use cache tags here, as I do not have any tags defined Tried to rebuild the form within the callback which didn't work either. The form input fields does not get cleared even after reloading the page and I'm confused why this happens even after the no_cache is set to true?

Tried using 'delete' on javascript end, which didn't work either

Is there a suitable approach to make sure that the variable from drupal php, received on the javascript is always an updated one?

  • Not sure if you can alter drupalSettings that way, keep in mind that though Drupal rebuilds the whole page during a typical AJAX callback and runs all behaviors I don't think it re-attach them. Why dont you use form or inputs data atrributes to pass relevant data between callbacks? – d70rr3s Jul 5 '18 at 21:25
  • It just seems that the code within the Drupal.Behaviors runs twice. alert(drupalSettings.table_data); shows up twice after clicking on ajax callback submit. So, before doing this: var table_data = drupalSettings.table_data; I cleared the drupalSettings as drupalSettings.table_data=[]; and that seems to do the trick. To answer your question, there's a high possibility that in future I may have to show large number of records in the table, So I'm inclined towards using this architecture rather than formAPI as I've noticed there are problems with pagination within in the ajax response area – Bharat Jul 6 '18 at 1:13
  • Yes, behaviors are run on every AJAX call is designed that way. If you don't want your behavior to run every time you need to use jQuery.once plugin during the behavior attach function like this, dont get fooled because it's a Drupal 7 example still used in Drupal 8. I think this may be the solution or at least point you towards. – d70rr3s Jul 6 '18 at 5:21
2

In this case instead of returning HTML (aka the form render array) your AJAX callback method needs to return an AjaxResponse object (see API docs). The AjaxResponse object should contain at least 2 commands, one for updating your HTML (the processed form) and other to update the drupalSettings object. A possible response could be like

public static function ajaxCallback(array $form, FormStateInterface $form_state) {
  // Assuming the $form variable is either the updated render array or rendered output.
  $response = new AjaxResponse();
  $response->addCommand(new ReplaceCommand('#wrapper-id', $form));
  // The $data variable is an assoc array with he same keys you passed during the build under #attached key.
  // If you don't want to merge the settings but instead replace it, remove the second argument.
  $response->addCommand(new SettingsCommand ($data, TRUE));
  return $response;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.