phpsymfonywebpack-encore

Why does JQuery is not found from one page to another as they use the same twig template?


I'm creating a symfony website with UX turbo, webpack encore and stimulus. The problem occurs when i call a new controller to change the content of my twig. So here is the first page that works on the url "findAllAssociation" : findAllAssociations Then i try to load the next page that uses the same template twig : findAllCarteJeunes So the only thing that changes between that two pages are the data provided.

And i get the following error : findAllCarteJeunes:50 Uncaught ReferenceError: $ is not defined at findAllCarteJeunes:50:9 Obviously, the javascript isn't reloaded with the new view and that bother me.

Here is the template that render both of the pages :

{% extends 'layout/partials/content.html.twig' %}
{% block stylesheets %}
    {{ parent() }}
{% endblock %}
{% block javascripts %}
    {{ parent() }}
{% endblock %}
{% block head %}
    {{ parent() }}
{% endblock %}
{% block contentTableWrapper %}
    <div class="card card-body pt-0">
        <div id="kt_ecommerce_sales_table_wrapper" class="dataTables_wrapper dt-bootstrap4 no-footer">
            <div class="table-responsive w-100">
                <div class="row">
                    <div class="col-sm-12 col-md-6"></div>
                    <div class="col-sm-12 col-md-6">
                        <div class="dataTables_filter text-end">
                            <label for="searchInput" class="form-label">Recherche:</label>
                            <input id="searchInput" type="search" class="form-control form-control-sm"
                                   placeholder="Entrez votre recherche ici">
                        </div>
                    </div>
                </div>
                <table id="myTable" class="table table-striped fs-6 gy-5 no-footer dataTable m-xl-8 align-middle">
                    <thead>
                    <tr class="text-start text-gray-600 fw-bold fs-5 text-uppercase gs-0">
                        <th></th>
                        <th class="text-center min-w-100px sorting" tabindex="0"
                            aria-controls="kt_ecommerce_sales_table"
                            rowspan="1" colspan="1" aria-label="activate">
                            Statut
                        </th>
                        <th class="text-center min-w-175px sorting" tabindex="0"
                            aria-controls="kt_ecommerce_sales_table"
                            rowspan="1" colspan="1" aria-label="Customer: activate to sort column ascending">Nom
                        </th>
                        <th class="text-center min-w-200px sorting" tabindex="0"
                            aria-controls="kt_ecommerce_sales_table"
                            rowspan="1" colspan="1" aria-label="Status: activate to sort column ascending">Adresse
                        </th>
                        <th class="text-center min-w-100px sorting" tabindex="0"
                            aria-controls="kt_ecommerce_sales_table"
                            rowspan="1" colspan="1" aria-label="Date Added: activate to sort column ascending">Email
                        </th>
                        <th class="text-center min-w-100px sorting" tabindex="0"
                            aria-controls="kt_ecommerce_sales_table"
                            rowspan="1" colspan="1" aria-label="Date Added: activate to sort column ascending">Téléphone
                        </th>
                        <th class="text-center min-w-100px sorting_disabled" rowspan="1" colspan="1"
                            aria-label="Actions"
                            style="width: 141.453px;">Actions
                        </th>
                    </tr>
                    </thead>
                    <tbody id="commercants">
                    {% for association in elements %}
                        <tr>
                            <td></td>
                            <td class='text-gray-800 text-hover-primary text-center fw-bold ms-xxl-4'>
                                {# Check the value of the statut property and set the badge color accordingly #}
                                {% if association.getStatut().getLibelleStatut() == 'demande valide' %}
                                <span class='text-center badge badge-success'>
                                {% elseif association.getStatut().getLibelleStatut() == 'a verifier' %}
                                    <span class='text-center badge badge-warning'>
                                {% elseif association.getStatut().getLibelleStatut() == 'demande refuse' %}
                                    <span class='text-center badge badge-danger'>
                                {% elseif association.getStatut().getLibelleStatut() == 'demande en attente' %}
                                    <span class='text-center badge badge-info'>
                                {% else %}
                                    <span class='text-center badge badge-secondary'>
                                {% endif %}
                                        {{ association.getStatut().getLibelleStatut() }}</span>
                            </td>
                            <td class='text-center text-gray-800 fw-bold ms-xxl-4'>{{ association.getNom() }}</td>
                            {% set relAssociationLieu = association.getRelAssociationLieu() %}
                            {% if relAssociationLieu|length > 0 %}
                                {% set firstRelAssociationLieu = relAssociationLieu|first %}
                                <td class='text-center text-gray-800 fw-bold ms-xxl-4'>{{ firstRelAssociationLieu.getLieu().getAdresse() }}</td>
                            {% else %}
                                <td class='text-center text-gray-800 fw-bold ms-xxl-4'>N/A</td>
                            {% endif %}
                            <td class='text-center text-gray-800 fw-bold ms-xxl-4'>{{ association.getEmail() }}</td>
                            <td class='text-center text-gray-800 fw-bold ms-xxl-4'>{{ association.getTelephone() }}</td>

                            <td class="text-center">
                                {# Bouton de redirection vers la page findOneAssociation #}
                                <a href="{{ path('findOneAssociation', {'slug': association.getSlug()}) }}"
                                   class="text-center align-center btn btn-sm btn-icon btn-light btn-active-light-primary h-25px w-25px">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                                         class="bi bi-pen" viewBox="0 0 16 16">
                                        <path d="m13.498.795.149-.149a1.207 1.207 0 1 1 1.707 1.708l-.149.148a1.5 1.5 0 0 1-.059 2.059L4.854 14.854a.5.5 0 0 1-.233.131l-4 1a.5.5 0 0 1-.606-.606l1-4a.5.5 0 0 1 .131-.232l9.642-9.642a.5.5 0 0 0-.642.056L6.854 4.854a.5.5 0 1 1-.708-.708L9.44.854A1.5 1.5 0 0 1 11.5.796a1.5 1.5 0 0 1 1.998-.001zm-.644.766a.5.5 0 0 0-.707 0L1.95 11.756l-.764 3.057 3.057-.764L14.44 3.854a.5.5 0 0 0 0-.708l-1.585-1.585z"></path>
                                    </svg>
                                    <span class="visually-hidden"> Button </span>
                                </a>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endblock %}

Here is the base twig file :

<!DOCTYPE html>
<html lang="fr" class="fontawesome-i2svg-active fontawesome-i2svg-complete">
<head>
    {% block head %}
        <base href="/"/>
        <title>DemainVandoeuvre</title>
        <meta charset="utf-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
    {% block stylesheets %}
        {# 'app' must match the first argument to addEntry() in webpack.config.js #}
        <!--Webpack compilation-->
        {{ encore_entry_link_tags('app') }}
        {{ encore_entry_link_tags('animate') }}
        {{ encore_entry_link_tags('main') }}
        {{ encore_entry_link_tags('print') }}
        {{ encore_entry_link_tags('datatable') }}
    <link rel="canonical" href="https://preview.keenthemes.com/metronic8"/>
    <link rel="shortcut icon" href="{{ redirectBaseWithoutLast ~ '/templates/assets/media/logos/favicon.ico' }}"/>
      <!--begin::Vendor Stylesheets(used for this page only)-->
    <link href="{{ redirectBaseWithoutLast ~ '/templates/assets/plugins/custom/fullcalendar/fullcalendar.bundle.css' }}"
          rel="stylesheet" type="text/css"/>
{#    <link href="{{ redirectBaseWithoutLast ~ '/templates/assets/plugins/custom/datatables/datatables.bundle.css' }}"#}
{#          rel="stylesheet" type="text/css"/>#}
        <!--end::Vendor Stylesheets-->
        <!--begin::Global Stylesheets Bundle(mandatory for all pages)-->
    <link href="{{ redirectBaseWithoutLast ~ '/templates/assets/plugins/global/plugins.bundle.css' }}"
          rel="stylesheet" type="text/css"/>
    {% endblock %}

    {% block javascripts %}
        {{ encore_entry_script_tags('app') }}
        {{ encore_entry_script_tags('animate') }}
        {{ encore_entry_script_tags('main') }}
        {{ encore_entry_script_tags('print') }}
        {{ encore_entry_script_tags('datatable') }}
    {% endblock %}
    {% endblock %}
</head>

{% block menu %}{% endblock %}
{% block ktAppBody %}{% endblock %}
</html>

Here is the app.js file:

import './bootstrap.js';
/*
 * Welcome to your app's main JavaScript file!
 *
 * We recommend including the built version of this JavaScript file
 * (and its CSS file) in your base layout (base.html.twig).
 */
// any CSS you import will output into a single css file (app.css in this case)
import './styles/app.scss';

// start the Stimulus application
//  import './bootstrap';

//https://symfony.com/doc/current/frontend/encore/bootstrap.html
const $ = require('jquery');
Window.prototype.$ = $;
// this "modifies" the jquery module: adding behavior to it
// the bootstrap module doesn't export/return anything
require('bootstrap'); // /!\ Importer plusieurs fois bootstrap rend certaines de ses fonctionnalités inopérantes
// or you can include specific pieces
// require('bootstrap/js/dist/tooltip');
// require('bootstrap/js/dist/popover');
require('datatables.net-bs5');

// $(document).ready(function() {
//     $('[data-toggle="popover"]').popover();
// });

// this waits for Turbo Drive to load
document.addEventListener('turbo:load', function (e) {
    // this enables bootstrap tooltips globally
    let tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
    let tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
        return new Tooltip(tooltipTriggerEl)
    });
});

As the error doesn't happend on the first page, i expect that the previous error mentionned don't show up on the next pages that uses the same template.

If you need more informations please ask.

Thanks in advance for your help.


Solution

  • Here is the answer that worked for me :

    https://symfony.com/doc/current/frontend/encore/faq.html :

    "jQuery is not defined" or "$ is not defined" This error happens when your code (or some library that you are using) expects $ or jQuery to be a global variable. But, when you use Webpack and require('jquery'), no global variables are set.

    The fix depends on if the error is happening in your code or inside some third-party code that you're using. See jQuery Plugins and Legacy Applications for the fix.

    https://symfony.com/doc/current/frontend/encore/legacy-applications.html

    I added to my app.js the following :

    resulting in :

    import './bootstrap.js';
    /*
     * Welcome to your app's main JavaScript file!
     *
     * We recommend including the built version of this JavaScript file
     * (and its CSS file) in your base layout (base.html.twig).
     */
    // any CSS you import will output into a single css file (app.css in this case)
    import './styles/app.scss';
    
    // start the Stimulus application
    //  import './bootstrap';
    
    //https://symfony.com/doc/current/frontend/encore/bootstrap.html
    const $ = require('jquery');
    Window.prototype.$ = $;
    global.$ = global.jQuery = $;
    // this "modifies" the jquery module: adding behavior to it
    // the bootstrap module doesn't export/return anything
    require('bootstrap'); // /!\ Importer plusieurs fois bootstrap rend certaines de ses fonctionnalités inopérantes
    // or you can include specific pieces
    // require('bootstrap/js/dist/tooltip');
    // require('bootstrap/js/dist/popover');
    require('datatables.net-bs5');
    
    // $(document).ready(function() {
    //     $('[data-toggle="popover"]').popover();
    // });
    
    // this waits for Turbo Drive to load
    document.addEventListener('turbo:load', function (e) {
        // this enables bootstrap tooltips globally
        let tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
        let tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
            return new Tooltip(tooltipTriggerEl)
        });
    });