[X] HTTP (GET)[X] PHP[X] Doctrine[X] Routeur Symfony[X] HTML[X] Twig[X] CSS[X] Formulaires[X] Sessions[X] Contrôle d’accèsIl nous manque JavaScript (JS), et AJAX
Objectifs de cette séance (1h) :
Améliorons l’UX des formulaires…
Rappel modèle données :
Project et Todo reliées par un OneToMany
make:crud
Propriété multi-valuée Project::todos
class ProjectType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('description')
            ->add('todos')
            ;
Problème : comment sélectionner plusieurs valeurs ? (Crtl + clic)
class ProjectType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('description')
            ->add('todos', null, [
                            'multiple' => true,
                            'expanded' => true
                         ])
            ;
Par défaut, génère un champs ChoiceType … OK, merci la doc…
class ProjectType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title')
            ->add('description')
            ->add('todos', null, [
              'multiple' => true,
              'expanded' => true,
              'by_reference' => false
          ])
            ;
'by_reference' => false nécessaire pour que ça sauvegarde les
modifications sur les tâches du projet … merci la doc…
Rappel : gabarit Twig généré par défaut par make:crud
{% extends 'base.html.twig' %}
{% block title %}Edit Project{% endblock %}
{% block body %}
    <h1>Edit Project</h1>
    {{ include('project/_form.html.twig', {'button_label': 'Update'}) }}
    <a href="{{ path('app_project_index') }}">back to list</a>
    {{ include('project/_delete_form.html.twig') }}
{% endblock %}
Sous-gabarit pour le formulaire project/_form.html.twig
{{ form_start(form) }}
    {{ form_widget(form) }}
    <button class="btn btn-primary">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
Éclater la structure des widgets du formulaire
{{ form_start(form) }}
    {% dump form.todos %}
    {{ form_errors(form) }}
    <div class="row">
        <div class="col">
            {{ form_row(form.title) }}
            {{ form_row(form.description) }}
        </div>
        <div class="col">
            
            {{ form_row(form.todos) }}
        </div>
    </div>
    <button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
Surcharge du gabarit par défaut… c’est faisable, mais à quel coût…
{% extends 'base.html.twig' %}
{% form_theme form _self %}
{% block _project_todos_entry_widget %}
  {% set entity = form.parent.vars.choices[form.vars.value].data %}
  {% set checked = form.parent.children[form.vars.value].vars.checked %}
  <div class="form-check">
    <input type="checkbox" id="project_todos_{{ entity.id }}"
           name="project[todos][]" class="form-check-input"
           value="{{ entity.id }}"
       {% if checked %}
           checked="checked"
       {% endif %}
     />
    <label class="form-check-label" for="project_todos_{{ entity.id }}">
      {% if entity.title is empty %}(<i>unnamed todo #{{ entity.id }}</i>)
      {% else %}{{ entity.title }}
      {% endif %}
    </label>
  </div>
{% endblock %} {# _project_todos_entry_widget #}
{% block title %}Edit Project{% endblock %}
...
Faites-en sorte que ça fonctionne… mais on n’est pas là pour faire une vraie application, donc ne pas faire tout cela.
Des listes à sélection multiple peuvent suffire… même si Ctrl+clic ce n’est pas formidable.
Sinon, explosion de l’effort nécessaire.
Objectifs de cette séance (1h) :
« HTML dynamique »
Objectifs de cette séance (1h) :
Abrégé : JS
Date, Array…)Nombreuses bibliothèques (frameworks) aident à programmer.
Ex: Dojo, Rialto, Angular, JQuery, Yui…
JSON (JavaScript Object Notation) utilise la notation des objets JavaScript pour transmettre de l’information structurée
{
  "nationalTeam":"Norway",
  "achievements":[
      "12 Olympic Medals",
      "9 World Championships",
      "Winningest Winter Olympian",
      "Greatest Nordic Skier"
     ],
  "name":"Bjoern Daehlie",
  "age":41,
  "gender":"Male"
}
<script> et </script>
Soit directement :
<head>
    <script> 
        code javascript (fonctions, variables...)
    </script>
</head>
Soit dans un fichier séparé (ou URL externe) :
<head>
    <script src="monprog.js"></script>
</head>
à partir d’évènements dans les balises
<input type="button"
       onClick="alert('clic sur bouton');">
à partir d’un lien
<a href="javascript:affiche(menu);">
par d’autres fonctions
function hello() {
  alert("hello");
}
onClick, onLoad, onChange, onMouseOver, onMouseOut, onKeyDown…)clic sur bouton :
<input type="button" name="surface" value="Surface"
       onClick="Test(all);">
