Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Prochaines sessions inter-entreprises : 28-31 mars 2017 / 13-16 juin 2017
Sessions intra-entreprises sur demande.
Inscrivez-vous vite !

Développer une application REST avec Spring MVC & Angular.js

Aujourd'hui plus que jamais, le Javascript a le vent en poupe. On le trouve même côté serveur - ce que je trouve personnellement d'une absurdité étourdissante, mais passons.

En ce moment, la mode est aux frameworks MVC côté client ; là, j'y crois déjà un peu plus. Mais il en sort environ un par semaine, et il est difficile de faire son choix, malgré la pléthore de comparatifs qui fleurissent sur le net (ici, , ou encore là-bas).

Thoughtworks, de son côté, estime que la peinture n'est pas encore sèche et qu'il vaut mieux attendre un peu avant de se lancer dans ce genre d'aventure en production. En effet, on a encore très peu de retours d'expérience, et la pérennité des frameworks n'est pas encore démontrée.

Pourtant, dans le tas, il y en a un qui m'a fait de l'oeil : Angular.js. Je vous propose donc une petite démonstration de son intégration avec Spring MVC côté serveur, pour réaliser une application, totalement originale n'est-ce pas, de "todo-list".

La stack

Voyons un peu la stack qui compose l'application.

Angular.js

Pour commencer, donc, Angular.js.

Malgré un nom propice aux jeux de mots les plus graveleux, c'est un projet qui paraît fort bien né. Développé et maintenu par Google (bonus +1 en pérennité) et disponible sous licence MIT, il se base sur l'incontournable JQuery pour fonctionner (bonus +1 pour la non-réinvention de la roue).

Contrairement à la plupart de ses concurrents qui se limitent plus ou moins à du templating, Angular propose de nombreuses fonctionnalités alléchantes :

  • Data-binding bi-directionnel entre un modèle et des composants, sans aucune ingérence du framework.
  • Templates HTML purs ; le binding est simplement réalisé par l'ajout de propriétés ng-* dans les balises (à la Wicket).
  • Possibilité de créer des composants personnalisés et entièrement réutilisables, en HTML ! (ex: un <colorpicker> qui encapsulerait tout le markup et le javascript nécessaires)
  • Modèle MVC2 avec un Front-controller ("router"), des Contrôleurs (JS), et des Vues (HTML). Les URLs des pages est bookmarkable.
  • Interaction immédiate avec des ressources REST exposées par le serveur.
  • Et la cerise sur le Kloug : Angular fournit même un framework de tests complet : TDD, mocks, tests de bout en bout...

Bref, la stack Angular est vraiment très complète !

Spring MVC

Le didacticiel d'Angular, bien qu'assez fourni, passe un peu rapidement sur l'interaction avec la partie serveur, et notamment la consommation de ressources REST. J'espère y remédier avec cet article, en démontrant son intégration avec Spring MVC/REST.

Spring MVC fait partie de la stack Spring, et propose depuis sa version 3.0 un support extensif du paradigme REST. Il est ainsi très facile de spécifier à quel type de requête HTTP répond un contrôleur (GET, POST, PUT, DELETE...), ainsi que le type des données qu'il consomme et/ou produit - par exemple, du JSON. La négociation de contenu est automatiquement gérée par Spring.

Dans notre exemple, nous produirons du contenu au format JSON, directement consommable par les modèles d'Angular ; la librairie Jackson se chargera de réaliser automatiquement le mapping objet/JSON. La combinaison de ces frameworks est d'une efficacité redoutable !

Application de démo

L'application de démonstation permet de lister, ajouter, supprimer, et voir le détail de tâches à réaliser ("to-do").

Voici quelques captures d'écrans (hé non, pas de Twitter Bootstrap cette fois !).

ngTodo_-_list_1.png ngTodo_-_new.png ngTodo_-_list_2.png ngTodo_-_detail.png

Côté serveur

Commençons par l'analyse de l'application côté serveur.

Une simple classe Todo sert de modèle :

public class Todo {
    private Long id;
    private String title;
    private String description;
}

Pour une raison de simplicité, les Todo sont stockés dans une Map directement dans le contrôleur - l'implémentation des couches de service et de persistence est laissée comme exercice au lecteur.

Les Todo sont exposés sous la forme d'une ressource REST de la façon suivante :

  • GET /todo : liste des Todo
  • GET /todo/{id}: récupération d'un Todo par son Id
  • PUT /todo : enregistrement d'une nouveau Todo
  • DELETE /todo/{id} : suppression d'un Todo par son Id

