Как я могу передать выбранную строку в commandLink внутри dataTable или ui:repeat?
Я использую 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 ответа
Что касается причины, то <f:attribute>
относится только к самому компоненту (заполняется во время построения представления), а не к повторяющейся строке (заполняется во время визуализации представления).
Есть несколько способов выполнить это требование.
использование
<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" />
В любом случае, это имеет преимущество в том, что модель данных не обязательно должна быть сохранена для отправки формы (для случая, когда ваш компонент имеет область действия запроса).
использование
<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
,Если ваш servletcontainer поддерживает Servlet 3.0 / EL 2.2, просто передайте его как аргумент метода. Это также требует, чтобы модель данных была сохранена для запроса отправки формы. Лучше всего поместить боб в область видимости
@ViewScoped
,<h:commandLink action="#{bean.insert(item.id)}" value="insert" />
В комбинации с:
public void insert(Long id) { // ... }
Вы можете даже передать весь объект item:
<h:commandLink action="#{bean.insert(item)}" value="insert" />
с:
public void insert(Item item) { // ... }
В контейнерах Servlet 2.5 это также возможно, если вы предоставите реализацию EL, которая поддерживает это, например, JBoss EL. Для деталей конфигурации, смотрите этот ответ.
Привязать значение данных к
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
и ленивое создание его экземпляра в получателе является обязательным, когда вы используете это в бине вида или сеанса сDataModel
не реализуетSerializable
)Тогда вы сможете получить доступ к текущей строке
DataModel#getRowData()
ничего не передавая (JSF определяет строку на основе имени параметра запроса по нажатой ссылке / кнопке команды).public void insert() { Item item = model.getRowData(); Long id = item.getId(); // ... }
Это также требует, чтобы модель данных была сохранена для запроса отправки формы. Лучше всего поместить боб в область видимости
@ViewScoped
,Ты можешь использовать
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.
В 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
,