ฉันจะส่งแถวที่เลือกไปยัง commandLink ภายใน dataTable หรือ ui: repeat ได้อย่างไร


100

ฉันใช้ Primefaces ในแอปพลิเคชัน JSF 2 ฉันมี a <p:dataTable>และแทนที่จะเลือกแถวฉันต้องการให้ผู้ใช้สามารถดำเนินการต่างๆในแต่ละแถวได้โดยตรง สำหรับสิ่งนั้นฉันมีหลายตัว<p:commandLink>ในคอลัมน์สุดท้าย

ปัญหาของฉัน: ฉันจะส่ง ID แถวไปยังการดำเนินการที่เริ่มต้นโดยลิงก์คำสั่งได้อย่างไรเพื่อให้ฉันรู้ว่าต้องดำเนินการกับแถวใด ฉันลองใช้<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. หาก servletcontainer ของคุณรองรับ 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>
    

    หาก bean ของคุณถูกกำหนดขอบเขตคำขอให้ JSF กำหนดโดย @ManagedProperty

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

    หรือถ้า bean ของคุณมีขอบเขตที่กว้างขึ้นหรือหากคุณต้องการการตรวจสอบความถูกต้อง / การแปลงที่ละเอียดยิ่งขึ้นให้ใช้<f:viewParam>กับมุมมองเป้าหมายโปรดดูที่f: viewParam vs @ManagedProperty :

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

    ไม่ว่าจะด้วยวิธีใดก็ตามสิ่งนี้มีข้อดีตรงที่รุ่นดาต้าไม่จำเป็นต้องถูกเก็บรักษาไว้สำหรับการส่งแบบฟอร์ม (สำหรับกรณีที่ bean ของคุณถูกกำหนดขอบเขตคำขอ)


  3. ใช้<f:setPropertyActionListener>ในUICommandส่วนประกอบ ข้อดีคือสิ่งนี้จะขจัดความจำเป็นในการเข้าถึงแผนที่พารามิเตอร์การร้องขอเมื่อ bean มีขอบเขตที่กว้างกว่าขอบเขตการร้องขอ

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

    ร่วมกับ

     private Long id; // +setter
    

    มันจะพร้อมใช้งานโดยคุณสมบัติidในวิธีการดำเนินการ สิ่งนี้ต้องการให้มีการเก็บรักษาโมเดลข้อมูลไว้สำหรับคำขอส่งแบบฟอร์มเท่านั้น @ViewScopedที่ดีที่สุดคือการใส่ถั่วอยู่ในขอบเขตมุมมองโดย


  4. ผูกค่า 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 เป็นสิ่งจำเป็นเมื่อคุณใช้สิ่งนี้ในมุมมองหรือเซสชันที่กำหนดขอบเขตถั่วเนื่องจาก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 container ด้วย # 2


1
+1 แม้ว่าความชอบของฉันจะไปที่ # 2 (หากต้องรองรับ 2.5)
Bozho

ขอบคุณสำหรับคำตอบที่ละเอียดถี่ถ้วน น่าเสียดายที่ฉันต้องรายงานว่า # 1 เป็นสิ่งเดียวที่ทำงานในไพรม์เฟซที่กรองข้อมูลได้ (ซึ่งเป็นสถานการณ์ที่ฉันต้องการ) คนอื่น ๆ ทั้งหมดทำงานบนโต๊ะที่ไม่มีการกรองเท่านั้น ฉันเห็นว่านี่เป็นจุดบกพร่องในไพรม์เฟซมากกว่าในคำตอบของคุณ
Michael Borgwardt

คำขอถั่วหรือมุมมองมีขอบเขตหรือไม่?
BalusC

2
ด้วย "กรอง" คุณหมายถึงในตัวอย่างการแสดงนี้หรือไม่ อาการแสดงว่าการดำเนินการกรองเกิดขึ้นในฝั่งไคลเอ็นต์เท่านั้นและโมเดลในฝั่งเซิร์ฟเวอร์ไม่ได้รับการดูแล ไม่แน่ใจว่าเป็นเจตนา คุณสามารถรายงานปัญหาได้ตลอดเวลา
BalusC

โพสต์ของคุณอยู่ระหว่างโพสต์ที่มีประโยชน์ที่สุดที่ฉันเคยอ่าน ฉันใช้วิธีที่ 5 เพราะฉันบังคับให้ใช้ servlet 2.5 คำถามของฉันตอนนี้คือเป็นไปได้ไหมที่จะส่งพารามิเตอร์ด้วย commandLink (เช่นในตัวอย่างของคุณ) แต่ใช้ ajax?
Aditzu

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}แผนที่สำหรับการร้องขอในภายหลังไม่ให้ส่งผ่านพารามิเตอร์ที่กำหนดเอง คำถาม & คำตอบของคุณครอบคลุมโดยstackoverflow.com/questions/17734230
BalusC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.