Ответ 1
Что касается причины, то <f:attribute>
относится к самому компоненту (заполняется во время создания времени просмотра), а не к итерированной строке (заполняется во время отображения времени просмотра).
Существует несколько способов достижения этого требования.
-
Вместо этого используйте
<f:param>
. Он добавляет параметр запроса.<h:commandLink action="#{bean.insert}" value="insert"> <f:param name="id" value="#{item.id}" /> </h:commandLink>
Если ваш bean - это область запроса, пусть JSF установил ее
@ManagedProperty
@ManagedProperty(value="#{param.id}") private Long id; // +setter
Или, если ваш bean имеет более широкую область видимости или требуется более мелкая проверка/преобразование, используйте
<f:viewParam>
в целевом view, см. также f: viewParam vs @ManagedProperty:<f:viewParam name="id" value="#{bean.id}" required="true" />
В любом случае это имеет то преимущество, что datamodel не обязательно нужно сохранять для отправки формы (для случая, когда ваш bean является областью действия запроса).
-
Вместо этого используйте
<f:setPropertyActionListener>
. Преимущество заключается в том, что это устраняет необходимость доступа к карте параметров запроса, когда bean имеет более широкую область действия, чем область запроса.<h:commandLink action="#{bean.insert}" value="insert"> <f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" /> </h:commandLink>
В сочетании с
private Long id; // +setter
Он будет доступен только с помощью свойства
id
в методе действий. Это требует только того, что датамодель сохраняется для запроса на отправку формы. Лучше всего поставить bean в область видимости на@ViewScoped
. -
Если ваш servletcontainer поддерживает Servlet 3.0/EL 2.2, просто передайте его как аргумент метода. Это также требует, чтобы датамодель сохранялась для запроса на отправку формы. Лучше всего поставить bean в область видимости на
@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. Подробную информацию о конфигурации см. В этом ответе.
-
Привяжите значение 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
и лениво инстанцирует его в getter, является обязательным, когда вы используете его в представлении или сеансе с областью bean, посколькуDataModel
не реализуетSerializable
)Затем вы сможете получить доступ к текущей строке
DataModel#getRowData()
, не передавая ничего вокруг (JSF определяет строку на основе запроса имя параметра щелкнутой командной строки/кнопки).public void insert() { Item item = model.getRowData(); Long id = item.getId(); // ... }
Это также требует, чтобы датамодель сохранялась для запроса на отправку формы. Лучше всего поставить bean в область видимости на
@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.