Le Contrôleur Spring MVC exposant la ressource est implémenté comme suit (je passe volontairement sur la configuration de la servlet et du contexte Spring - ils sont tout à fait standards) :

@Controller
public class TodoController {
 
    private static final AtomicLong todoIdGenerator = new AtomicLong(0);
    private static final ConcurrentSkipListMap<Long, Todo> todoRepository = new ConcurrentSkipListMap<Long, Todo>();
 
    @RequestMapping(value = "/todo", method = RequestMethod.GET, produces = "application/json")
    public @ResponseBody List<Todo> list() {
        return new ArrayList<Todo>(todoRepository.values());
    }
 
    @RequestMapping(value = "/todo/{id}", method = RequestMethod.GET, produces = "application/json")
    public @ResponseBody Todo getById(@PathVariable long id) {
        return todoRepository.get(id);
    }
 
    @RequestMapping(value = "/todo", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void create(@RequestBody Todo todo) {
        long id = todoIdGenerator.incrementAndGet();
        todo.setId(id);
        todoRepository.put(id, todo);
    }
 
    @RequestMapping(value = "/todo/{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable long id) {
        todoRepository.remove(id);
    }
 
}

Points intéressants :

  • Les méthodes list() et getById() renvoient de simples objets Java : le mapping JSON est automatiquement réalisé par la librairie Jackson. Cela améliore considérablement la testabilité du code du contrôleur !
  • Les méthodes ne produisant aucune donnée, comme create() et delete(), renvoient un code HTTP 204 "NO CONTENT"
  • Les annotations PathVariable et RequestBody permettent d'extraire et de convertir les paramètres des requêtes HTTP ; l'annotation ResponseBody permet au contraire de convertir puis de placer l'objet renvoyé dans le corps de la réponse HTTP.

Simple et efficace.

Mais voyons maintenant comment cette ressource est consommée côté client.

Côté client

Angular respecte le bon vieux pattern MVC 2. C'est donc sans surprise qu'on retrouve les concepts de Front Controller, Contrôleur, Vue, et Modèle. La communication avec le serveur, quant à elle, est déléguée à un service Todo spécifique, que je vous présenterai plus loin.

Pour faciliter le développement et la maintenance de l'application, le Front Controller, les Contrôleurs et les Services sont isolés dans 3 fichiers distincts.
La page hôte est donc configurée comme suit :

<!doctype html>
<html>
<head>
    <title>Todo.ng</title>
    <meta charset="UTF-8">
    <link href="css/style.css" rel="stylesheet"/>
    <script src="js/libs/angular-1.0.1.js"></script>
    <script src="js/libs/angular-resource-1.0.1.js"></script>
    <script src="js/app/application.js"></script>
    <script src="js/app/services.js"></script>
    <script src="js/app/controllers.js"></script>
</head>
<body>
    ...
</body>
</html>
Le Front controller

Le rôle d'un Front Controller est celui d'un guichet d'accueil : il accepte toutes les requêtes, mais ne les traite pas lui-même ; il délègue au contraire chaque requête à un Contrôleur spécifique, sélectionné en fonction d'un certain critère - le plus souvent, l'URL de la ressource demandée.

Comme nous sommes ici dans une application de type single-page, il n'existe qu'une seule URL : celle de la page HTML embarquant l'application. Pour différencier les différents états de l'application, Angular utilise donc les "ancres" HTML, qui peuvent varier librement au sein de l'URL :

http://company.com/app/document.html          // URL du document hôte
http://company.com/app/document.html#etat1    // Avec ancre "etat1"
http://company.com/app/document.html#etat2    // Avec ancre "etat2"

Pour notre application, les mappings sont les suivants (les chemins doivent commencer par un slash pour qu'Angular les reconnaisse). Vous pouvez les reconnaître sur les captures d'écrans vues plus haut.

  • http://<application>/#/todo/list : liste des Todo
  • http://<application>/#/todo/new : saisie d'un nouveau Todo
  • http://<application>/#/todo/{id} : détail du Todo d'identifiant {id}

Nous devons maintenant associer à chaque chemin un Contrôleur et une Vue. Angular utilise pour cela un routeProvider, configurable grâce à une API fluide :

angular.module('todoApp', ['todoService']).
    config(['$routeProvider', function ($routeProvider) {
        $routeProvider.
            when('/todo/list', {templateUrl:'views/todo-list.html',   controller:TodoListController}).
            when('/todo/new',  {templateUrl:'views/todo-new.html',    controller:TodoNewController}).
            when('/todo/:id',  {templateUrl:'views/todo-detail.html', controller:TodoDetailController}).
            otherwise({redirectTo:'/todo/list'});
}]);

Deux petits réglages restent à effectuer pour que l'application puisse prendre vie : l'associer à la page hôte à l'aide de la propriété ng-app, et indiquer l'emplacement où les vues seront affichées avec la propriété ng-view.

<!doctype html>
<html ng-app="todoApp">
<head>
    <title>Todo.ng</title>
    <meta charset="UTF-8">
    <link href="css/style.css" rel="stylesheet"/>
    <script src="js/libs/angular-1.0.1.js"></script>
    <script src="js/libs/angular-resource-1.0.1.js"></script>
    <script src="js/app/application.js"></script>
    <script src="js/app/services.js"></script>
    <script src="js/app/controllers.js"></script>
</head>
<body>
   <div ng-view></div>
</body>
</html>

Nous pouvons maintenant commencer le développement des contrôleurs et des vues.

Contrôleur et Vue pour l'écran de liste

Contrairement à d'autres frameworks MVC / JS, les contrôleurs Angular sont de simples fonctions Javascript, très facilement testables. S'ils dépendent de certains services tiers ($location, etc.), il leur suffit de les demander en paramètre ; le mécanisme d'injection de dépendances d'Angular se chargera de les leur fournir au runtime.

Un contrôleur possède un certain nombre de propriétés qui forment son modèle, ainsi que de méthodes permettant de les manipuler.
Pour éviter les interférences inter-contrôleurs et bénéficier du mécanisme de binding bidirectionnel avec la vue, ces propriétés et méthodes ne sont pas déclarées directement dans le contrôleur, mais sur l'objet $scope qui lui est passé en paramètre.

Prenons l'exemple (simplifié) du contrôleur TodoListController. Son contexte contient la liste des Todo à afficher à l'écran, ainsi qu'une méthode permettant de naviguer vers la page de saisie d'un nouveau Todo.

function TodoListController($scope, $location, Todo) {
 
    // List of Todos, loaded by the Todo service
    $scope.todos = Todo.query();
 
    // Navigation to the "New Todo" page
    $scope.gotoTodoNewPage = function () {
        $location.path("/todo/new")
    };
}

(Note : pour naviguer vers la page de saisie d'un Todo, un simple lien aurait suffi, comme pour naviguer vers le détail d'un Todo ; mais j'ai utilisé un bouton afin de présenter l'appel d'une méthode sur le contrôleur.)

La vue associée est un simple fichier HTML, dont certaines balises sont dotées de propriétés Angular (ng-*) permettant de lier leur contenu au modèle du contrôleur.

<div id="todoList">
 
    <h2>Liste des todos</h2>
 
    <ul>
        <li ng-repeat="todo in todos">
            <a href="#/todo/{{todo.id}}">{{todo.title}}</a> :
            {{todo.description}}
        </li>
    </ul>
 
    <button ng-click="gotoTodoNewPage()">Ajouter</button>
 
</div>

Notez l'itération sur la liste des Todo, ainsi que l'utilisation de double accolades pour parcourir le graphe du modèle.

Services REST

Le dernier point qu'il nous reste à voir est l'intégration avec les services REST exposés par le serveur.

Angular propose un modèle inspiré du pattern Active Record. Un objet de type $resource représente une ressource REST exposée à une certaine URI. Les opérations de création, suppression, requêtage sont exposées sous la forme de méthodes prédéfinies.

  • query() : récupère tous les objets par une requête GET
  • get() : récupère 1 objet à l'aide d'une requête HTTP GET, en passant l'identifiant de la ressource
  • save() : crée une nouvelle ressource grâce à une requête HTTP POST
  • remove() et delete() : deux méthodes équivalentes, qui suppriment une ressource via une requête HTTP DELETE contenant son identifiant.

Il est toutefois possible de modifier les réglages de ces méthodes, ou d'en fournir de nouvelles.

Voici la configuration de notre ressource Todo :

angular.module('todoService', ['ngResource']).
    factory('Todo', function ($resource) {
        return $resource('rest/todo/:id', {}, {
            'save': {method:'PUT'}
        });
    });

Les points importants sont :

  • L'URI de la ressource, sous forme de template : rest/todo/:id. La partie "rest/" correspond au mapping de la servlet Spring, et la fin, "todo/:id", au pattern des mappings REST vus plus haut.
  • La modification du paramétrage de de la méthode save, afin qu'elle produise une requête HTTP de type PUT au lieu de POST.

Grâce à cette simple déclaration, toute la communication client/serveur en REST est automatiquement prise en charge !

Voyons comment cette ressource est utilisée dans les contrôleurs :

//TodoListController
function TodoListController($scope, $location, Todo) {
    // Retrieve all Todo
    $scope.todos = Todo.query();
    ...
}
 
// TodoDetailController
function TodoDetailController($scope, $routeParams, Todo) {
    // Load a Todo by id (taken from the path)
    $scope.todo = Todo.get({id:$routeParams.id});
    ...
}
 
// TodoNewController
function TodoNewController($scope, $location, Todo) {
    // Save the new Todo
    $scope.submit = function () {
        Todo.save($scope.todo, function (todo) {
            $location.path('/');
        });
    };
    ...
}

Conclusion

Au milieu de la jungle des nouveaux frameworks Javascript, Angular.js se distingue par sa large palette de fonctionnalités, allant du binding automatique à la gestion des ressources REST, en passant par l'architecture MVC2 et le templating en pur HTML.
Son développement par Google est un gage (certes pas absolu) de pérénnité et de qualité, et le caractère non-intruif du framework limite le risque d'enfermement technologique.

Couplé à Spring MVC et Jackson côté serveur, il offre un modèle de développement léger et productif, adapté au développement d'applications de type single-page.

Si j'étais vous, je garderais un oeil sur ce framework !

Ressources

Je vous invite consulter le code source de l'application sur GitHub. Clonez-le, jouez avec !

Et pour apprendre...

Et un article de mon camarade Adrien Lecharpentier sur les petites subtilités de Javascript sur lesquelles vous pourriez buter lors de l'utilisation d'Angular :


Commentaires

1. Le mardi 7 août 2012, 09:21 par fcamblor

Article sympa : je ne connaissais pas Angular, ça me permet de le découvrir rapidement.

J'ai quelques remarques :
- Coté SpringMVC, le produces=application/json n'est _normalement_ pas nécessaire si la requête qui part du client possède un header "Accept: application/json". Par défaut, si on ne positionne pas explicitement de "produces", Spring MVC se sert de ce header pour "produire" automatiquement le bon format en fonction de ce que le client demande : ça offre une souplesse pour les clients qui peut être appréciable :)
- J'ai hurlé lorsque j'ai vu que tu utilisais un PUT pour créer une nouvelle ressource : le PUT en REST doit être idempotent. J'ai compris en lisant la suite que c'était voulu mais un disclaimer serait peut-être bienvenu ;)
- Je trouve étonnant de la part de google, d'utiliser un prefixe "non standard" en ng-* pour définir les traitements spécifiques angular. Je me serais attendu à un data-ng-* qui permettait de rendre html5 compatible les templates
- Ton service REST de création ne communique jamais au client l'identifiant du Todo qui vient d'être créé : c'est généralement bien utile pour le client (pour rediriger sur la page de détail du Todo créé par exemple)
- Je reste sur ma faim sur la partie binding bidirectionnel qui n'est pas du tout illustré dans l'article (ni dans l'application github) : lorsqu'on rajoute un nouveau Todo à la liste des todo dans le scope, l'UI se met à jour toute seule sans qu'on ait rien à faire ?
Ca aurait été intéressant d'en parler un peu plus car c'est quelque chose qui me manque aujourd'hui dans Backbone ;)

En tous les cas, entrée en matière plutôt sympa ! :)

2. Le mardi 7 août 2012, 10:22 par Thomas Recloux

Frédéric : Normalement je pense que les attributs en ng-* ne se retrouvent pas dans le DOM donc ce n'est pas "sale", à mon humble avis :)

3. Le mardi 7 août 2012, 13:39 par joseph

Arg, prévisualiser m'a tuer (mon post)...

Quoiqu'il en soit, merci bcp pour cet article, c'est rare de voir du server side dans les blogs JS.

Deux questions principales me viennent à l'esprit:
- pas de notion de session dans l'application présentée. Je serai curieux de voir les approches recommandées: as tu des pistes?
- quid de la rapidité et de l'aisance de développement, par rapport à du wicket par exemple ? Cela te semble t il plus lent, plus riche, plus naturel ?

Au plaisir de te lire, si jamais je réussis à franchir la barrière du prévisualiser !

4. Le mercredi 8 août 2012, 13:45 par Cyril Lakech

Sympa cet angular.js

Ca donne quoi du côté indexation des moteurs de recherche ?

+1 pour le put non idempotent , le put et le get doivent être symétriques je pense.

Merci pour la decouverte

5. Le mercredi 8 août 2012, 14:36 par fcamblor

@Thomas : Je pense en effet qu'ils ne se retrouvent pas dans le DOM, mais dans une approche de maquettage par un designer (par exemple), c'est vraiment pas quelque chose que je trouve génial comme approche (je faisais le même reproche à wicket).
On peut faire une étape 1/ le designer design, 2/ le codeur code à partir de la maquette ... mais on ne peut pas revenir à l'étape 1 sans que le designer n'enlève les attributs incompatibles avec son outil de designing (là-dessus, feu flex était imbattable)
C'est un inconvénient qui est négligeable lorsque le dev s'occupe de l'ergo du site, mais ça n'est pas tout le temps le cas :)

@joseph : pour la première question, je pense que l'idée est de plus en plus de faire du stateless, donc de mettre le moins de choses en sessions (REST encourage pas mal cela à coup d'urls facilement bookmarkables). Cela implique de généralement mettre une politique de cache coté serveur, afin de limiter les appels les plus récurrents (à la bdd notamment).
Spring 3.1 aide beaucoup sur cet aspect grâce à son annotation @Cacheable.
On peut également imaginer l'utilisation d'une base NoSQL qui présentera les données de manière très proche des écrans (quitte à redonder des données).

