Search code examples
stimulusjs

Symfony Stimulus controller target not recognize on initialize() but recognize on connect()


Dealing with Symfony 7 project that it use Hotwire technologies (Stimulus, Turbo), I'm facing with strange issue with my Stimulus controller.

I have a target controller Stimulus that recognize onto connect() function lifecycle BUT not onto the initialize() controller lifecycle.

The Stimulus controller :

export default class Autocomplete extends Controller
{
    static targets = ["input", "hidden", "results"]
    static classes = ["selected"]
    static values = {
        ready: Boolean,
        submitOnEnter: Boolean,
        url: String,
        minLength: Number,
        delay: { type: Number, default: 300 },
        queryParam: { type: String, default: "q" },
    }
    static uniqOptionId = 0

    connect() {

        console.log(this.targets.find("input")) // OK
        console.log(this.targets.find("results")) // OK

        

the HTML DOM objects :

        <div data-controller="autocomplete" class="ms-auto">

            <div data-controller="autocomplete" data-autocomplete-url-value="{{ path('app_fo_search') }}" role="combobox">

                <div class="input-group input-group-sm">
                    <input type="text" id="search_input" class="form-control form-control-sm collapse collapse-horizontal" placeholder="Rechercher un artiste, une oeuvre ou une collection...." data-autocomplete-target="input"/>
                    <span class="input-group-text" data-bs-toggle="collapse" data-bs-target="#search_input"><i class="bi bi-search"></i></span>
                </div>

                <input type="hidden" name="search" id="search_value" data-autocomplete-target="hidden"/>

                <ul class="list-group" data-autocomplete-target="results" style="min-width: calc(25% - 8px);max-width:calc(33% - 8px);max-height: 90vh; overflow-y: scroll;position: absolute;right:1rem;z-index: 10000;"></ul>

            </div>

        </div>

Browser inspector error :

browser inspector error


Solution

  • You have nested your automplete controllers. There is no need for that here. The outer controller doesn't have access to nested targets. Note, that this applies only if it is the same controller, different controllers can be nested without interference.

    When nested, each controller is only aware of its own scope excluding the scope of any controllers nested within.

    https://stimulus.hotwired.dev/reference/controllers#nested-scopes

    You should use connect() whenever you want to access DOM:

    initialize()    // Once, when the controller is first instantiated
    connect()       // Anytime the controller is connected to the DOM
    

    https://stimulus.hotwired.dev/reference/lifecycle-callbacks#methods

    You can also use predefined target properties instead this.inputTarget, this.resultsTarget:

    https://stimulus.hotwired.dev/reference/targets#properties