Angular, un peu de formulaire
AprĂšs une petite escapade du cĂŽtĂ© de chez Redis, revenons Ă nos moutons. Mon (Notre maintenant) application est plutĂŽt âmocheâ donc nous allons un peu travailler sur le code HTML.
Pré-requis: avoir lu les articles précédents:
- http://k33g.github.io/2014/05/17/ANGULAR-01.html
- http://k33g.github.io/2014/05/18/ANGULAR-02.html
- http://k33g.github.io/2014/05/19/ANGULAR-03.html
- http://k33g.github.io/2014/05/20/ANGULAR-04.html
- http://k33g.github.io/2014/05/21/ANGULAR-05.html
ou lire la version âe-bookâ : http://e-books.github.io/je.decouvre.angular/
Mais dâabord le contrĂŽleur
Pour pouvoir interagir bien mieux avec lâIHM je vous propose dâajouter quelques mĂ©thodes Ă notre contrĂŽleur.
selectBook()
: je veux pouvoir sélectionner un livre dans la liste
$scope.selectBook = function(book) {
$scope.book = book;
}
saveBook()
: je fais un update si mon livre a une propriété _id
renseignĂ©e, sinon câest une crĂ©ation
$scope.saveBook = function(book) {
book._id !== undefined ? $scope.updateBook(book) : $scope.createBook(book);
}
newBook()
: je crĂ©Ă©e un livre âvideâ (cela me servira Ă vider mon formulaire)
$scope.newBook = function() {
$scope.book = {};
}
On peut passer Ă lâIHM
Pour une fois, je ne vais pas utiliser Bootstrap mais UIkit http://www.getuikit.com/ que je trouve assez joli (et jâavais envie de changer un peu).
Donc dans notre fichier bower.json
, nous ajoutons une ligne pour UIkit:
{
"name": "books",
"version": "0.0.0",
"dependencies": {
"angular" : "1.2.16",
"angular-resource" : "1.2.16",
"uikit" : "2.6.0"
}
}
Ensuite vous faite un bower update
dans votre console/terminal. Et vous ĂȘtes prĂȘts Ă refaire la page index.html
(dans /public
). Vous pouvez tout supprimer, nous allons reprendre tout le code html.
Voici la nouvelle structure de votre page:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>livres</title>
<link rel="stylesheet" href="bower_components/uikit/dist/css/uikit.almost-flat.min.css" />
</head>
<body ng-app="booksApp" style="padding: 10px"> <!-- on n'oublie pas la directive ng-app -->
<div class="uk-container uk-container-center">
<div class="uk-grid" ng-controller="MainCtrl"> <!-- on n'oublie pas la directive ng-controller -->
<div class="uk-width-4-10">
<!-- FORMULAIRE : Ici nous aurons notre formulaire de saisie -->
</div>
<div class="uk-width-6-10">
<!-- GRILLE : Ici nous aurons la liste des livres -->
</div>
</div>
</div>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-resource/angular-resource.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Le formulaire: Ă lâendroit oĂč il y a le commentaire <!-- FORMULAIRE : Ici nous aurons notre formulaire de saisie -->
, insérez le code suivant:
<div class="uk-panel">
<h3 class="uk-panel-title">Formulaire Livre</h3>
<form class="uk-form" name="bookForm">
<input ng-model="book.title" name="title" placeholder="titre du film">
<input ng-model="book.description" placeholder="description du film">
<select ng-model="book.level"
ng-options="level for level in levels">
</select>
<p ng-model="book">{{book._id}}</p>
<hr>
<a href="# " ng-click="newBook()">Nouveau</a> |
<a href="# " ng-click="saveBook(book)">Valider (ajout ou modification)</a> |
<a href="# " ng-click="deleteBook(book._id)">Supprimer</a> |
<hr>
</form>
</div>
Nous retrouvons bien:
- les directives
ng-model
dans les tag<input>
et<select>
pour fair le lien avec le modĂšlebook
- jâai ajoutĂ© :
<p ng-model="book">{{book._id}}</p>
pour afficher lâid du livre quand il existe (donc quand il a dĂ©jĂ Ă©tĂ© sauvegardĂ© en base).
Nous avons ensuite une liste de liens:
<a href="# " ng-click="newBook()">Nouveau</a>
qui permet de âviderâ notre formulaire en appelant la nouvelle mĂ©thodenewBook()
de notre contrĂŽleur<a href="# " ng-click="saveBook(book)">Valider (ajout ou modification)</a>
qui permet dâappeler la nouvelle mĂ©thodesaveBook(book)
de notre contrĂŽleur en lui passant les valeurs debook
(liĂ© au formulaire), et qui dĂ©terminera en fonction de la prĂ©sence ou non dâun id si câest une modification ou un ajout<a href="# " ng-click="deleteBook(book._id)">Supprimer</a>
pour supprimer le livre sélectionné
La grille (ou table) des livres: Ă lâendroit oĂč il y a le commentaire <!-- GRILLE : Ici nous aurons la liste des livres -->
, insérez le code suivant:
<div class="uk-panel">
<h3 class="uk-panel-title">Liste des Livres</h3>
<table class="uk-table uk-table-hover">
<thead>
<tr>
<th>Titre</th>
<th>Description</th>
<th>Niveau</th>
<th>id</th>
</tr>
</thead>
<tbody ng-repeat="book in books" ng-click="selectBook(book)">
<tr>
<td>{{book.title}}</td>
<td>{{book.description}}</td>
<td>{{book.level}}</td>
<td>{{book._id}}</td>
</tr>
</tbody>
</table>
</div>
Nous avons toujours notre directive ng-repeat="book in books"
qui va nous permettre dâajouter autant de lignes(rows) ou <tr>
dans notre grille ou <table>
.
Ainsi que ng-click="selectBook(book)"
qui permettra ainsi dâafficher le livre dans le formulaire si on clique sur la ligne correspondante.
Donc si ce nâest dĂ©jĂ fait, relancez votre application cĂŽtĂ© serveur et connectez vous sur votre splendide âSingle Page Applicationâ de gestion de livre, et jouez avec:
Vous allez rapidement vous apercevoir que vous pouvez ajouter des livres âvidesâ, câest moche!
Nous avons donc un prĂ©texte pour regarder comment fonctionne le contrĂŽle de saisie avec Angular (il faudrait aussi modifier cĂŽtĂ© serveur notre API pour empĂȘcher dâavoir un livre âvideâ).
Nous allons voir une infime partie des possibilités proposées par Angular, mais déjà bien pratique. Pour aller plus loin, vous pouvez commencer par ceci https://docs.angularjs.org/api/ng/type/form.FormController et https://docs.angularjs.org/guide/forms.
Validation
Nous avions le formulaire suivant:
<form class="uk-form" name="bookForm">
<input ng-model="book.title" name="title" placeholder="titre du film">
<input ng-model="book.description" placeholder="description du film">
<select ng-model="book.level"
ng-options="level for level in levels">
</select>
<p ng-model="book">{{book._id}}</p>
<hr>
<a href="# " ng-click="newBook()">Nouveau</a> |
<a href="# " ng-click="saveBook(book)">Valider (ajout ou modification)</a> |
<a href="# " ng-click="deleteBook(book._id)">Supprimer</a> |
<hr>
</form>
Vous pouvez noter que le formulaire a un nom name="bookForm"
et que le champ de saisie des titres a lui aussi un nom name="title"
. Cela va nous servir à tester la validité de notre saisie. Modifions notre formulaire comme suit:
On ajoute lâattribut novalidate
au tag <form></form>
:
<form class="uk-form" name="bookForm" novalidate>
Comme cela on nâutilise pas les messages dâerreurs natifs
On ajoute lâattribut required
au champ de saisie des titres:
<input ng-model="book.title" name="title" placeholder="titre du film" required>
Ensuite on ajoute un message qui nâapparaĂźtra que si le champ de saisie de titre est vide:
<span ng-show="bookForm.title.$error.required" class="uk-text-warning">Champs obligatoire</span>
Cette partie là reste inchangée:
<input ng-model="book.description" placeholder="description du film">
<select ng-model="book.level"
ng-options="level for level in levels">
</select>
<p ng-model="book">{{book._id}}</p>
Remplaçons nos liens par des boutons et prĂ©cisons pour le bouton de sauvegarde quâil nâest actif uniquement si les donnĂ©es du formulaire sont valide avec lâattribut : ng-disabled="bookForm.$invalid"
:
<hr>
<button class="uk-button" ng-click="newBook()">Nouveau</button> |
<button class="uk-button uk-button-primary" ng-disabled="bookForm.$invalid" ng-click="saveBook(book)">Valider (ajout ou modification)</button> |
<button class="uk-button uk-button-danger" ng-click="deleteBook(book._id)">Supprimer</button> |
<hr>
</form>
Sauvegardez, relancez et vérifiez que cela fonctionne:
Simple et pratique.
Ă demain.
Tweet