6. Le jeudi 9 août 2012, 07:11 par joseph

@fcamblor

Je veux bien faire du stateless, mais il y a quand même un paquet d'appli web qui ont besoin d'état, ou, plus exactement, d'identification... D'ailleurs c'est même de plus en plus le cas je trouve: il n'y a presque plus d'appli utilisables sans identification.

Du coup comment faire? Balader un jsessionid partout dans les url? Faire ça par des cookies?

7. Le lundi 13 août 2012, 00:09 par doanduyhai

Super intro à Angular.js, ça me donne envie de tester!

@joseph pour faire du State full côté serveur tu peux mettre Spring Security just pour récupérer le token d'identification du user connecté (pas besoin de login/password, anonymous role suffit) et tu combines avec @cacheable de Spring pour stocker son état (clés du cache = token user par ex)

8. Le jeudi 16 août 2012, 12:43 par dnr

Petit retour d'expérience : on utilise AngularJS avec Grails et JSON sur une appli business critical en interne. Et on est parti pour un extranet avec les mêmes technos.

On a commencé avec leur version RC en comptant sur le fait qu'ils passeraient en version finale, ce qui est le cas. Je ne me vois plus travailler autrement qu'avec Angular (ou un autre) pour des applications web riches... On a bien eu quelques petites surprises, principalement dues à des modifications d'API ou de comportement en RC (ce qui est normal).

