Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Autocomplete] (using without form) How to pass extra_options to stimulus controller ? #2368

Open
matthieumastadenis opened this issue Nov 12, 2024 · 3 comments
Labels
Autocomplete question Further information is requested

Comments

@matthieumastadenis
Copy link

Hello,

I'm using the autocomplete component outside of a form and I need to use extra_options. I followed the documentation and implemented the following class:

<?php

namespace App\Autocompleter;

use App\Entity\Tag;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use Symfony\UX\Autocomplete\OptionsAwareEntityAutocompleterInterface;

#[AutoconfigureTag('ux.entity_autocompleter', [ 'alias' => 'tag' ])]
class TagAutocompleter implements OptionsAwareEntityAutocompleterInterface
{

    /**
     * @var array<string, mixed>
     */
    protected array $options = [];

    public function getEntityClass(): string
    {
        return Tag::class;
    }

    /**
     * @param array<string, mixed> $options
     */
    public function setOptions(array $options): void
    {
        $this->options = $options;
    }

    /**
     * @param EntityRepository<Tag> $repository
     */
    public function createFilteredQueryBuilder(
        EntityRepository $repository,
        string           $query,
    ): QueryBuilder {
        $extra   = $this->options['extra_options'] ?? [];
        $context = $extra['context'] ?? null;

        $qb = $repository->createQueryBuilder('t')
            ->andWhere('t.name LIKE :name')
            ->setParameter('name', '%'.$query.'%')
        ;

        if ($context !== null) {
            $qb->where('t.context=:context')
                ->setParameter('context', (string) $context)
            ;
        }

        return $qb;
    }

    /**
     * @throws \Exception
     */
    public function getLabel(object $entity): string
    {
        if (!($entity instanceof Tag)) {
            return throw new \Exception('Object of class '.($entity::class).' is not a Tag');
        }

        return $entity->getName();
    }

    /**
     * @throws \Exception
     */
    public function getValue(object $entity): string
    {
        if (!($entity instanceof Tag)) {
            return throw new \Exception('Object of class '.($entity::class).' is not a Tag');
        }

        return (string) $entity->getId();
    }

    public function isGranted(Security $security): bool
    {
        return true;
    }
}

However, I cannot find how to properly pass my extra_options to the stimulus controller from twig. Unless I'm mistaken, I think the "Manually using stimulus controller" section of the documentation lacks some precision about that.

I first tried this:

<select
    id="attachment_{{ id }}_tags"
    name="attachments[{{ id }}][tags]"
    multiple
    {{ stimulus_controller('symfony/ux-autocomplete/autocomplete', {
        url: path('ux_entity_autocomplete', { alias: 'tag', extra_options: { context: attachmentTagContext.value } }),
    }) }}
></select>

...which resulted in the following error:

Input value "extra_options" contains a non-scalar value.

Then I tried this (with a custom base64_encode filter):

<select
    id="attachment_{{ id }}_tags"
    name="attachments[{{ id }}][tags]"
    multiple
    {{ stimulus_controller('symfony/ux-autocomplete/autocomplete', {
        url: path('ux_entity_autocomplete', { alias: 'tag', extra_options: { context: attachmentTagContext.value }|json_encode|base64_encode }),
    }) }}
></select>

...which also gave me an error:

The extra options are missing the checksum.

So, how can I simply pass my extra options? Do I have to manually create and include the checksum myself (if so, how exactly please?) or is there a simpler way to achieve this?

Thanks

@smnandre
Copy link
Member

Hi @matthieumastadenis , I believe the second paragraph about custom Autocomplete has been missplaced.

You can pass options to a custom Autocompleter (in the meaning "not for an entity, or not with the same implementation than the one we use).. but to use extra_options it must be generated with the form system (where we generate the url / checksum).

Or ... you can look at the ChecksumCalculator class to see how it's done today. But as you will see this class is marked internal, meaning it can change at any moment (passing the "extra_options" is supported, but the way it works right now must stay internal to be able to change/improve it)

@smnandre smnandre added question Further information is requested and removed Bug Bug Fix Status: Needs Review Needs to be reviewed labels Nov 12, 2024
@matthieumastadenis
Copy link
Author

Hi @matthieumastadenis , I believe the second paragraph about custom Autocomplete has been missplaced.

You can pass options to a custom Autocompleter (in the meaning "not for an entity, or not with the same implementation than the one we use).. but to use extra_options it must be generated with the form system (where we generate the url / checksum).

Or ... you can look at the ChecksumCalculator class to see how it's done today. But as you will see this class is marked internal, meaning it can change at any moment (passing the "extra_options" is supported, but the way it works right now must stay internal to be able to change/improve it)

Thanks, indeed I saw the ChecksumCalculator class and the @internal tag so I preferred to ask.

For the moment I found a workaround by using a child component in which I can now use a dedicated form.

But I eventually may have a similar issue in the future, and I think it would be better to avoid reimplementing ChecksumCalculator myself (especially if this is expected to change in the future). In the ideal scenario it would be great to have a twig function (autocomplete() or something like that) which could accept extra_options and calculate the checksum transparently. But I don't know if this would be possible, so it's just a naive suggestion for the moment.

@smnandre
Copy link
Member

Could i ask you what would be your use case here ? See what would be possible ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Autocomplete question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants