ActionListener
Utilisez actionListener
si vous voulez avoir un crochet avant l'action commerciale réelle a été exécutée, par exemple pour l'enregistrer, et/ou pour définir une propriété supplémentaire (en <f:setPropertyActionListener>
), et/ou pour avoir accès au composant qui a invoqué l'action (qui est disponible par ActionEvent
argument). Donc, purement à des fins de préparation avant que la véritable action commerciale ne soit invoquée.
Le site actionListener
a par défaut la signature suivante :
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
Et il est censé être déclaré comme suit, sans parenthèses de méthode :
<h:commandXxx ... actionListener="#{bean.actionListener}" />
Notez que vous ne pouvez pas passer supplémentaire par EL 2.2. Vous pouvez toutefois remplacer l'option ActionEvent
en passant et en spécifiant un ou plusieurs arguments personnalisés. Les exemples suivants sont valables :
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
Notez l'importance des parenthèses dans l'expression de la méthode sans argument. S'ils étaient absents, JSF s'attendrait toujours à ce qu'une méthode avec le paramètre ActionEvent
argument.
Si vous êtes sous EL 2.2+, vous pouvez déclarer plusieurs méthodes d'écoute d'action via <f:actionListener binding>
.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
Notez l'importance des parenthèses dans l'expression binding
attribut. S'il n'y en avait pas, EL enverrait un message d'erreur de type javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
parce que le binding
est interprété par défaut comme une expression de valeur, et non comme une expression de méthode. L'ajout de parenthèses de style EL 2.2+ transforme de manière transparente une expression de valeur en expression de méthode. Voir également a.o. Pourquoi suis-je capable de lier <f:actionListener> à une méthode arbitraire si elle n'est pas supportée par JSF ?
action
Utilisez action
si vous souhaitez exécuter une action commerciale et, le cas échéant, gérer la navigation. Le site action
peut (donc, pas obligatoirement) retourner une méthode String
qui sera utilisé comme résultat du cas de navigation (la vue cible). Une valeur de retour de null
ou void
lui permettra de revenir à la même page et de conserver l'étendue de la vue actuelle. Une valeur de retour d'une chaîne vide ou du même identifiant de vue permettra également de retourner à la même page, mais recréera l'étendue de la vue et détruira ainsi tous les beans actuellement actifs et, le cas échéant, les recréera.
Le site action
peut être n'importe quelle méthode valide MethodExpression
ainsi que ceux qui utilisent des arguments EL 2.2, comme ci-dessous :
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
Avec cette méthode :
public void edit(Item item) {
// ...
}
Notez que lorsque votre méthode d'action ne renvoie qu'une chaîne de caractères, vous pouvez également spécifier exactement cette chaîne de caractères dans la balise action
attribut. C'est donc totalement maladroit :
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
Avec cette méthode insensée qui renvoie une chaîne codée en dur :
public String goToNextpage() {
return "nextpage";
}
Au lieu de cela, il suffit de mettre cette chaîne codée en dur directement dans l'attribut :
<h:commandLink value="Go to next page" action="nextpage" />
Veuillez noter que cela indique à son tour une mauvaise conception : la navigation par POST. Cette méthode n'est pas conviviale pour l'utilisateur ni pour le référencement. Tout ceci est expliqué dans Quand dois-je utiliser h:outputLink au lieu de h:commandLink ? et est censé être résolu comme
<h:link value="Go to next page" outcome="nextpage" />
Voir aussi Comment naviguer en JSF ? Comment faire en sorte que l'URL reflète la page actuelle (et non la précédente) ? .
f:ajax listener
Depuis JSF 2.x, il y a une troisième voie, le <f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
Le site ajaxListener
a par défaut la signature suivante :
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
À Mojarra, le AjaxBehaviorEvent
est facultatif, le paramètre ci-dessous fonctionne aussi bien.
public void ajaxListener() {
// ...
}
Mais dans MyFaces, cela déclencherait un MethodNotFoundException
. Below fonctionne dans les deux implémentations de JSF lorsque vous souhaitez omettre l'argument.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
Les écouteurs Ajax ne sont pas vraiment utiles sur les composants de commande. Ils sont plus utiles sur les composants de saisie et de sélection <h:inputXxx>
/ <h:selectXxx>
. Dans les composants de commande, il suffit de s'en tenir à action
et/ou actionListener
pour plus de clarté et un meilleur code auto-documenté. De plus, comme actionListener
le f:ajax listener
ne permet pas de renvoyer un résultat de navigation.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
Pour une explication sur execute
et render
attributs, rendez-vous sur Comprendre les attributs PrimeFaces process/update et JSF f:ajax execute/render .
Ordre d'invocation
Le site actionListener
sont toujours invoqués avant le site action
dans l'ordre où ils ont été déclarés dans la vue et attachés au composant. Le site f:ajax listener
est toujours invoqué avant n'importe quel écouteur d'action. Ainsi, l'exemple suivant :
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
Les méthodes seront invoquées dans l'ordre suivant :
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
Traitement des exceptions
Le site actionListener
soutient une exception spéciale : AbortProcessingException
. Si cette exception est levée à partir d'un actionListener
JSF ignorera tous les autres écouteurs d'action et la méthode d'action et rendra directement la réponse. Vous ne verrez pas de page d'erreur/exception, mais JSF l'enregistrera. Cette opération sera également effectuée implicitement chaque fois qu'une autre exception sera levée par une méthode d'action. actionListener
. Ainsi, si vous avez l'intention de bloquer la page par une page d'erreur à la suite d'une exception commerciale, vous devez absolument effectuer le travail dans la section action
méthode.
Si la seule raison d'utiliser un actionListener
est d'avoir un void
qui revient à la même page, alors c'est une mauvaise méthode. Le site action
peuvent parfaitement retourner aussi void
contrairement à ce que certains IDEs vous laissent croire via la validation EL. Notez que le Vitrine PrimeFaces Les exemples sont truffés de ce genre de actionListener
sur toute la place. C'est vraiment mauvais. N'utilisez pas ça comme une excuse pour le faire vous aussi.
Dans les requêtes ajax, cependant, un gestionnaire d'exception spécial est nécessaire. Ceci indépendamment du fait que vous utilisiez listener
l'attribut de <f:ajax>
ou pas. Pour une explication et un exemple, rendez-vous sur Traitement des exceptions dans les requêtes JSF ajax .