0

I have a custom field formatter that attaches a library that includes a javascript file. It uses drupalSettings to pass some values to the script.

The first time the field formatter appears on a page, it works as expected. However, subsequent appearances of the formatter behave as if they have no script attached.

A simplified example:

(function ($, Drupal, drupalSettings) {
  $(document).ready(function () {
    var selector = drupalSettings.gallery.id + ' .foo';
    alert(selector);
  });
})(jQuery, Drupal, drupalSettings);

If the field formatter appears three times on a page, I would expect to get three alerts with three (slightly) different strings. Instead, I only get one, with the ID I expect for the first string.

It seems like the easy way to deal with this is to use inline scripts, but I know that's strongly discouraged. Is there a right way to do this?

Edit: updating the code to use drupalBehaviors, I now have:

(function ($) {
  Drupal.behaviors.galleryBehavior = {
    attach: function (context, settings) {
      $.each(settings.gallery.id, function(index, item) {
        alert(item);
      });
    }
  };
})(jQuery);

I'm now getting multiple alerts instead of one, but they still all contain the same string. Dumping the contents of settings.gallery shows that only one ID has been inserted into the array, which suggests to me that subsequent instances of the formatter aren't adding attachments? The PHP code looks like so:

$id = $items[0]->getEntity()->uuid() . '__' . $this->fieldDefinition->getName();
ksm($id); // just to make sure I'm actually generating the expected number of unique IDs
$elements['#attached']['drupalSettings']['gallery']['id'][] = $id;

This appears to be the right way to populate an attached drupalSettings array, based on one somewhat similar question I was able to find this morning, but clearly I'm missing something.

4
  • 4
    Adding a library multiple times doesn't run the library multiple times. You need to iterate over the multiple field formatter appearances. And use Drupal behaviors instead of document ready.
    – 4k4
    Oct 20 '20 at 22:21
  • I appreciate the response. I think it's helped me make progress, but there's something I'm just not grasping here. I've updated based on this info.
    – WRD
    Oct 21 '20 at 16:21
  • [] always adds 0, the arrays are not connected at this point, they are merged later. You have to generate a unique array key with the entity data. Since $id seems to be a unique ID already, why are you adding it as data and not use it as array key?
    – 4k4
    Oct 21 '20 at 16:28
  • Because this did not occur to me at all. But it was exactly the piece of information I needed, thank you. Everything is working now.
    – WRD
    Oct 21 '20 at 17:28
0

Thanks to responses from 4k4, the following works:

$id = $items[0]->getEntity()->uuid() . '__' . $this->fieldDefinition->getName();
$settings = [
  'id' => '#' . $id,
  'setting1' => 'foo',
  'setting2' => 'bar',
];
$elements['#attached']['drupalSettings']['gallery'][$id] = $settings;

And then in the javascript:

(function ($) {
  Drupal.behaviors.galleryBehavior = {
    attach: function (context, settings) {
      $.each(settings.gallery, function(key, item) {
        var main_selector = item.id + ' .gallery-main';
        alert(main_selector);
      });
    }
  };
})(jQuery);

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.