102 votes

Comment passer un paramètre à un commandLink à l'intérieur d'un datatable ?

J'utilise Primefaces dans une application JSF 2. J'ai un <p:dataTable> et au lieu de sélectionner des lignes, je veux que l'utilisateur puisse exécuter directement diverses actions sur des lignes individuelles. Pour cela, j'ai plusieurs <p:commandLink> dans la dernière colonne.

Mon problème : comment puis-je transmettre un ID de ligne à l'action lancée par le lien de commande afin de savoir sur quelle ligne agir ? J'ai essayé d'utiliser un <f:attribute> :

<p:commandLink actionListener="#{FilterList.insert}" value="insert" ajax="false">
    <f:attribute name="id" value="#{f.id}" />
</p:commandLink>

Mais cela donne toujours 0 - apparemment la variable de ligne f n'est pas disponible lorsque l'attribut est rendu (il fonctionne lorsque j'utilise une valeur fixe).

Quelqu'un a-t-il une solution alternative ?

215voto

BalusC Points 498232

Quant à la cause, le <f:attribute> est spécifique au composant lui-même (rempli pendant la construction de la vue), et non à la ligne itérée (remplie pendant le rendu de la vue).

Il existe plusieurs façons de satisfaire à cette exigence.

  1. Utilisez <f:param> à la place. Il ajoute un paramètre de requête.

    <h:commandLink action="#{bean.insert}" value="insert">
        <f:param name="id" value="#{item.id}" />
    </h:commandLink>

    Si votre bean est "request scoped", laissez JSF le définir par @ManagedProperty

    @ManagedProperty(value="#{param.id}")
    private Long id; // +setter

    Si votre haricot a une portée plus large ou si vous voulez une validation/conversion plus fine, utilisez <f:viewParam> sur la vue cible, voir aussi f:viewParam vs @ManagedProperty :

    <f:viewParam name="id" value="#{bean.id}" required="true" />

    D'une manière ou d'une autre, cela présente l'avantage que le modèle de données ne doit pas nécessairement être préservé lors de l'envoi du formulaire (dans le cas où votre bean a une portée de requête).


  2. Utilisez <f:setPropertyActionListener> à la place. L'avantage est que cela supprime la nécessité d'accéder à la carte des paramètres de la requête lorsque le bean a une portée plus large que celle de la requête.

    <h:commandLink action="#{bean.insert}" value="insert">
        <f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" />
    </h:commandLink>

    En combinaison avec

    private Long id; // +setter

    Il sera juste disponible par propriété id dans la méthode d'action. Cela nécessite seulement que le modèle de données soit préservé pour la demande de soumission du formulaire. Le mieux est de mettre le bean dans le scope de la vue en @ViewScoped .


  3. Si votre servletcontainer supporte Servlet 3.0 / EL 2.2, il suffit de le passer comme argument de méthode. Cela nécessite également que le modèle de données soit préservé pour la demande de soumission du formulaire. Le mieux est de placer le bean dans la portée de la vue par @ViewScoped .

    <h:commandLink action="#{bean.insert(item.id)}" value="insert" />

    En combinaison avec :

    public void insert(Long id) {
        // ...
    }

    Vous pouvez même transmettre l'objet entier de l'article :

    <h:commandLink action="#{bean.insert(item)}" value="insert" />

    avec :

    public void insert(Item item) {
        // ...
    }

    Sur les conteneurs Servlet 2.5, cela est également possible si vous fournissez une implémentation EL qui le prend en charge, comme JBoss EL. Pour plus de détails sur la configuration, voir cette réponse .


  4. Lier la valeur de la table de données à DataModel<E> qui, à son tour, enveloppe les éléments.

    <h:dataTable value="#{bean.model}" var="item">

    avec

    private transient DataModel<Item> model;
    
    public DataModel<Item> getModel() {
        if (model == null) {
            model = new ListDataModel<Item>(items);
        }
        return model;
    }

    (ce qui en fait transient et son instanciation paresseuse dans le getter est obligatoire lorsque vous l'utilisez sur une vue ou un bean à portée de session puisque DataModel ne met pas en œuvre Serializable )

    Ensuite, vous pourrez accéder à la rangée en cours par DataModel#getRowData() sans rien transmettre (JSF détermine la ligne sur la base du nom du paramètre de requête du lien/bouton de commande cliqué).

    public void insert() {
        Item item = model.getRowData();
        Long id = item.getId();
        // ...
    }

    Cela nécessite également que le modèle de données soit préservé pour la demande de soumission du formulaire. Le mieux est de mettre le bean dans le scope de la vue en @ViewScoped .


  5. Vous pouvez utiliser Application#evaluateExpressionGet() pour évaluer de manière programmatique l'actuel #{item} .

    public void insert() {
        FacesContext context = FacesContext.getCurrentInstance();
        Item item = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
        Long id = item.getId();
        // ...
    }

Le choix de la voie à suivre dépend des exigences fonctionnelles et du fait que l'une ou l'autre offre plus d'avantages pour d'autres objectifs. Personnellement, j'opterais pour la solution n° 3 ou, si vous souhaitez également prendre en charge les conteneurs de servlets 2.5, pour la solution n° 2.

1 votes

+1, bien que ma préférence aille au n°2 (si la 2.5 doit être supportée).

0 votes

Merci pour cette réponse exhaustive. Malheureusement, je dois signaler que le numéro 1 est la seule chose qui fonctionne dans une table de données primefaces filtrée (ce qui est exactement le scénario pour lequel j'en ai besoin). Toutes les autres ne fonctionnent que sur une table non filtrée. Je vois cela plus comme un bug dans primefaces que dans votre réponse, cependant.

0 votes

La requête ou la vue du bean est-elle scopée ?

11voto

Bozho Points 273663

Dans JSF 1.2, cela était fait par <f:setPropertyActionListener> (au sein de la composante de commande). Dans JSF 2.0 (EL 2.2 pour être précis, merci à BalusC) il est possible de le faire comme ceci : action="${filterList.insert(f.id)}

6 votes

Cette fonctionnalité n'est pas spécifique à JSF 2.0 (qui peut fonctionner seul dans des conteneurs Servlet 2.5), mais à EL 2.2 (qui fait partie de Servlet 3.0).

11voto

Arfan J Points 31

Dans ma page de vue :

<p:dataTable  ...>
<p:column>
<p:commandLink actionListener="#{inquirySOController.viewDetail}" 
               process="@this" update=":mainform:dialog_content"
           oncomplete="dlg2.show()">
    <h:graphicImage library="images" name="view.png"/>
    <f:param name="trxNo" value="#{item.map['trxNo']}"/>
</p:commandLink>
</p:column>
</p:dataTable>

haricot de soutien

 public void viewDetail(ActionEvent e) {

    String trxNo = getFacesContext().getRequestParameterMap().get("trxNo");

    for (DTO item : list) {
        if (item.get("trxNo").toString().equals(trxNo)) {
            System.out.println(trxNo);
            setSelectedItem(item);
            break;
        }
    }
}

0voto

Zhuinden Points 3074

Merci à ce site par Mkyong la seule solution qui en fait a fonctionné pour nous pour passer un paramètre était le suivant

<h:commandLink action="#{user.editAction}">
    <f:param name="myId" value="#{param.id}" />
</h:commandLink>

avec

public String editAction() {

  Map<String,String> params = 
            FacesContext.getExternalContext().getRequestParameterMap();
  String idString = params.get("myId");
  long id = Long.parseLong(idString);
  ...
}

Techniquement, vous ne pouvez pas passer à la méthode elle-même directement, mais à l'option JSF request parameter map .

1 votes

Votre problème n'est pas le même que celui posé ici. Vous souhaitez conserver les paramètres de requête de #{param} pour les requêtes suivantes, et non pour passer un paramètre arbitraire. Vos questions et réponses sont couvertes par stackoverflow.com/questions/17734230

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X