[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
Propriété multi-valuée Project::todos
<?php
//...
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)
<?php
//...
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…
<?php
//...
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 proprement dit
{{ 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.attributs
monObjet.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.6.0.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.6.0.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
test
Même syntaxe que les sélecteurs CSS
Objectifs de cette séance (1h) :
Asynchronous JavaScript And XML
XMLHttpRequest
(XHR) de JavaScriptnew XMLHttpRequest();
XMLHttpRequest
GET
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 POST
success
: 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