- La courbe d'apprentissage est raisonnable
- Bonne testabilté, même si de ce côté ce n'est pas hyper robuste (parfois besoin de redémarrer le serveur de test, la moindre erreur peut provoquer un msg d'erreur incompréhensible)
- La doc bien faite (quoique ça manque de cookbooks AMHA)
- Les développeurs sont réactifs, prennent la peine de communiquer
- Le fait que cela provienne de Google est de bonne augure pour la pérénité du framework

Le seul truc qui me chiffonne, c'est que "par défaut", tout le templating arrive sur le client. Il n'est pas possible d'en cacher des parties comme on le fait classiquement côté serveur en fonction d'une autorisation. Il y a moyen de contourner cela mais ce n'est pas aussi confortable qu'un "if" côté serveur.

@fcamblor "lorsqu'on rajoute un nouveau Todo à la liste des todo dans le scope, l'UI se met à jour toute seule sans qu'on ait rien à faire" -> oui bien sûr, c'est tout la beauté de la chose. Tu peux avoir des parties du UI qui s'affichent ou se masquent sans rien faire en fonction d'un changement du modèle dans le scope.

9. Le dimanche 19 août 2012, 22:24 par fcamblor

@joseph : Même réponse que doanduyhai, sauf que je fais ça à la main (le seul état que je stocke en session, c'est le token du user connecté... si je voulais vraiment être complètement stateless, je pourrais le mettre dans un cookie car l'info est "petite")... et après, c'est un jeu de compromis entre faire une requête ou la cacher avec un @Cacheable

