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:

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Ăšle book
  • 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Ă©thode newBook() de notre contrĂŽleur
  • <a href="# " ng-click="saveBook(book)">Valider (ajout ou modification)</a> qui permet d’appeler la nouvelle mĂ©thode saveBook(book) de notre contrĂŽleur en lui passant les valeurs de book (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.

blog comments powered by Disqus

Related posts