Як я можу передати вибраний рядок commandLink всередині dataTable чи ui: повторити?


99

Я використовую 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недоступна, коли атрибут надається (він працює, коли я використовую фіксоване значення).

У когось є альтернативне рішення?

Відповіді:


215

Що стосується причини, то <f:attribute>специфічний для самого компонента (заповнюється під час побудови перегляду), а не ітераційного рядка (заповнюється під час візуалізації перегляду).

Існує кілька способів досягнення вимоги.

  1. Якщо ваш сервлет-контейнер підтримує мінімум Servlet 3.0 / EL 2.2, тоді просто передайте його як аргумент дії / методу прослуховувача UICommand компонента або AjaxBehaviorтегу. Напр

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

    У поєднанні з:

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

    Це вимагає збереження лише моделі даних для запиту надіслати форму. Найкраще - поставити квасоля в поле зору @ViewScoped.

    Ви навіть можете передавати весь об’єкт:

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

    з:

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

    На контейнерах Servlet 2.5 це також можливо, якщо ви поставите реалізацію EL, яка підтримує це, як, наприклад, JBoss EL. Детальну інформацію про конфігурацію див . У відповіді .


  2. Використання <f:param>в UICommandкомпоненті. Він додає параметр запиту.

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

    У будь-якому випадку, це має перевагу в тому, що модель моделювання не обов'язково повинна зберігатися для надсилання форми (для випадку, коли ваш боб буде проаналізований).


  3. Використання <f:setPropertyActionListener>в UICommandкомпоненті. Перевага полягає в тому, що це усуває необхідність доступу до карти параметрів запиту, коли боб має ширший обсяг, ніж область запиту.

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

    У поєднанні з

     private Long id; // +setter

    Це буде просто доступне за властивістю idв методі дії. Це вимагає збереження лише моделі даних для запиту надіслати форму. Найкраще - поставити квасоля в поле зору @ViewScoped.


  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і ліниво створити інстанцію в геттері є обов'язковим, коли ви використовуєте це на перегляді або наборі сеансів, оскільки 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();
         // ...
     }

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


1
+1, хоча мої переваги стосуються №2 (якщо 2,5 має підтримуватися).
Божо

Дякую за вичерпну відповідь. На жаль, я маю повідомити, що №1 було єдиним, що працювало у відфільтрованих даних про префікси (що саме такий сценарій мені потрібен). Усі інші працювали лише над нефільтрованим столом. Хоча я бачу це більше як помилку в префіксах, ніж у вашій відповіді.
Майкл Боргвардт

Чи запит на квасоля чи перегляд визначений?
BalusC

2
Під "відфільтрованим" ви маєте на увазі, як у цьому прикладі вітрини ? Симптоми вказують на те, що дія фільтра відбувається тільки на стороні клієнта і що модель на стороні сервера не підтримується. Не впевнений, чи це навмисно. Ви завжди можете залишити звіт про проблему.
BalusC

Ваше повідомлення знаходиться між найкориснішими публікаціями, які я коли-небудь читав. Я використовував метод 5, тому що я змушений використовувати сервлет 2.5. Моє запитання зараз, чи можна надіслати параметр за допомогою commandLink (як у вашому прикладі), але за допомогою ajax?
Адітцу

11

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


6
Ця функція не характерна для JSF 2.0 (який сам по собі може працювати в контейнерах Servlet 2.5), але для EL 2.2 (який є частиною Servlet 3.0).
BalusC

11

На моїй сторінці перегляду:

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

-1

Завдяки цьому веб-сайту 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.


1
Ви маєте іншу проблему, ніж тут задавали. Ви хочете зберегти параметри запиту з #{param}карти для наступних запитів, а не передавати довільний параметр. Ваш Q & А покривається stackoverflow.com/questions/17734230
BalusC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.