Could I get some guidance on applying this to an entity reference field? I've built the form alter, though I'm unclear on how to apply the ER to the options list:

'#options' => array('' => 'Pick something or enter your own', 1 => 'ABC', 2 => 'DEF', 3 => 'GHI'),

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

eswiderski created an issue. See original summary.

kevinquillen’s picture

I am currently investigating this.

Form fields on content/entity forms are widgets, and not just vanilla Elements like you can use with custom forms in FormAPI.

I have a working version on my local, and will update dev shortly to provide widget support with settings.

kevinquillen’s picture

Assigned: Unassigned » kevinquillen
kevinquillen’s picture

So, while I sort of got it working on a List (text) widget, and it could work for entity reference, widgets are different in a few key ways.

One, in order to replicate the autocomplete functionality, I would need to reimplement the widget code - which looks like a lot of work to implement all of what selectize needs to replicate what Drupal is doing.

However... in the interim, I was able to get List (text) widgets working, which is in the latest code.

dnotes’s picture

quiron’s picture

Hi, I had the same issue, I need support for the entity_reference autocomplete widget.

I developed a patch that works for me, basically:

  1. Adds a new widget type for field_types entity_reference, keeping all the configurable options
  2. Adds a new setting called 'field_type' in the element['#settings'] and in the selectize element is uses to manage the different settings
  3. Adds a new JS function to set up the renders and autocomplete AJAX calls to Drupal

Hope it's useful for someone, also if works and passes the tests the module can have a new release including this new feature.

BlacKICEUA’s picture

Status: Active » Needs review
FileSize
9.59 KB

Fixed undefined CARDINALITY in the SelectizeEntityReferenceWidget.
Fixed per field_type configurations in the Selectize element class.

BlacKICEUA’s picture

Status: Needs review » Active
quiron’s picture

Hi,

whats missing here to move it forward?

thanks.

kevinquillen’s picture

Great patch here. I am trying to test it out with a term reference field. I set the type to "Autocomplete Tags style (selectize.js)", but I am getting this error in the console:

selectize.drupal.js?v=8.4.4:60 Uncaught TypeError: $.ajax(...).error is not a function

kevinquillen’s picture

Ok, its because jQuery has deprecated those methods. Patch needs to be updated to be:

$.ajax({
          url: url,
          data: {
            q: query,
          }
        })
          .fail(function () {
            callback();
          })
          .done(function (response) {
            return callback(response);
          });
sun’s picture

Indeed, we're still testing this patch, too. We'll follow up shortly with an improved version of the patch.

Also adding support for basic entit reference select drop-downs with a fixed / predefined list of options (the most basic use-case of e.g. categories).

kevinquillen’s picture

I am also having some UI issues with typing/autocomplete, and I can't seem to get the drop down select to show up if you click into the field (showing some limited list of options).

Also seeing the remove button show up on page load, pic attached.

a

The returned list of option matches also seem to be unsorted (this can be seen with one or two letters). I can't recall if the returned options were supposed to be alpha sorted or not if the match was in the middle of a word.

kevinquillen’s picture

The above screenshot also prevents a placeholder from being attached to the element.

edit: Also just noticed that only 10 options are returned because the autocomplete is using TermSelection. Looks like the only way to override this is implementing our own per https://drupal.stackexchange.com/a/220521/57 and upping the limit to 100, or allow the user to configure it.

kevinquillen’s picture

Forgive my JS here, just trying a few things.

When the element first loads, it adds an empty item div - I am not entirely sure why. I was able to undo this by adding an onInitialize event:

config.onInitialize = function() {
  this.clear();
};

Outside of that, it looks like there are two CSS issues at play. First, if you use the Field Group module and the element is within a vertical tab, you need to override this in your own style:

.vertical-tab { overflow: visible; }

Otherwise, the drop down list is hidden and cut off by the border of the tab area.

Second, the Selectize input has some style issue where clicking around inside of the input doesn't seem to have much of an effect except near the end of the element input area. For example, clicking near a tag doesn't trigger the drop down list, but clicking way over on the far right end of the element will trigger it (even then it is 50/50). I overcame this with:

.selectize-input { overflow: visible; }

With that, clicking anywhere in the input triggers the drop down list. This did not seem to break the widget in any way.

Will work on updating patches.

kevinquillen’s picture

Just realized I forgot to post a picture of the vertical tab CSS bug.

vertical tab bug

blasvicco’s picture

kevinquillen’s picture

Some more bugs. It looks like you can save the field with referenced values, but when you come back to the entity form, the default values are not loaded into the field.

Also, saving values fails if the reference entity string contains a comma in its label, due to this:

  /**
   * {@inheritdoc}
   */
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
    return explode(',', $input["target_id"]);
  }

This turns a term like "Foo, Bar, Baz (2)" into an array of:

  • Foo
  • Bar
  • Baz (2)

Upon saving, this will cause Drupal to print "an illegal option has been detected" meaning this value is useless to it.

kevinquillen’s picture

