4

I'm implementing the javascript library Annotorious which allow to add annotations on an image. My goal is to be able to link content with part of the image select with Annotorious. When we select a zone, Annotorious open a form we can personalize to add information we want link with the zone. In my case, I added a fieldtext but I want it uses the autocomplete but I don't know how to activate this behavior.

Regarding the code in core/lib/Drupal/Core/Render/Element/FormElement.php, the form element add the class 'form-autocomplete' and the attributes 'data-autocomplete-path' equals to the url of an autocomplete function on his input and inject the library core/drupal.autocomplete. Regarding this, I tried to reproduce the same behavior. But I guess something is missing because my field doesn't query my endpoint when I typed in it but I don't know why. I was also thinking this maybe doesn't work because it's add by javascript after the loading of the page but in this case, I don't know how to solve this problem.

Here my code:

My widget field:

class ImagePinWidget extends ImageWidget {

  public static function process($element, FormStateInterface $form_state, $form) {
    $element = parent::process($element, $form_state, $form);

    $element['preview']['#attributes'] = array('id' => array('my-image'));

    $element['#attached']['library'][] = 'my_module/image-pin';
    $element['#theme'] = 'image_pin_widget';

    return $element;
  }

}

My my_module.libraries.yml

recogito-annotorious:
  version: 1.x
  css:
    component:
      /libraries/annotorious/annotorious.min.css: { minified: true }
  js:
    /libraries/annotorious/annotorious.min.js: { minified: true }

annotorious-toolbar:
  version: 1.x
  js:
    https://cdn.jsdelivr.net/npm/@recogito/annotorious-toolbar@latest/dist/annotorious-toolbar.min.js: { type: external, minified: true }

image-pin:
  version: 1.0.0
  css:
    component:
      css/image-pin.css: {}
  js:
    js/image_pin.js: {}
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupalSettings
    - my_module/recogito-annotorious
    - core/drupal.autocomplete
    - my_module/annotorious-toolbar

image_pin.js:

(function ($, Drupal, drupalSettings, Annotorious) {

  'use strict';

  Drupal.behaviors.redacto_form_image_pin = {
    attach: function (context) {
      var config = {
        image:'my-image',
        widgets: [
          Drupal.behaviors.my_module_image_pin.nodeSelectorWidget,
        ],
      };

      var anno = Annotorious.init(config);

      Annotorious.Toolbar(anno, document.getElementById('toolbar'));
    },

    /**
     * Dynamic behavior when the status changes.
     *
     * @param $status
     */
    nodeSelectorWidget: function (args) {

      // Adding the autocomplete field
      var createField = function() {
        var input = document.createElement('input');

        input.classList.add('form-autocomplete');
        input.setAttribute('data-autocomplete-path', '/fr/autocomplete/custom');

        return input;
      }

      var container = document.createElement('div');
      container.className = 'nodeselector-widget';

      container.appendChild(createField());

      return container;

    }

  };

})(jQuery, Drupal, drupalSettings, Annotorious);

I precise the path /fr/autocomplete/insects return correctly a json list of content and autocomplete create in a usual form works correctly with it. Example of autocomplete I do in an usual drupal form with this custom autocomplete:

$element['test_autocomplete'] = [
     '#type' => 'textfield',
     '#title' => t('Autocomplete Articles'),
     '#autocomplete_route_name' => 'my_module.custom_autocomplete',
   ];
4
  • You could try forcing the autocomplete behavior to re-attach after adding the elements to the DOM, e.g. Drupal.behaviors.autocomplete.attach(container); – Clive May 6 at 18:46
  • Thanks for the suggestion. I try to add it at the end of the Annotorious Wdget and in the event function when we create annotation but that doesn't fix the problem. I will continue to explore – Claire D May 6 at 19:03
  • I was thinking it would be added straight after container.appendChild(createField());. It might not work because the element may need to be attached to the DOM, which it seems wouldn't happen until after that method returns, but since it's dynamic it's the only place in your current code where it seems to fit. This might turn into more of a question of how to hook into the post-creation of the widget form in Annatorious itself, if you look at the code for Drupal.behaviors.autocomplete.attach invoking that method should work if it's done at the right time – Clive May 6 at 19:09
  • Thanks Clive, it was exactly that ! I was not able to see the list of result on my first test because the z-index of the modal is too high and hide them. – Claire D May 7 at 1:14
4

Thanks to Clive for his help ! To active the autocomplete, I should re-attach the autocomplete behavior after added my new element.

nodeSelectorWidget: function (args) {

      // Adding the autocomplete field
      var createField = function() {
        var input = document.createElement('input');

        input.classList.add('form-autocomplete');
        input.setAttribute('data-autocomplete-path', '/fr/autocomplete/custom');

        return input;
      }

      var container = document.createElement('div');
      container.className = 'nodeselector-widget';

      container.appendChild(createField());

      // Re-attach autocomplete behavior to active the autocomplete on the added input
      Drupal.behaviors.autocomplete.attach(container);


      return container;

    }

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.