déplacement souris au-dessus :
<a href="menu.html" onMouseOver="affiche();">
fin de chargement du document :
<body onLoad="init(1);">
| Evénements | Balises | Fonctions | 
onBlur | 
* | désélection | 
onChange | 
idem | modification | 
onFocus | 
idem | sélection | 
onSelect | 
password, text, textarea | 
sélection de valeur | 
onClick | 
a href, button, checkbox, radio, reset, submit | 
clic | 
onMouseover | 
a href, area | 
souris pointe | 
onLoad | 
body | 
chargement page | 
onSubmit | 
form | 
soumission | 
<html>
    <head> 
        <script language="JavaScript">
            function maFonction() {
                alert('Vous avez cliqué sur le bouton GO');
            }
            function autreFonction() {
                alert('Cliqué sur le lien "Cliquer ici"');
            }    
        </script> 
    </head>
    <body>
      <ol>
        <li>Appel sur évènement : 
            <input type="button" value="GO" onClick="maFonction();"> 
        </li>
        <li>Appel sur un lien : 
            <a href="javascript:autreFonction();">Cliquer ici</a> 
        </li>
      </ol>
      <a href="javascript:history.go(-1);">Retour</a>
    </body>
</html>
monObjet.attributsmonObjet.méthode()// Création d'une variable
var etienne = {
    nom : "etienne";
    branche : "marketing";
}
// Création d'un objet par constructeur
function Employe (nom,branche) {
    this.nom = nom;
    this.branche = branche;
    this.fullDescription = function () {
        return this.nom + " " + this.branche;
    };
}
var marc=new Employe("marc","informatique");
marc.fullDescription(); // appel de méthodes
Les objets du noyau
Object : création d’un objetFunction : création d’une fonctionArray : création d’un tableauString : création d’une chaîne de caractèresNumber : création d’un nombreDate : création d’une dateMath : création d’un objet mathématiqueLes objets du navigateur :
Délicate avec les langages interprétés car :
Document Object Model (Modèle Objet du Document)
<html>
  <head>
    ...
  </head>
  <body>
    <h1>DOM</h1>
    <div id='main'>
      <p name="p1">Le DOM trop top</p>
      <p class="p2">DOM API</p>
    </div>
    <h2>Exemples</h2>
  </body>
</html>
<div id="intro">h2, …class) avec
des définitions de feuilles de style : interfaces réactives
Faciliter la tâche des développeurs.
Un peu ancien, et il y a sûrement mieux aujourd’hui… mais montré ici pour illustrer, pas comme recommendation ultime.
jQuery dispose aussi d’extensions sous forme de plugins
téléchargé depuis jQuery.com et inclus en local sur notre site
<head>
  <script src="jquery-3.7.1.min.js"></script>
</head>
ou référencer sur serveur de contenu externe, p. ex. sur CDN (Content Delivery Network) jQuery
<head>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js">
  </script>
</head> 
Attention : traçage des utilisateurs
Syntaxe de base jQuery :
$(selector).action(...)
$() permet d’implanter un traitement avec jQueryselector) permet de sélectionner un (ou plusieurs) élément(s) HTMLaction) est exécutée sur chaque élément sélectionnéActions immédiates : changer l’état d’un élément du DOM. Exemple :
$(this).hide() // cacher l'élément courant
Mise en place de réflexes (callbacks) sur des événements (actions différées) :
$('#bouton1').click(function() {
    // actions à faire lors d'un clic sur le bouton
    //...
});
Pour éviter que nos actions jQuery s’exécutent sur des objets non encore chargés, jQuery permet de ne démarrer le tout qu’une fois reçu l’évènement « document ready » :
$(document).ready(function(){
   // code jQuery...
});
$(this)$("p"), pour tous éléments <p>$("#id1") : l’élément ayant l’identifiant id1$(".test")  tous éléments ayant attribut class testMême syntaxe que les sélecteurs CSS
Objectifs de cette séance (1h) :
Asynchronous JavaScript And XML
XMLHttpRequest (XHR) de JavaScriptnew XMLHttpRequest();XMLHttpRequestGET d’un document ou POST de
données, ou …)
L’utilisation de jQuery permet de faciliter l’écriture de programmes AJAX avec la fonction :
$.ajax()
url : définit l’URL de la requêtetype : précise la méthode (GET ou POST)data : précise les données à envoyer si POSTsuccess : définit traitement à effectuer si requête réussit (fonction)error : définit traitement à effectuer si requête échoue (fonction)//...
$.ajax( {
    url: "test.php",
    error: function(resultat, statut, erreur) {
        // ...
    }
    success: function(resultat, statut) {
        // ...
    }
} );
Construction de formulaires dynamiques avec Symfony