@dnr C'est cool si ça fonctionne bien ainsi. Par contre, j'ai du mal à comprendre comment angular fait sachant que dans l'exemple, les attributs dans le scope sont accédés "en direct" (ie sans passer par une fonction/méthode qui permettrait alors de "notifier" des observers pour mettre a jour l'UI).

10. Le mardi 21 août 2012, 08:37 par Seb

Bien content que AngularJS te plaise, j'y consacre actuellement une série d'articles (voir http://www.itaware.eu/tag/angularjs...) qui aideront tous ceux qui veulent s'y mettre.
Pour ce qui est du préfixe ng-* sachez que vous pouvez en mettre d'autres notamment pour avoir la compatibilité avec XHTML (http://www.itaware.eu/2012/06/25/an...)

11. Le dimanche 16 septembre 2012, 23:44 par Gregory Boissinot

Concernant l’usage du JavaScript côté serveur, cela n’est pas nécessairement une absurdité mais uniquement peu outillé d’un point de vue d’administration. Mais si c’était le cas, cela serait extrêmement performant en pouvant, par exemple, traiter directement du JSON côté serveur sans le coût du unmarshalling/marshaling.

Pour le serveur, il peut être envisagé de se rapprocher d’un serveur RESTful. Dans ce cas, la création d’un élément sans connaître au préalable son adresse, est effectuée à travers une méthode de type POST. En réponse, le serveur renvoie une réponse HTTP avec un status CREATED (201) et un header Location (avec pour valeur l’URI de la nouvelle ressource).
Mais la question que je pose est : quel est le niveau de support de AngularJS dans la gestion du code de retour d’une réponse HTTP (avec gestion des 404, 500, …)?
Y-a-t-il, par exemple, des traitement sur étagère ou cela doit être géré manuellement?

Je me permets également de mettre en évidence qu’une architecture REST n’est pas nécessairement plus simple à concevoir et à son lot d’inconvénients aussi.

Ensuite, plus globalement, il existe de nombreux framework client-side offrant différents niveaux d’industrialisation du développeur. Pour ma part, je favorise Sencha EXTJS 4. Il s'agit d'un framework complet, offrant également le paradigme MVC, mais aussi de nombreux outillage de bout en bout (tests, packaging, déploiement, IDE drag&drop, …).
Dans tous les cas, il est intéressant de se poser la question, est-ce que ce type d’architecture est viable chez nos clients (quels sont les cas d’utilisation)?
Parmi les éléments de réponse, un point qui peut être important à prendre en compte dans le choix de ton framework de front, est le niveau de réutilisabilité de ton application en version mobile (besoin croissant de faire une même application en desktop et en mobile)

Et pour finir, un critère à ne pas négliger, est le fait que cela nécessite des développeurs avancés en Java maîtrisant les architectures REST et des développeurs avancés maîtrisant plutôt bien la partie cliente basée sur la stack JavaScript (même si il faut dire que AngularJS comme les autres framework client-side, cachent les détails de JavaScript).
Ainsi, pour REST, quel est le niveau de skills Java du développeur à demander ? De même pour la partie client, quel est le niveau de skills du développeur à avoir?

12. Le lundi 5 novembre 2012, 17:33 par mbo

Merci pour cet article, les articles sur les frameworks MVC coté navigateur faisant trop souvent l'impasse sur le coté serveur.

@fcamblor cf. http://stackoverflow.com/questions/... Misko Hevery, l'un des promoteurs d'angularjs, explique le fonctionnement des liaisons entre les objets JavaScript et les vues, ainsi que les avantages et les inconvénients de cette façon de faire.

La philosophie du framework est de vérifier 'constamment' si les objets ont changés de valeur, et de répercuter les changements sur les vues. C'est à ma connaissance le seul framework à ne pas nécessiter de getter/setter.

Pour ce qui est des attributs ng-*, comme cela a déjà été dit, il est possible de les remplacer par data-ng-* (j'ai vérifié) ou encore class="data-ng-*" (je n'ai pas vérifié), si on veut un document HTML5 valide. A ce sujet, le framework nécessite au moins IE8 (attention car IE8 se comporte par défaut en IE7 pour des sites intranet, il faut donc configurer proprement IE8, ou mettre IE=Edge dans l'entête HTTP ou HTML).

13. Le mercredi 10 février 2016, 12:07 par Guillaume

Excellent exemple. Merci !

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.