29.01.2026 | Peter Gerken

Manipulate Form Data before Submit

formDataManipulation.js
// Modifies form data on submit.
form.addEventListener("formdata", (e) => {
  const formData = e.formData;
  geoLocationFieldNames.forEach((name) => {
    formData.delete(name);
  });
});

Issue:

  • A list of teasers should be filtered by the set "area of detail" (boundaries) on an embedded map and additionaly by exposed filters
  • A filtered version of the view should be shareable by link, ensuring no items are unwantedly filtered out

Solution:

  • use "formdata event" which is supported by recent versions of all major browsers
  • form data is being manipulated on submit
  • map viewport boundaries will be injected into the get request, but not included into exposed filters

Conclusion:

Using the provided solution will enable sharing of a set filter and ensures that whoever opens the link will see all teasers corresponding to the exposed filters. The map will be fully zoomed out so no teasers are 'accidentally' filtered out.

Weitere DevBits

23.10.2026 | Lothar Ferreira Neumann

How to fill empty form fields via a custom Drupal AJAX command

SetValueIfEmptyCommand.php
<?php

declare(strict_types=1);

namespace Drupal\my_module\Ajax;

use Drupal\Core\Ajax\CommandInterface;

/**
 * Ajax command: fill empty form elements with a predefined value.
 *
 * This command targets one or more form elements via a CSS selector and sets
 * their value only if the current value is empty (after trimming).
 *
 * The command also triggers `input` and `change` events so Drupal behaviors and
 * other listeners react as if the user entered the value manually.
 */
final class SetValueIfEmptyCommand implements CommandInterface {

  /**
   * The Ajax command name used by Drupal.AjaxCommands.
   */
  public const COMMAND = 'setValueIfEmpty';

  /**
   * Default selector used when none is provided.
   */
  public const DEFAULT_SELECTOR = '[data-my-fill-target]';

  /**
   * Creates a command instance.
   *
   * @param string $fillValue
   *   The value to set when the target element is empty.
   * @param string|null $targetSelector
   *   CSS selector for the target elements. If omitted, DEFAULT_SELECTOR is used.
   */
  public function __construct(
    protected string $fillValue,
    protected ?string $targetSelector = null,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function render(): array {
    return [
      'command' => self::COMMAND,
      'selector' => $this->targetSelector ?? self::DEFAULT_SELECTOR,
      'value' => $this->fillValue,
    ];
  }

}
media_fill_if_empty.js
/**
 * @file Field empty check.
 */
(function (Drupal) {
  'use strict';

  Drupal.AjaxCommands.prototype.setValueIfEmpty = function (ajax, response) {
    const targetSelector = response && response.selector ? response.selector : '';
    const fillValue = response && typeof response.value === 'string' ? response.value : '';

    if (!targetSelector) {
      return;
    }

    const elements = document.querySelectorAll(targetSelector);
    for (const element of elements) {
      let currentValue = '';

      if (typeof element.value === 'string') {
        currentValue = element.value.trim();
      }
      else if (element.isContentEditable) {
        currentValue = (element.textContent || '').trim();
      }

      if (currentValue !== '') {
        continue;
      }

      if (typeof element.value === 'string') {
        element.value = fillValue;
      }
      else if (element.isContentEditable) {
        element.textContent = fillValue;
      }
      else {
        continue;
      }

      element.dispatchEvent(new Event('input', { bubbles: true }));
      element.dispatchEvent(new Event('change', { bubbles: true }));
    }
  };

})(Drupal);
my_module.libraries.yml
set_value_if_empty:
  js:
    js/set_value_if_empty.js: {}
  dependencies:
    - core/drupal
    - core/drupal.ajax
MyResponse.php
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\my_module\Ajax\SetValueIfEmptyCommand;

$response = new AjaxResponse();

// Example: fill a media name field if it's empty.
$fill_value = 'foo-bar';

// Selector for a specific element in this use-case.
$target_selector = '[data-drupal-selector$="my_field"]';

$response->addAttachments([
  'library' => [
    'my_module/set_value_if_empty',
  ],
]);

$response->addCommand(new SetValueIfEmptyCommand($fill_value, $target_selector));

return $response;
26.02.2026 | Holger Weischenberg

Using CSS media queries and CSS variables in JavaScript

cssMediaQuery.js
// Retrieve all computed styles from the root HTML element (:root)
const rootStyles = getComputedStyle(document.documentElement);

// Get the value of the CSS variable --Breakpoint.
// Use a fallback (e.g., 768px) if the variable is not defined.
const breakpoint = rootStyles.getPropertyValue('--Breakpoint').trim() || '768px';

// Create a MediaQueryList based on the breakpoint value
const mediaQuery = window.matchMedia(`(min-width: ${breakpoint})`);

// Function that runs when the viewport is at or above the breakpoint
function handleDesktopLayout() {
    console.log("Viewport is at or above the breakpoint.");
}

// Function that runs when the viewport drops below the breakpoint
function handleMobileLayout() {
    console.log("Viewport is below the breakpoint.");
}

// Early return for the initial state:
// If the viewport does NOT meet the breakpoint requirement, run mobile logic and exit
if (!mediaQuery.matches) {
    handleMobileLayout();
    // No desktop logic needed at this point
} else {
    handleDesktopLayout();
}

// Listen for changes in viewport size relative to the breakpoint
mediaQuery.addEventListener('change', (event) => {
    if (event.matches) {
        // The viewport just became equal to or larger than the breakpoint
        handleDesktopLayout();
    } else {
        // The viewport just became smaller than the breakpoint
        handleMobileLayout();
    }
});
js