Ajax submit: Automatically save values when changed

Created on 11 September 2018, about 7 years ago
Updated 18 January 2023, over 2 years ago

Thanks for the great module. Is there a way to add an ajax call to the element? ie when you change a value it would then save the entity on change without the need for the save button?

πŸ’¬ Support request
Status

Needs work

Version

1.0

Component

Code

Created by

πŸ‡ΏπŸ‡¦South Africa hyltonmillar

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Patch at #41 worked for me but caused issues when the view results use groupping.

    Here is a modified version, it's most likely not the most performant solution but it can be a good starting point.

  • Status changed to Needs review over 2 years ago
  • πŸ‡ΊπŸ‡ΈUnited States loze Los Angeles

    This was still not working for me. I was getting Warning: Attempt to read property "_entity" on array in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 831 of /Users/####/web/modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)" in my logs.

    Here is a patch that got it working for me. I needed to change
    $form['output'][$key]['#rows'][$row]->_entity;
    to
    $form['output'][$key]['#rows'][$row]['#row']->_entity;

  • πŸ‡ΊπŸ‡ΈUnited States loze Los Angeles

    Ignore that last patch. This should work correctly.

  • πŸ‡ΈπŸ‡°Slovakia coaston

    Hi Loze,
    It does not change it for me - receiving following issue in logs after your patch #55

    Error: Cannot use object of type Drupal\views\ResultRow as array in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 854 of  modules/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)
    
    #0 [internal function]: Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity()
    #1  core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php(69): call_user_func_array()
    #2  core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php(109): Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse()
    #3 [internal function]: Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber->onException()
    #4  core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(142): call_user_func()
    #5  vendor/symfony/http-kernel/HttpKernel.php(219): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
    #6  vendor/symfony/http-kernel/HttpKernel.php(92): Symfony\Component\HttpKernel\HttpKernel->handleThrowable()
    #7  core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\Component\HttpKernel\HttpKernel->handle()
    #8  core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
    #9  core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
    #10  core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass()
    #11  core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle()
    #12  core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
    #13  vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
    #14  core/lib/Drupal/Core/DrupalKernel.php(709): Stack\StackedHttpKernel->handle()
    #15  index.php(19): Drupal\Core\DrupalKernel->handle()
    #16 {main}
    
  • πŸ‡ΈπŸ‡°Slovakia coaston

    I just tested #55 with boolean field and following error in logs :

    TypeError: Drupal\Core\Render\MainContent\AjaxRenderer::renderResponse(): Argument #1 ($main_content) must be of type array, null given, called in /core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php on line 89 in Drupal\Core\Render\MainContent\AjaxRenderer->renderResponse() (line 49 of /core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php)

  • πŸ‡¦πŸ‡ΉAustria jordik

    Since #41 neither of the later patches (#53 and #55) worked for me. Here is a re-roll of the #41 patch to the latest dev version.
    For me it works without any errors with most of the base fields. The patch also applies cleanly to the beta10.

  • πŸ‡¦πŸ‡ΉAustria jordik

    Had some weird behavior when the view is sorted/paginated/filtered with AJAX.
    The widget works only on the first page and after a fresh reload. The moment the view is reloaded through AJAX after e.g. column sort with AJAX the functionality breaks.
    Similar to πŸ’¬ Changes not saving properly after filtering/sorting table Active .

    Modified the AJAX attached to the form field by adding the original path as url and the rest of the parameters. Now it works fine for me.
    Adding patch.

  • πŸ‡ΈπŸ‡°Slovakia coaston

    Hi JordiK,

    After I have applied your patch #59 it seems it does not work as it should. It always "forget" to update some values.

  • πŸ‡¦πŸ‡ΉAustria jordik

    Did you get this behavior on a clean install? Anything in the logs - warnings, errors? What is your filed configuration?

  • πŸ‡ΉπŸ‡­Thailand AlfTheCat

    I tried the patch from #59 for a simple view of ECK entities, with a few regular fields and only one number field using a form field.
    After this patch, I can change values but they only seem to get saved in the form. The entities themselves don't get updated.

    Two warnings and one error are reported in the log:

    Warning: Undefined array key 231 in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 788 of /var/www/***/modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)

    Warning: Attempt to read property "_entity" on null in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 788 of /var/www/***/modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)

    TypeError: Drupal\Core\Render\MainContent\AjaxRenderer::renderResponse(): Argument #1 ($main_content) must be of type array, null given, called in /var/www/***/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php on line 89 in Drupal\Core\Render\MainContent\AjaxRenderer->renderResponse() (line 49 of /var/www/***/core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php)

    Hope this helps!

  • Status changed to Needs work over 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States jimmynash

    Here is a patch based on #58 and #59 that is working for me against beta10.

    It does have some other code for hiding descriptions and titles that is different than the original patches.

    #59 did take care of the problems with ajax submit after the view had been paginated or filtered. But there was some strange
    behavior around the entity field values not all saving as mentioned in #60.

    I added a bit to reload the entity before setting the field values and this seems to take care of that. I'm not sure that it's the most
    performant thing to do though. Take that with a grain of salt.

  • πŸ‡¦πŸ‡ΉAustria maxilein

    Does the patch respect node versioning? i.e. does it create a new version, when a field value gets changed?

  • πŸ‡ΉπŸ‡­Thailand AlfTheCat

    I tried #64 but no luck. Slightly different errors than I was getting before in the log:

    Error: Call to a member function getEntityTypeId() on null in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 852 of /var/www/***/modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)

    Warning: Trying to access array offset on value of type null in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 845 of /var/www/***/modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)

    Warning: Attempt to read property "_relationship_entities" on null in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 845 of /var/www/***/modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)

  • Status changed to Needs review about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States loze Los Angeles

    I created MR!9 which is the patch from #64 plus I tried to address the errors in #66.

    It appears to work as expected now in my initial testing.

    Here's a patch of the MR to use with composer.

  • Status changed to Needs work 10 months ago
  • πŸ‡ΈπŸ‡°Slovakia coaston

    Hello loze,

    I just tried your patch #68 but I am getting 1 Error and 2 Warnings, hence it does not work for me.

    Error: Call to a member function getEntityTypeId() on null in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 840 of //modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)
    
    #0 [internal function]: Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity()
    #1 //core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php(69): call_user_func_array()
    #2 //core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php(109): Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse()
    #3 [internal function]: Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber->onException()
    #4 //core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(142): call_user_func()
    #5 //vendor/symfony/http-kernel/HttpKernel.php(229): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
    #6 //vendor/symfony/http-kernel/HttpKernel.php(92): Symfony\Component\HttpKernel\HttpKernel->handleThrowable()
    #7 //core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\Component\HttpKernel\HttpKernel->handle()
    #8 //core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
    #9 //core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
    #10 //core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
    #11 //vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
    #12 //core/lib/Drupal/Core/DrupalKernel.php(718): Stack\StackedHttpKernel->handle()
    #13 //index.php(19): Drupal\Core\DrupalKernel->handle()
    #14 {main}
    

    where Line 840 is :

    // Reload the entity.
    $entity_type = $entity->getEntityTypeId();

    Warning: Undefined array key "#relationship" in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 832 of //modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)
    
    #0 //core/includes/bootstrap.inc(347): _drupal_error_handler_real()
    #1 //modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php(832): _drupal_error_handler()
    #2 [internal function]: Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity()
    #3 //core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php(69): call_user_func_array()
    #4 //core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php(109): Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse()
    #5 [internal function]: Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber->onException()
    #6 //core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(142): call_user_func()
    #7 //vendor/symfony/http-kernel/HttpKernel.php(229): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
    #8 //vendor/symfony/http-kernel/HttpKernel.php(92): Symfony\Component\HttpKernel\HttpKernel->handleThrowable()
    #9 //core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\Component\HttpKernel\HttpKernel->handle()
    #10 //core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
    #11 //core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
    #12 //core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
    #13 //vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
    #14 //core/lib/Drupal/Core/DrupalKernel.php(718): Stack\StackedHttpKernel->handle()
    #15 //index.php(19): Drupal\Core\DrupalKernel->handle()
    #16 {main}
    

    where line line 832 is :

    elseif (!empty($trigger['#ajax']['#relationship']) && $trigger['#relationship'] != 'none') {
    $entity = $results_row->_relationship_entities[$trigger['#ajax']['#relationship']];

    and

    Warning: Undefined array key "none" in Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity() (line 833 of //modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php)
    
    #0 //core/includes/bootstrap.inc(347): _drupal_error_handler_real()
    #1 //modules/contrib/views_entity_form_field/src/Plugin/views/field/EntityFormField.php(833): _drupal_error_handler()
    #2 [internal function]: Drupal\views_entity_form_field\Plugin\views\field\EntityFormField::updateEntity()
    #3 //core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php(69): call_user_func_array()
    #4 //core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php(109): Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse()
    #5 [internal function]: Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber->onException()
    #6 //core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(142): call_user_func()
    #7 //vendor/symfony/http-kernel/HttpKernel.php(229): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
    #8 //vendor/symfony/http-kernel/HttpKernel.php(92): Symfony\Component\HttpKernel\HttpKernel->handleThrowable()
    #9 //core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\Component\HttpKernel\HttpKernel->handle()
    #10 //core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
    #11 //core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
    #12 //core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
    #13 //vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
    #14 //core/lib/Drupal/Core/DrupalKernel.php(718): Stack\StackedHttpKernel->handle()
    #15 //index.php(19): Drupal\Core\DrupalKernel->handle()
    #16 {main}
    

    Where line 833 is :

    $entity = $results_row->_relationship_entities[$trigger['#ajax']['#relationship']];

  • I have a few problems with this patch.

    Most importantly, while the patch applies cleanly and produces no errors, my forms don't save. I've spent several hours trying to debug it, but it's just dead for me.

    Second, and more of a request: is it possible to engage autosave AND keep the submit button as a backup? As soon as I engage ajax on the view, the button disappears.

    Also, another request: is it possible to make this functionality optional, since it may not be appropriate for all form use cases on a site.

  • πŸ‡ΊπŸ‡ΈUnited States jive01

    patch #68 applied cleanly for me and work. I agree that the feature should be optional.

  • πŸ‡ΈπŸ‡°Slovakia coaston

    for me patch #68 did not work for Date field and entity reference so I asked AI for a help and this part of code has been changed from patch #68

    Original :

    +    // Get the views ResultRow.
    +    $results_row = $form['output'][0]['#view']->result[$row] ?? NULL;
    +
    +    // Find the entity we are updating from the ResultRow.
    +    if ($results_row instanceof ResultRow) {
    +      if (!empty($trigger['#relationship']) && $trigger['#relationship'] != 'none') {
    +        $entity = $results_row->_relationship_entities[$trigger['#relationship']];
    +      }
    +      elseif (!empty($trigger['#ajax']['#relationship']) && $trigger['#relationship'] != 'none') {
    +        $entity = $results_row->_relationship_entities[$trigger['#ajax']['#relationship']];
    +      }
    +      else {
    +        $entity = $results_row->_entity;
    +      }
    +
    +      // Reload the entity.
    +      $entity_type = $entity->getEntityTypeId();
    +      $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity->id());
    +    }
    +
    +    // If the entity has the field - write the value.
    +    if (isset($entity) && is_object($entity) && $entity->hasField($field)) {
    +      if (in_array($value_type, ['target_id', 'date'])) {
    +        $entity->set($field, [$value_type = $value]);
    +      }
    +      else {
    +        $entity->set($field, $value);
    +      }
    +      $entity->save();
    +      return ['#markup' => "Ok"];
    +    }
    

    and replaced with

        // Get the views ResultRow.
        $results_row = $form['output'][0]['#view']->result[$row] ?? NULL;
    
        // Find the entity we are updating from the ResultRow.
      if ($results_row instanceof ResultRow) {
    
      if (
    
        isset($trigger['#relationship']) &&
    
        !empty($trigger['#relationship']) &&
    
        $trigger['#relationship'] != 'none'
    
      ) {
    
        $entity = $results_row->_relationship_entities[$trigger['#relationship']];
    
      }
    
      elseif (
    
        isset($trigger['#ajax']['#relationship']) &&
    
        !empty($trigger['#ajax']['#relationship']) &&
    
        $trigger['#ajax']['#relationship'] != 'none'
    
      ) {
    
        $entity = $results_row->_relationship_entities[$trigger['#ajax']['#relationship']];
    
      }
    
      else {
    
        $entity = $results_row->_entity;
    
      }
    
          // Reload the entity.
    if ($entity !== NULL && is_object($entity)) {
    
      // Proceed as before
    
      $entity_type = $entity->getEntityTypeId();
    
      $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity->id());
        }
    } else {
    
      \Drupal::logger('views_entity_form_field')->error('No entity found for row @row and field @field', [
    
        '@row' => $row,
    
        '@field' => $field,
    
      ]);
    
      return ['#markup' => "Entity not found."];
    
    }
        // If the entity has the field - write the value.
    if (isset($entity) && is_object($entity) && $entity->hasField($field)) {
      $field_type = $entity->getFieldDefinition($field)->getType();
    
     
      if ($field_type === 'entity_reference') {
    
        // Entity reference (user, taxonomy, node, etc.)
    
        if (is_array($value) && isset($value['target_id'])) {
    
          $entity->set($field, [ ['target_id' => $value['target_id']] ]);
    
        }
    
        elseif (is_numeric($value)) {
    
          $entity->set($field, [ ['target_id' => $value] ]);
    
        }
    
        elseif (is_string($value) && preg_match('/\((\d+)\)$/', $value, $matches)) {
    
          $entity->set($field, [ ['target_id' => $matches[1]] ]);
    
        }
    
        else {
    
          \Drupal::logger('views_entity_form_field')->error('Could not extract target_id from value: @value', ['@value' => print_r($value, TRUE)]);
    
        }
    
      }
    elseif ($field_type === 'datetime' || $field_type === 'timestamp') {
      if (is_string($value)) {
        $entity->set($field, ['value' => $value]);
      }
      elseif (is_array($value) && isset($value['date'])) {
        $date = $value['date'];
        $time = isset($value['time']) ? $value['time'] : '00:00:00';
        $datetime = $date . 'T' . $time;
        $entity->set($field, ['value' => $datetime]);
      }
      elseif (is_array($value) && isset($value['value'])) {
        $entity->set($field, $value);
      }
      else {
        \Drupal::logger('views_entity_form_field')->error('Unexpected date value: @value', ['@value' => print_r($value, TRUE)]);
      }
    }
      else {
        $entity->set($field, $value);
      }
      $entity->save();
      return ['#markup' => "Ok"];
    }
    

    attached you can find the file. If anyone can check and create a patch i would be grateful.
    EntityFormField.php_.txt β†’

    This is really the first time it works for me as expected for all tested cases like "standard text, boolean, entity reference and Date field". I have tested it several times with a multiple nodes and all works finally as expected.

  • πŸ‡ΊπŸ‡ΈUnited States jive01

    Can someone create a patch using @coastons text file?

Production build 0.71.5 2024