Angular, et la directive include

Alors comme je l’annonçais ce matin, l’article d’aujourd’hui sera court (très court), mais néanmoins il pourra peut-être changer votre vie de développeur front (ok, j’y vais un peu fort, mais …). Combien de fois j’ai pesté parce que mon code html devenait trop “touffu”, illisible, … Dans ces moments là, il ya plusieurs solutions : bricolage avec jquery pour charger les templates, appel au plugin text de require, grunt, … mais toujours une gymnastique à force pénible pour arriver à modulariser ses page html.

Avec Angular c’est simple, en 1 seule directive vous pouvez régler tous vos problèmes.

Pré-requis: avoir lu les articles précédents:

Restructuration de notre projet (côté front)

Actuellement nous avons une structure front qui doit ressembler à ceci:

votre_projet/
├── public/
|   ├── bower_components/ /* angular est par ici */
|   ├── js/      
|   |    └── main.js
|   └── index.html
├── bower.json
└── .bowerrc

Créez donc dans /public un répertoire books avec 2 fichiers html à l’intérieur : bookForm.html et booksList.html, comme ceci:

votre_projet/
├── public/
|   ├── bower_components/ /* angular est par ici */
|   ├── js/      
|   |    └── main.js
|   ├── books/ 
|   |    ├── bookForm.html
|   |    └── booksList.html   
|   └── index.html
├── bower.json
└── .bowerrc

Dans votre page index.html extrayez complètement le code correspondant à votre formulaire pour le coller dans bookForm.html. Le contenu de bookForm.html devrait être celui-ci:

<h3 class="uk-panel-title">Formulaire Livre</h3>

<form class="uk-form" name="bookForm" novalidate>
  <input ng-model="book.title" name="title" placeholder="titre du film" required>

  <span ng-show="bookForm.title.$error.required" class="uk-text-warning">Champs obligatoire</span>

  <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>
  <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>

Ensuite, toujours de votre page index.html extrayez complètement le code correspondant à votre liste de livre pour le coller dans booksList.html. Le contenu de booksList.html devrait être celui-ci:

<h3 class="uk-panel-title">Liste des Livres</h3>

<form class="uk-form">
  <input ng-model="search.$" placeholder="chercher un livre">
  <input ng-model="search.title" placeholder="par titre">
  <input ng-model="search.description" placeholder="par description">
  <select ng-model="search.level"
          ng-options="level for level in levels">
  </select>
</form>

<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 | filter:search:strict" ng-click="selectBook(book)">

  <tr>
    <td>{{book.title}}</td>
    <td>{{book.description}}</td>
    <td>{{book.level | stars}}</td>
    <td>{{book._id}}</td>
  </tr>
  </tbody>
</table>

Du coup, votre page index.html devrait ressembler à ceci:

<!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">

    <div class="uk-container uk-container-center">

      <div class="uk-grid" ng-controller="MainCtrl">
        <div class="uk-width-4-10">

          <div class="uk-panel">
            <!-- ici il y avait la saisie des livres -->
          </div>

        </div>

        <div class="uk-width-6-10">

          <div class="uk-panel">
            <!-- ici il y avait la liste des livres -->
          </div>

        </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>

Alors c’est tout de suite plus propre, mais ça marche forcément beaucoup moins bien …

La “magie” avec Angular

Nous devons juste nous contenter d’expliquer à Angular où sont bookForm.html et booksList.html. Et pour cela la directive ng-include va grandement nous faciliter la vie. Pour cela,

Remplacez:

<div class="uk-panel">
  <!-- ici il y avait la saisie des livres -->
</div>

par:

<div class="uk-panel" ng-include="'books/bookForm.html'" onload="whenFormIsLoaded()"></div>

Angular à partir de ng-include ira charger books/bookForm.htmlet lancera grâce à onload la méthode whenFormIsLoaded()du contrôleur (il faudra créer la méthode, mais onload n’est pas obligatoire).

Puis remplacez:

<div class="uk-panel">
  <!-- ici il y avait la liste des livres -->
</div>

par:

<div class="uk-panel" ng-include="'books/booksList.html'" onload="whenListIsLoaded()"></div>

Angular, toujours à partir de ng-include ira aussi charger books/booksList.htmlet lancera grâce à onload la méthode whenListIsLoaded()du contrôleur (il faudra créer la méthode, mais onload n’est pas obligatoire).

Remarque importante: avez vous vu que j’ai mis les paths vers les templates html entre simples quotes avant de les mettre entre doubles quotes : c’est pour éviter à Angular d’évaluer la directive.

Donc le code définitif de index.html devrait être le suivant:

<!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">

    <div class="uk-container uk-container-center">

      <div class="uk-grid" ng-controller="MainCtrl">
        <div class="uk-width-4-10">

          <div class="uk-panel" ng-include="'books/bookForm.html'" onload="whenFormIsLoaded()"></div>

        </div>

        <div class="uk-width-6-10">

          <div class="uk-panel" ng-include="'books/booksList.html'" onload="whenListIsLoaded()"></div>

        </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>

Il ne vous reste plus qu’à tester. Je vous laisse imaginer comment cela va être facile de modulariser vos projets et de vous en faciliter la maintenance.

Next step: ngRoute

@ bientôt ;)

blog comments powered by Disqus

Related posts