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

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

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

211 голосов
/ 14 февраля 2011

Что касается причины, <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" />
    

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


  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. Если ваш сервлет-контейнер поддерживает Servlet 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) {
        // ...
    }
    

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


  4. Привязать значение данных к 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-объекте представления или сеанса, поскольку 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 или, если вы хотите также поддерживать контейнеры с сервлетом 2.5, с № 2.

11 голосов
/ 14 февраля 2011

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

10 голосов
/ 09 мая 2011

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

<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;
        }
    }
}
0 голосов
/ 20 апреля 2015

Благодаря этому сайту от 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.

...