Как я могу передать выбранную строку в commandLink внутри dataTable или ui: repeat?


Я использую Primefaces в приложении JSF 2. У меня есть <p:dataTable>, и вместо того, чтобы выбирать строки, Я хочу, чтобы пользователь мог напрямую выполнять различные действия над отдельными строками. Для этого у меня есть несколько <p:commandLink>s в последней колонке.

моя проблема: как я могу передать идентификатор строки в действие, начатое по командной ссылке, чтобы я знал, на какую строку действовать? Я пробовал использовать <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>

но он всегда дает 0-видимо, переменная строки f не доступно, когда атрибут отображается (он работает, когда я использую фиксированное значение).

у кого-нибудь есть альтернативное решение?

4 90

4 ответа:

что касается причины, то <f:attribute> относится к самому компоненту (заполняется во время построения представления), а не к итерационной строке (заполняется во время визуализации представления).

существует несколько способов достижения этого требования.

  1. использовать <f:param>. Он добавляет параметр запроса.

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

    если ваш Боб имеет область запроса, пусть JSF установит его на @ManagedProperty

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

    или если ваш Боб имеет более широкую область действия или если вы хотите более мелкозернистую проверку / преобразование, используйте <f:viewParam> на целевом представлении см. также f: viewParam vs @ManagedProperty:

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

    в любом случае, это имеет то преимущество, что datamodel не обязательно должен быть сохранен для формы submit (для случая, когда ваш bean-это область запроса).


  2. использовать <f:setPropertyActionListener>. Преимущество что это устраняет необходимость доступа к карте параметров запроса, когда компонент имеет более широкую область, чем область запроса.

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

    в сочетании с

    private Long id; // +setter
    

    он будет просто доступен по свойству id в способ действий. Для этого требуется только сохранить модель данных для запроса на отправку формы. Лучше всего поместить боб в область видимости с помощью @ViewScoped.


  3. если ваш servletcontainer поддержка сервлетов 3.0 / EL 2.2, затем просто передайте его в качестве аргумента метода. Это также требует, чтобы модель данных сохранялась для формы отправить запрос. Лучше всего поместить боб в область видимости с помощью @ViewScoped.

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

    в сочетании с:

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

    вы даже можете передать весь объект элемента:

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

    С:

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

    на контейнерах сервлета 2.5 это также возможно, если вы предоставляете реализацию EL, которая поддерживает это, например, как JBoss EL. Для подробности конфигурации см. ответ.


  4. привязать значение datatable к DataModel<E> вместо этого, который, в свою очередь, обхватывает предметы.

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

    С

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

    (делая это transient и лениво инстанцирование его в геттере является обязательным, когда вы используете это в представлении или сеансе с областью действия bean since DataModel не выполнять Serializable)

    тогда вы сможете чтобы получить доступ к текущей строке с помощью DataModel#getRowData() не передавая ничего вокруг (JSF определяет строку на основе имени параметра запроса нажатой командной ссылки/кнопки).

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

    это также требует, чтобы модель данных была сохранена для формы отправить запрос. Лучше всего поместить боб в область видимости с помощью @ViewScoped.


  5. можно использовать Application#evaluateExpressionGet() для программной оценки текущего #{item}.

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

какой путь выбрать зависит от функциональных требований и предлагает ли одно или другое больше преимуществ для других целей. Я лично пошел бы вперед с #3 или, когда вы хотите поддерживать контейнеры servlet 2.5, с #2.

в JSF 1.2 это было сделано <f:setPropertyActionListener> (в командной составляющей). В JSF 2.0 (EL 2.2, если быть точным, благодаря BalusC) это можно сделать так:action="${filterList.insert(f.id)}

на моей странице просмотра:

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

базовый компонент

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

спасибо этот сайт от Mkyong единственное решение, которое на самом деле работали для нас, чтобы передать параметр был этот

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

С

public String editAction() {

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

технически, что вы не можете перейти непосредственно к самому методу, но к JSF request parameter map.