This code appears twice in Selectize.php:

      // Per field_type configurations.
      if (isset($element['#settings']['field_type']) && $element['#settings']['field_type'] === 'entity_reference') {
        unset($complete_form['options']);
        $element['#theme'] = 'entity_autocomplete';
        $complete_form['#attached']['drupalSettings']['selectize'][$element['#id'] . '-target-id'] = json_encode($element['#settings']);
      }
      else {
        // If no file type is set we assume 'list_string'.
        $complete_form['#attached']['drupalSettings']['selectize'][$element['#id']] = json_encode($element['#settings']);
      }

      // Per field_type configurations.
      if (isset($element['#settings']['field_type']) && $element['#settings']['field_type'] === 'entity_reference') {
        unset($complete_form['options']);
        $element['#theme'] = 'entity_autocomplete';
        $complete_form['#attached']['drupalSettings']['selectize'][$element['#id'] . '-target-id'] = json_encode($element['#settings']);
      }
      else {
        // If no file type is set we assume 'list_string'.
        $complete_form['#attached']['drupalSettings']['selectize'][$element['#id']] = json_encode($element['#settings']);
      }
kevinquillen’s picture

There is a minor typo in the code comment, 'file' should be 'field'

kevinquillen’s picture

Not sure if its just an end of the day thing or not, but I am running in circles in the code.

The new field widget type SelectizeEntityReferenceWidget extends EntityReferenceAutocompleteTagsWidget however the form element inside of the formElement method is having its type set to selectize, which is triggering a pre/post rendering callback as well as valueCallback in the Selectize class. This almost seems like a conflict, because the core entity reference form element and field widget classes work fine and set default values without an issue, however ours does not because the current form element is intended for just select lists.

We need to have a better separation of concerns and intent so its easier to debug, instead of forks all around the code for 'entity_reference' vs 'list_string' as the original Selectize FormElement class only accounted for simple drop down lists, not autocomplete fields. I checked both the Chosen and Select2 Widget modules to see how they handle it, and neither one seems to tackle applying themselves to EntityReferenceAutocomplete widgets, only OptionSelectList and Select.

The way values and default values are parsed and set for autocomplete widgets vs basic select/option widgets are different and I don't think it can co-exist in the same class.

kevinquillen’s picture

Also it will throw a fatal error if you reference an entity with comma or quotes in the name. I think because our Selectize form elements valueCallback is too simplistic for this type of field.

See: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...

kevinquillen’s picture

Last patch will need a re-roll, it won't apply cleanly anymore after the last two commits.

kevinquillen’s picture

I am testing with adding "entity_reference" as a supported type to the original Selectize form element. It looks like it works well - except for autocomplete based widgets, for the reasons outlined above.

I don't have those same issues with an entity reference with using "Selectize" as the form widget. The dev branch now has the change that allows the original widget to work with Entity Reference.

I think if you want to move forward with Selectize applying to an entity reference field but using Autocomplete, it should be split out to a new widget and a new form element (perhaps extending EntityAutocomplete?) because theres a little more work to do there to make that work. There is also the core issue of autocomplete fields not liking comma or quotes in a term name, which is what I ran into with the above patch but wasn't sure how to fix it unless the values are stored as objects instead of a string.

Of course the obvious caveat is that someone should not enable "Selectize" for a field that could have tons of results... which is where you'd want the Selectized autocomplete... and I think this patch is almost there, but needs work.

kevinquillen’s picture

Status: Active » Needs work
BlacKICEUA’s picture

Status: Needs work » Needs review
FileSize
19.97 KB

