Allow removing the last item even for required fields

Created on 6 February 2025, about 1 month ago

Problem/Motivation

Especially when the cardinality is 1, it is not natural for people to know they have to add another item before the existing one can be removed. The Remove option should always be there; regular validation can handle the enforcement of the field not being empty, same as when it is new and has no references yet.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

โœจ Feature request
Status

Active

Version

1.0

Component

Code

Created by

๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA

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

Comments & Activities

  • Issue created by @mlncn
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA

    OK this is actually a bug, that it does not already work the way i expect:

        if (!$allow_new && $allow_existing) {
          // Only count referencable entities if existing entities are allowed
          // to be referenced otherwise we set the variable to false.
          /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler */
          $handler = $this->selectionManager->getInstance($options);
          $have_multiple_existing_entities = count($handler->getReferenceableEntities(NULL, 'CONTAINS', 2)) > 1;
        } else {
          $have_multiple_existing_entities = FALSE;
        }
    
            // Determine if a reference may be removed.
            // Unless the user has permission to delete the entity, then they should
            // not be able to remove it if that will lead to its deletion.
            $may_remove_existing = $settings['removed_reference'] !== self::REMOVED_DELETE || $entity->access('delete');
    
            // Don't allow a user to remove the only entity if an entity is required
            // and the user cannot replace the entity if they remove it, because
            // this would put the form in an unrecoverable state.
            $can_replace_last_reference = $allow_new || ($allow_existing && $have_multiple_existing_entities);
            $reference_is_not_required = !$element['#required'] || $entities_count > 1 || $can_replace_last_reference;
    
            // Unsaved entities may always be removed.
            $may_remove = empty($entity_id) || ($may_remove_existing && $reference_is_not_required);
    

    The reason the count seems to be off, at least in my case, is because getReferenceableEntities() returns an array of bundles, and inside that the entities, so in the case of the user reference it counts the one bundleโ€” not the two entities that it should count. (There are many more than two, but the code limits the maximum results to two, because it only cares if it is zero, one, or more than one.)

    This is indeed exactly what the getReferenceableEntities method says it will return:

       *   A nested array of entities, the first level is keyed by the
       *   entity bundle, which contains an array of entity labels (escaped),
       *   keyed by the entity ID.
    

    We can probably save ourselves a step, and fix this bug, by using the countReferenceableEntities() method.

    • mlncn โ†’ committed 01cb7751 on 1.0.x
      Issue #3504707: Allow removing the last item even for required fields
      
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States mlncn Minneapolis, MN, USA

    @TODO offer same patch to IEF

Production build 0.71.5 2024