Comment passer une ligne sélectionnée à commandLink dans dataTable ou ui: repeat?

j'utilise des Primefaces dans une application JSF 2. J'ai un <p:dataTable> , et au lieu de sélectionner des lignes, je veux que l'utilisateur soit capable d'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 passer un ID de ligne à l'action commencée par le lien de commande pour que je sache sur quelle ligne agir? J'ai essayé d'utiliser un <f:attribute> :

<p:dataTable value="#{bean.items}" var="item">
    ...
    <p:column>
        <p:commandLink actionListener="#{bean.insert}" value="insert">
            <f:attribute name="id" value="#{item.id}" />
        </p:commandLink>
    </p:column>
</p:dataTable>

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

Quelqu'un a une solution alternative?

90
demandé sur BalusC 2011-02-14 19:17:51

4 réponses

quant à la cause, le <f:attribute> est spécifique au composant lui-même (peuplé pendant le temps de construction de la vue), pas à la ligne itérée (peuplée pendant le temps de rendu de la vue).

il y a plusieurs façons de satisfaire à cette exigence.

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

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

    si votre haricot est demandé scoped, laissez JSF le définir par @ManagedProperty

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

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

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

    de toute façon, cela a l'avantage que le datamodel n'a pas nécessairement besoin d'être préservé pour le formulaire Soumettre (pour le cas où votre haricot est demandé scoped).


  2. utilisez <f:setPropertyActionListener> à la place. L'avantage est que cela supprime la nécessité d'accéder à la table des paramètres request 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 la propriété id dans la méthode d'action. Ce exige seulement que le datamodel soit préservé pour le formulaire soumettre la demande. Le mieux est de mettre le haricot dans la portée de vue par @ViewScoped .


  3. si votre servletcontainer supporte Servlet 3.0 / EL 2.2, alors passez-le simplement comme argument de méthode. Cela exige également que le datamodel soit préservé pour le formulaire soumettre la demande. Le mieux est de mettre le haricot dans la portée de vue par @ViewScoped .

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

    en combinaison avec:

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

    vous pouvez même passer l'objet de l'article entier:

    <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 supporte cela, comme JBoss EL. Pour plus de détails sur la configuration, voir cette réponse .


  4. Bind la valeur datable à DataModel<E> à la place qui enveloppe à son tour les articles.

    <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 le rend transient et instanciation lazily dans le getter est obligatoire lorsque vous utilisez ceci sur une vue ou une session scoped bean depuis DataModel ne met pas en œuvre Serializable )

    alors vous serez en mesure d'accéder à la rangée actuelle par DataModel#getRowData() sans passer quoi que ce soit (JSF détermine la ligne en se basant sur le nom du paramètre request de la commande cliquée lien/bouton).

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

    cela exige également que le datamodel soit conservé pour le formulaire soumettre la demande. Le mieux est de mettre le haricot dans la portée de vue par @ViewScoped .


  5. vous pouvez utiliser Application#evaluateExpressionGet() évaluer programmatiquement le courant #{item} .

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

quel chemin choisir dépend des exigences fonctionnelles et si l'une ou l'autre offre plus d'avantages pour d'autres fins. Personnellement, j'irai de l'avant avec le N ° 3 ou, si vous voulez prendre en charge les conteneurs servlet 2.5 aussi, avec le N ° 2.

203
répondu BalusC 2017-05-23 12:18:10

dans JSF 1.2 ceci a été fait par <f:setPropertyActionListener> (au sein de la composante de commandement). Dans JSF 2.0 (EL 2.2 Pour être précis, grâce à BalusC) il est possible de le faire comme ceci: action="${filterList.insert(f.id)}

10
répondu Bozho 2011-02-14 16:58:28

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>

background bean

 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;
        }
    }
}
10
répondu Arfan J 2011-05-09 08:50:05

merci à ce site par Mkyong , la seule solution que en fait travaillé pour nous de passer un paramètre était ce

<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, que vous ne pouvez pas passer directement à la méthode elle-même, mais à la JSF request parameter map .

0
répondu EpicPandaForce 2015-04-20 20:21:10