Jak przekazać wybrany wiersz do commandLink wewnątrz dataTable lub UI: repeat?

Używam Primefaces w aplikacji JSF 2. Mam <p:dataTable> i zamiast wybierać wiersze, chcę, aby użytkownik mógł bezpośrednio wykonywać różne akcje na poszczególnych wierszach. Do tego mam kilka <p:commandLink>s w ostatniej kolumnie.

Mój problem: jak mogę przekazać ID wiersza do akcji rozpoczętej przez łącze poleceń, aby wiedzieć, w którym wierszu działać? Próbowałem użyć <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>

Ale zawsze daje 0-widocznie zmienna wiersza f nie jest dostępna, gdy atrybut jest renderowany (działa, gdy używam stałej wartości).

Ktoś ma inne rozwiązanie?
Author: BalusC, 2011-02-14

4 answers

Jeśli chodzi o przyczynę, <f:attribute> jest specyficzna dla samego komponentu (wypełnionego w czasie budowania widoku), a nie dla iterowanego wiersza (wypełnionego w czasie renderowania widoku).

Istnieje kilka sposobów na osiągnięcie tego wymogu.
  1. Użycie <f:param> zamiast tego. Dodaje parametr request.

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

    Jeśli twój bean jest request scoped, niech JSF ustaw go przez @ManagedProperty

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

    Lub jeśli fasola ma szerszy zakres lub jeśli chcesz bardziej drobnoziarniste Walidacja/konwersja, użycie <f:viewParam> w tym celu należy zapoznać się z poniższym opisem:viewParam vs @ ManagedProperty :

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

    Tak czy inaczej, ma to tę zaletę, że datamodel niekoniecznie musi być zachowany dla formularza submit (w przypadku, gdy twoja fasola jest scopedem żądania).


  2. Użycie <f:setPropertyActionListener> zamiast tego. Zaletą jest to, że eliminuje to potrzebę dostępu do mapy parametrów żądania, gdy bean ma szerszy zakres niż zakres żądania.

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

    W połączeniu z

    private Long id; // +setter
    

    Będzie dostępny tylko według właściwości {[18] } w metodzie action. Wymaga to tylko, aby datamodel był zachowany dla żądania przesłania formularza. Najlepiej umieścić fasolę w polu widzenia przez @ViewScoped.


  3. Jeśli twój servletcontainer obsługuje Servlet 3.0 / EL 2.2, po prostu przekaż go jako argument metody. Wymaga to również, aby datamodel był zachowany dla żądania przesłania formularza. Najlepiej jest umieścić bean in the view scope by @ViewScoped.

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

    W połączeniu z:

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

    Możesz nawet przekazać cały obiekt elementu:

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

    Z:

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

    Na kontenerach Servlet 2.5 jest to również możliwe, jeśli dostarczysz implementację EL, która to obsługuje, jak np. JBoss EL. Aby uzyskać szczegóły konfiguracji, zobacz ta odpowiedź .


  4. Bind the datatable value to DataModel<E> zamiast tego, co z kolei owija pozycji.

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

    Z

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

    (tworzenie go transient i leniwe tworzenie instancji w getterze jest obowiązkowe, gdy używasz go w widoku lub sesji, ponieważ DataModel nie implementuje Serializable)

    Wtedy będziesz mógł uzyskać dostęp do bieżącego wiersza przez DataModel#getRowData() bez przekazywania czegokolwiek (JSF określa wiersz na podstawie nazwy parametru żądania klikniętego linku/przycisku polecenia).

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

    To również wymaga, aby datamodel jest zachowany dla żądania przesłania formularza. Najlepiej umieścić fasolę w polu widzenia przez @ViewScoped.


  5. Możesz użyć Application#evaluateExpressionGet() aby programowo ocenić prąd #{item}.

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

Jaki sposób wybrać zależy od wymagań funkcjonalnych i czy jeden lub drugi oferuje więcej korzyści dla innych celów. Ja osobiście bym poszedł na #3 lub, gdy chcielibyście również obsługiwać kontenery servlet 2.5, z numerem 2.

 203
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:10

W JSF 1.2 zostało to zrobione przez <f:setPropertyActionListener> (wewnątrz komponentu command). W JSF 2.0 (dokładnie el 2.2, dzięki BalusC) można to zrobić tak: action="${filterList.insert(f.id)}

 10
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-14 16:58:28

In my view page:

<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>

Backing 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
Author: Arfan J,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-09 08:50:05

Dzięki tej stronie przez Mkyong , jedynym rozwiązaniem, którew rzeczywistości zadziałało dla nas, aby przekazać parametr, było to

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

Z

public String editAction() {

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

Technicznie, że nie można przejść do samej metody bezpośrednio, ale do JSF request parameter map.

 0
Author: EpicPandaForce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-20 20:21:10