Làm cách nào để chuyển hàng đã chọn vào commandLink bên trong dataTable hoặc ui: repeat?


99

Tôi đang sử dụng Primefaces trong ứng dụng JSF 2. Tôi có một <p:dataTable>và thay vì chọn các hàng, tôi muốn người dùng có thể thực hiện trực tiếp các hành động khác nhau trên các hàng riêng lẻ. Đối với điều đó, tôi có một số <p:commandLink>s trong cột cuối cùng.

Vấn đề của tôi: làm thế nào tôi có thể chuyển một ID hàng cho hành động được bắt đầu bởi liên kết lệnh để tôi biết hàng nào sẽ hành động? Tôi đã thử sử dụng <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>

Nhưng nó luôn cho kết quả là 0 - dường như biến hàng fkhông khả dụng khi thuộc tính được hiển thị (nó hoạt động khi tôi sử dụng giá trị cố định).

Bất cứ ai có một giải pháp thay thế?

Câu trả lời:


215

Về nguyên nhân, giá trị <f:attribute>cụ thể cho chính thành phần đó (được điền trong thời gian tạo chế độ xem), không phải hàng được lặp lại (được điền trong thời gian hiển thị chế độ xem).

Có một số cách để đạt được yêu cầu.

  1. Nếu servletcontainer của bạn hỗ trợ tối thiểu Servlet 3.0 / EL 2.2, thì chỉ cần chuyển nó như một đối số của phương thức hành động / trình nghe của UICommand thành phần hoặc AjaxBehaviorthẻ. Ví dụ

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

    Kết hợp với:

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

    Điều này chỉ yêu cầu mô hình dữ liệu được giữ nguyên cho yêu cầu gửi biểu mẫu. Tốt nhất là đặt bean trong phạm vi xem bằng cách @ViewScoped.

    Bạn thậm chí có thể chuyển toàn bộ đối tượng item:

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

    với:

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

    Trên các thùng chứa Servlet 2.5, điều này cũng có thể thực hiện được nếu bạn cung cấp triển khai EL hỗ trợ điều này, chẳng hạn như JBoss EL. Để biết chi tiết cấu hình, hãy xem câu trả lời này .


  2. Sử dụng <f:param>trong UICommandthành phần. Nó thêm một tham số yêu cầu.

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

    Nếu bean của bạn là phạm vi yêu cầu, hãy để JSF đặt nó bằng @ManagedProperty

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

    Hoặc nếu bean của bạn có phạm vi rộng hơn hoặc nếu bạn muốn xác thực / chuyển đổi chi tiết hơn, hãy sử dụng <f:viewParam>trên chế độ xem đích, xem thêm f: viewParam vs @ManagedProperty :

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

    Dù bằng cách nào, điều này có lợi thế là mô hình dữ liệu không nhất thiết phải được lưu giữ cho biểu mẫu gửi (đối với trường hợp bean của bạn là phạm vi yêu cầu).


  3. Sử dụng <f:setPropertyActionListener>trong UICommandthành phần. Ưu điểm là điều này loại bỏ nhu cầu truy cập bản đồ tham số yêu cầu khi bean có phạm vi rộng hơn phạm vi yêu cầu.

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

    Kết hợp với

     private Long id; // +setter

    Nó sẽ chỉ có sẵn theo idphương thức thuộc tính trong hành động. Điều này chỉ yêu cầu mô hình dữ liệu được giữ nguyên cho yêu cầu gửi biểu mẫu. Tốt nhất là đặt bean trong phạm vi xem bằng cách @ViewScoped.


  4. Ràng buộc giá trị có thể dữ liệu DataModel<E>thay vào đó sẽ bao bọc các mục.

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

    với

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

    ( transientbắt buộc tạo nó và khởi tạo nó một cách lười biếng trong getter khi bạn đang sử dụng nó trên một bean phạm vi chế độ xem hoặc phiên vìDataModel không triển khai Serializable)

    Sau đó, bạn sẽ có thể truy cập hàng hiện tại DataModel#getRowData()mà không cần chuyển bất kỳ thứ gì xung quanh (JSF xác định hàng dựa trên tên tham số yêu cầu của liên kết / nút lệnh đã nhấp).

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

    Điều này cũng yêu cầu mô hình dữ liệu được giữ nguyên cho yêu cầu gửi biểu mẫu. Tốt nhất là đặt bean trong phạm vi xem bằng cách @ViewScoped.


  5. Sử dụng Application#evaluateExpressionGet()để đánh giá dòng điện theo chương trình #{item}.

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

Việc lựa chọn cách nào phụ thuộc vào các yêu cầu chức năng và liệu cách này hay cách khác mang lại nhiều lợi thế hơn cho các mục đích khác. Cá nhân tôi sẽ tiếp tục với # 1 hoặc, khi bạn cũng muốn hỗ trợ các thùng chứa servlet 2.5, với # 2.


1
+1, mặc dù tùy chọn của tôi chuyển sang # 2 (nếu 2,5 phải được hỗ trợ).
Bozho

Cảm ơn vì câu trả lời đầy đủ. Thật không may, tôi phải báo cáo rằng số 1 là thứ duy nhất hoạt động trong lập trình dữ liệu primefaces được lọc (đó chính xác là kịch bản mà tôi cần nó). Tất cả những người khác chỉ làm việc trên một cái bàn chưa được lọc. Tuy nhiên, tôi thấy đây là một lỗi trong các mặt nguyên tố hơn là trong câu trả lời của bạn.
Michael Borgwardt

Yêu cầu bean hoặc lượt xem có được xác định phạm vi không?
BalusC

2
Với "lọc", bạn có nghĩa là như trong ví dụ trưng bày này ? Các triệu chứng cho thấy rằng hành động bộ lọc chỉ diễn ra ở phía máy khách và mô hình ở phía máy chủ không được duy trì. Không chắc chắn nếu điều này là cố ý. Bạn luôn có thể để lại một báo cáo vấn đề.
BalusC

Bài đăng của bạn nằm giữa những bài viết hữu ích nhất mà tôi từng đọc. Tôi đã sử dụng phương pháp 5 vì tôi buộc phải sử dụng servlet 2.5. Câu hỏi của tôi bây giờ là liệu có thể gửi một tham số bằng commandLink (như trong ví dụ của bạn) nhưng sử dụng ajax không?
Aditzu

11

Trong JSF 1.2, điều này được thực hiện bởi <f:setPropertyActionListener>(trong thành phần lệnh). Trong JSF 2.0 (chính xác là EL 2.2, nhờ có BalusC), bạn có thể làm điều đó như sau:action="${filterList.insert(f.id)}


6
Tính năng này không dành riêng cho JSF 2.0 (tự nó có thể chạy trong vùng chứa Servlet 2.5), mà dành cho EL 2.2 (là một phần của Servlet 3.0).
BalusC

11

Trong trang xem của tôi:

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

đậu ủng hộ

 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

Nhờ trang web này của Mkyong , giải pháp duy nhất thực sự hiệu quả để chúng tôi chuyển một tham số là

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

với

public String editAction() {

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

Về mặt kỹ thuật, bạn không thể chuyển trực tiếp đến chính phương thức mà phải chuyển đến JSF request parameter map.


1
Bạn có một vấn đề khác với vấn đề được hỏi ở đây. Bạn muốn giữ lại các tham số yêu cầu từ #{param}bản đồ cho các yêu cầu tiếp theo, không phải chuyển một tham số tùy ý. Hỏi và Đáp của bạn được bao gồm bởi stackoverflow.com/questions/17734230
BalusC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.