De l'utilisation d'AngularJS avec un formulaire qui sera soumis au serveur

Le framework front-end JavaScript MVC AngularJS a l'avantage d'être pensé de façon à pouvoir être utilisé uniquement sur un module donné, au lieu d'englober la totalité de l'application sur laquelle il est utilisé. Il est donc très pratique de s'en servir pour renforcer un élément complexe dans votre projet (comme un moteur de recherche devant interfacer une API JSON, par exemple). Néanmoins, il est parfois nécessaire de ruser un peu pour contourner son comportement lorsque le formulaire HTML que vous alimentez joyeusement à l'aide d'AngularJS est tout de même destiné à être envoyé côté serveur.

Tout d'abord, il faut savoir qu'AngularJS bloque automatiquement la soumission "classique" d'un formulaire sous son joug , sauf si celui-ci dispose d'un attribut action. Mais qu'en est-il si vous souhaitez déléguer la gestion du formulaire à AngularJS sous certaines conditions, ou plutôt jusqu'à un certain point ? Je pense notamment à la validation, un point que le framework gère très bien, mais pour lequel il peut être sympathique d'avoir un moyen de lui demander de nous rendre la main quand sa tâche est accomplie.

Il y a plusieurs solutions envisageables ; de mon côté, je privilégie la suivante, qui est limpide et facilement réutilisable. Voici la balise d'ouverture du formulaire :

<form method="POST" data-target="/my-action.html" data-ng-submit="submit()">

Notez l'attribut personnalisé data-target qui vient remplacer l'action, ainsi que le listener pour l'évènement de soumission. Voici la méthode appelée par ce dernier, qui pour notre exemple se situe directement dans notre contrôleur :

$scope.submit = function() {
var $form = $element.find('form'); // à ajuster
if (/* insérez ici vos conditions */) {
$form.attr('action', $form.data('target')).submit(); // le formulaire sera désormais soumis de manière classique
}
};

Simplissime, non ? D'aucuns souligneront que procéder ainsi équivaut à un viol potentiel (pour toi, Google) du principe de base d'AngularJS qui interdit toute manipulation du DOM dans un contrôleur. À mes yeux, il s'agit plus d'un tour de passe-passe qu'autre chose, mais c'est vous qui voyez.

...d'autant que transformer ce code en une directive ne représente pas un obstacle insurmontable.

moi du Futur

Un autre point qui peut être surprenant lors des premiers pas avec AngularJS concerne la façon dont celui-ci remplit les select. En effet, aucun contrôle n'est possible sur l'attribut value des éléments option générés par la directive correspondante, à savoir ngOptions. Plutôt que de chercher un chemin de traverse compliqué, faisons preuve d'astuce :

<!-- Ne faites pas : -->
<select name="my_key" ng-model="myModel" ng-options="select o.label for o in myOptions"></select>

<!-- Mais faites plutôt : -->
<select ng-model="myModel" ng-options="select o.label for o in myOptions"></select>
<input type="hidden" name="my_key" value="{{ myModel }}" />

Ceci vous permet de gérer indépendamment le select et la valeur correspondante qui sera envoyée au serveur.