So, I spent some time for Entity Reference functionality for the Selectize module. All my work based on previous solutions from this issue.
I think, I found the working solution and also added some extra features for widgets.
Tested:
- entity_reference tag widget;
- entity_reference simple select widget;
- handled possibility for creation entities via widget (like: Create referenced entities if they don't already exist)
Added sort setting for a widget (field/direction).
Fixed summary for a widget.
Added new form element ('selectize_entity_autocomplete') based on 'selectize' form element.
Changed composer.json (added library requirment and repository).

BlacKICEUA’s picture

FileSize
25.96 KB

Another implementation for the EntityReferenceAutocomplete:
- Form Element extends EntityAutocomplete;
- Form Widget extends EntityReferenceAutocompleteTagsWidget;
- Added additional options for the AutoCreate (Create On Blur, Create filter(REGEX))

kevinquillen’s picture

I also noticed that autocomplete matcher methods exist and can be overrridden, I also noticed that Selectize has an option to change the default delimiter from a comma to whatever, like triple pipes. Perhaps that would solve the issue of referenced items having commas or quotes in their label.

I will give this patch a look.

kevinquillen’s picture

This patch is looking pretty good. Although there is one thing I can't narrow down.

In this screenshot, the values and labels are messed up. I think it is because the default value has a quote added (because this term has commas in the name and is escaped when labels are created).

e

This causes selectize to parse it out into 3 different labels when it should be one item.

BlacKICEUA’s picture

FileSize
39.1 KB

Extended Widgets functionality - added possibility to specify delimiter. Used ";" - as default delimiter symbol for Autocomplete.
Some changes for the "Select" element:
- FormElement Selectize extends Select;
- FieldWidget SelectizeWidget extends OptionsSelectWidget;

fabian.marz’s picture

Enhanced patch 30 with following:

- parse the config only if it's not already an object, thus the config can be extended with callback functions from other modules
- added a config to hide the term id from the values to prevent value duplicates when creating them on the fly or using autocomplete

fabian.marz’s picture

FileSize
39.85 KB

@BlacKICEUA, is there a particular case why did you use

$options = $element['#selection_settings'] + [
  'target_type' => $element['#target_type'],
  'handler' => $element['#selection_handler'],
];

over this?

$options = [
  'target_type' => $element['#target_type'],
  'handler' => $element['#selection_handler'],
  'handler_settings' => $element['#selection_settings'],
];

The upper code block threw some errors when trying to save a reference field without IDs in the values with just one entity referenced in the field config. The new patch fixes the functionality

sun’s picture

  1. +++ b/selectize.module
    @@ -2,4 +2,4 @@
    - */
    \ No newline at end of file
    + */
    

    Lots of unnecessary changes to files in this patch...

  2. +++ b/src/Element/SelectizeEntityAutocomplete.php
    @@ -0,0 +1,257 @@
    +  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
    ...
    +  public static function processAutocomplete(&$element, FormStateInterface $form_state, &$complete_form) {
    

    The overridden methods of this class never calls into the parent methods.

    We should try to avoid duplicating code of the parent class and reuse it instead. Are we doing that?

  3. +++ b/src/Element/SelectizeEntityAutocomplete.php
    @@ -0,0 +1,257 @@
    +    if ($access) {
    +      // Process selectize settings.
    +      if (isset($element['#settings'])) {
    ...
    +        // Inject the selectize library and CSS assets.
    +        $libraries[] = 'selectize/core';
    +        $libraries[] = 'selectize/drupal';
    

    $access should really be pre-determined by #access on the form element at this point of processing (possibly by the parent class code), since we don't want to be involved with that kind of logic (at all).

…cancelled right there with my review, as I wasn't sure how much is being duplicated here without solid reason. Even if that problem exists in core, we can and should still work around it using traits or helper classes here.

BlacKICEUA’s picture

@fabian.marz
This part from core. No changes added by me.

@sun
1. Added new lines
https://www.drupal.org/node/318#indenting

2. Overrided methods in the SelectizeEntityAutocomplete:
- function valueCallback - overrided call to static::getEntityLabels($element['#default_value'], $delimiter); (delimiter - added)
- function processAutocomplete (from FormElement) - overrided element #attributes and added processing for selectize settings.
- function validateEntityAutocomplete - overrided $input_values extract functionality.
- function getEntityLabels - added $delimiter.

Non-overrided methods used from parent classes:
processEntityAutocomplete, matchEntityByTitle, extractEntityIdFromAutocompleteInput ...

3. This is checks a named route with parameters against applicable access check services.
In case it - false we simple return textfield.

This is only my patch proposal.

quiron’s picture

re-rolled #32 to last version beta5 removing a not related change.

quiron’s picture

Adding a new patch version to handle with entities with duplicated labels in the referenced taxonomy. The hide ID was wrongly implemented as long as was removing the ID both from the label and the value. Now it removes only from the label.

rodrigoaguilera’s picture

Title: Entity Reference » Add support for entity reference with autocomplete
FileSize
39.33 KB
39.2 KB
1.51 KB

Patch 36 is not applying for me so I tried to re-do it based on the simple interdiff. I also attach a proper interdiff between 35 and 37.

I also include a version of the patch for the beta5 "stable" release.

BlacKICEUA’s picture

Fixed small issues in the src/Element/Selectize.php. (Added additional use statements.)
Updated Selectize library up to v0.12.6
Included two patches for 1.x-dev and beta5 releases.
Attached interdiff between 37 and 38.

BlacKICEUA’s picture

Sorry. Wrong files was uploaded early.

quiron’s picture

Status: Needs review » Reviewed & tested by the community

Tested #39 and worked for me. Also, the solution IMHO is correct.

@kevinquillen how can I help to move this forward?

thanks!

Guido_S’s picture

Nothing new here and on this module in general since almost 3 years, although it's tested & reviewed by the community?
I would really love to use selectize as a widget in drupal 8.

Pasqualle’s picture

Pasqualle’s picture

  • Pasqualle committed c3f7baa on 8.x-1.x authored by BlacKICEUA
    Issue #2678916 by BlacKICEUA, quiron, rodrigoaguilera, fabian.marz,...
Pasqualle’s picture

Category: Support request » Feature request
Status: Reviewed & tested by the community » Fixed

committed without the composer.json changes

The library installation can continue in #2949060: Add composer drupal-library information to composer.json

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.