ตั้งค่า ID ภายในดาต้าลิสต์แบบไดนามิกโดยไม่ต้องใช้ JavaScript

ฉันมีปัญหาใหญ่กับอินเทอร์เฟซ Primefaces ของฉัน ฉันต้องการวนซ้ำรายการและแสดงข้อมูลบางส่วน + ช่องแก้ไขที่ซ่อนอยู่

ข้อมูลโค้ด XHTML Primefaces:

<p:dataList  value="#{datas}" var="data">
<div class="ui-g">
    <div class="ui-g-3">
        <h2>#{data.desc}</h2>
    </div>
    <div class="ui-g-3">
        <p:commandButton operation="edit" disabled="#{data.isLocked()}" actionListener="#{view.edit(data)}"
            style="width:120px;" update="edit_#{data.id}" />
        <p:commandButton operation="delete" actionListener="#{view.delete(data.getId())}" disabled="#{data.isLocked()}"/>           
    </div>
</div>

<!-- works perfectly to set the id -->
<span id="edit_#{data.id}">#{data.desc} #{index}</span>

<!-- doesnt work - maybe of the rendering moment to set the id? -->
<p:panelGrid id="edit_#{data.id}" rendered="#{view.edit}">
    <p:outputLabel for="desc" value="#{msg.text}" />
    <p:inputText id="desc" value="#{view.selectedValue.desc}" />        
</p:panelGrid>

How can I set a dynamic ID to the panelGrid to update it by commandButton click if I want to edit that div? + How can I make the div toggled while editing it? or are there other Solutions? I am not allowed to use JavaScript/jQuery.

ขอบคุณมาก!

ไชโย JohnRamb0r


person JohnRamb0r    schedule 10.01.2019    source แหล่งที่มา
comment
ในตัวอย่างของคุณ คุณจะสร้างรหัสที่ซ้ำกัน edit_{data.id} บางทีนี่อาจเป็นปัญหา คุณได้รับข้อความแสดงข้อผิดพลาดหรือไม่? หากคุณต้องการรหัสเฉพาะสำหรับ update= คุณควรใส่ <span และ <p:panelGrid ไว้ใน <h:panelGroup id='edit_#{data.id}'> และตัดรหัสของพวกเขาออก   -  person Holger    schedule 10.01.2019
comment
สวัสดี ขอบคุณสำหรับคำตอบของคุณ สแปนเป็นเพียงตัวอย่างที่แสดงว่าโซลูชันนี้ใช้งานได้และส่วน panelGrid ใช้ไม่ได้ ฉันต้องการตัวเลือกที่แสดงผลเพื่ออัปเดต panelGrid ดังนั้นฉันต้องการใช้มัน   -  person JohnRamb0r    schedule 10.01.2019
comment
ปัญหาหนึ่งคือการใส่ (อัพเดต) id ในส่วนประกอบซึ่งมีแอตทริบิวต์ที่แสดงผล หากองค์ประกอบนี้ไม่แสดงผล คุณจะใช้รหัสไม่ได้ ตามที่ฉันเขียน: คุณควรวาง panelGrid ไว้ใน <h:panelGroup id='edit_#{data.id}'> และไม่มีใครต้องได้รับรหัสเดียวกัน   -  person Holger    schedule 10.01.2019
comment
ตอนนี้ฉันลบแท็ก span และรวมพาเนล Grid ของฉันไว้ในพาเนลกรุ๊ป ผลลัพธ์ก็เหมือนกัน: Cannot find component for expression "edit_1" referenced from "main:j_idt70:0:j_idt122". คำชี้แจงการอัปเดตกำลังมองหา edit_1 แต่รหัสของ panelgrid ถูกสร้างขึ้นโดย Primefaces: main:j_idt70:0:edit_ แต่ฉันต้องการให้ panelGrid ควรมี id --> edit_1 เดียวกันสำหรับตัวอย่าง   -  person JohnRamb0r    schedule 10.01.2019
comment
อ๋อ ใช่ มันอยู่ใน dataList เนื่องจาก dataList สร้างรหัสด้วยตัวเอง :0 คุณจึงไม่จำเป็นต้องใช้รหัสแบบไดนามิก เพียงใช้เช่น editbox มันจะเปลี่ยนเป็น main:j_idt70:x:editbox โดยที่ x คือดัชนีแถวของ dataList ญาติ update='editbox' ที่ไม่มี : ควรค้นหามัน   -  person Holger    schedule 10.01.2019
comment
ใช่ แต่ฉันมีข้อมูลมากมายที่จะแสดง และข้อมูลทั้งหมดก็มีกล่องแก้ไขซ่อนอยู่กล่องเดียว ดังนั้นถ้าฉันโทรไปที่ update="editbox"กล่องแก้ไขทุกกล่องจะปรากฏขึ้น - ฉันพูดถูกไหม?   -  person JohnRamb0r    schedule 10.01.2019
comment
ไม่ มีเพียงอันเดียวในคอนเทนเนอร์นามินเดียวกัน   -  person Kukeltje    schedule 10.01.2019


คำตอบ (1)


ฉันจะบอกว่าคุณเกือบจะทำงานกับ JSF และวิธีการทำงานในตัวอย่างโค้ดของคุณ ก่อนที่จะแสดงตัวอย่างการทำงานให้คุณเห็น มีบางสิ่งที่ฉันอยากจะพูดที่นี่เกี่ยวกับแนวปฏิบัติที่ดี:

  • อย่าเรียกเมธอดโดยตรง ใช้การแปลการอ้างอิงคุณสมบัติในตัว การอ้างอิงถึง data.locked จะถูกแปลงเป็นการเรียกเป็น data.isLocked() โดยอัตโนมัติ แนะนำให้เรียก data.locked เนื่องจากจะทำให้กรอบงานประเมินมันแทนที่จะส่งค่าที่ประเมินไว้แล้ว
  • ทำงานร่วมกับ JSF - ไม่ใช่ต่อต้าน มีรหัสที่ไม่จำเป็นและการใช้แท็กและดัชนีที่ไม่จำเป็นจำนวนมากในโค้ดตัวอย่างของคุณ ทำให้มันเรียบง่ายและทำงานกับกรอบงาน แทนที่จะอ้างอิง ID ให้อ้างอิงออบเจ็กต์โดยตรง - ช่วยให้โค้ดง่ายขึ้นและทำให้ใช้งานบนเพจได้ง่ายขึ้น
  • ใช้การกระทำเป็นตัวดำเนินการหลักของตรรกะและผลลัพธ์ทางธุรกิจ ผู้ฟังการดำเนินการจะถูกดำเนินการล่วงหน้า และสามารถใช้เพื่อสกัดกั้นหรือหยุดการดำเนินการของการดำเนินการหลักได้ ดังนั้นจึงเหมาะสมที่จะใช้เป็นขั้นตอนการตรวจสอบก่อนที่จะดำเนินการตรรกะทางธุรกิจ
  • ทำเครื่องหมายกิจกรรมของคุณ แนวทางปฏิบัติที่ดีคือใช้แบบแผนการตั้งชื่อ on<Something> เมื่อตั้งชื่อวิธีการรับเหตุการณ์ของผู้ใช้ สิ่งนี้ทำให้คุณสามารถระบุได้อย่างชัดเจน

ฉันได้สร้างตัวอย่างการทำงานเล็กๆ น้อยๆ ของโค้ดของคุณ (ซึ่งใช้ ลอมบอก และ Apache Commons)

@Data
@Named
@ViewScoped
public class DataListViewBackingBean implements Serializable {
    private Entity entity;
    private Entity selectedEntity;
    private List<Entity> dataEntities;

    @PostConstruct
    private void init() {
        dataEntities = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            dataEntities.add(new Entity(i, RandomUtils.nextBoolean(),
                             RandomStringUtils.randomAlphabetic(30)));
        }
    }

    @Data
    @AllArgsConstructor
    @EqualsAndHashCode(exclude = {"locked","description"})
    public class Entity {
        private int id;
        private boolean locked;
        private String description;
    }

    public void onEdit(Entity entity) {
        selectedEntity = entity;
    }

    public void onDelete(Entity entity) {
        dataEntities.remove(entity);
        selectedEntity = null;
    }
}

โค้ดด้านบนเริ่มต้นรายการข้อมูลของเอนทิตีสิบรายการและเติมข้อมูลแบบสุ่ม ฉันได้รับสิทธิพิเศษในการเปลี่ยน data เป็น entity เมื่อพูดถึงโค้ด HTML ของคุณ ฉันรู้สึกว่าจำเป็นต้องทำความสะอาดบ้าง คำจำกัดความของ JSF จะมีลักษณะดังนี้

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Data list test</title>
    </h:head>
    <h:body>
        <h:form id="items">
            <p:dataList type="definition" value="#{dataListViewBackingBean.dataEntities}" var="entity">
                <div class="ui-g">
                    <div class="ui-g-8">
                        #{entity.description}
                    </div>
                    <div class="ui-g-4" style="text-align: right">
                        <p:commandButton value="Edit" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onEdit(entity)}" update=":edit" />
                        <p:commandButton value="Delete" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onDelete(entity)}" update="@form :edit" />
                    </div>
                </div>
            </p:dataList>
        </h:form>

        <h:form id="edit">
            <p:outputPanel rendered="#{dataListViewBackingBean.selectedEntity != null}">
                <h1>Editing...</h1>
                <p:inputText placeholder="Description" value="#{dataListViewBackingBean.selectedEntity.description}" />
                <p:commandButton value="Save" update=":items" />
            </p:outputPanel>
        </h:form>
    </h:body>
</html>

สังเกตว่าการแก้ไข div/outputPanel ถูกรวมไว้ในคอนเทนเนอร์อื่น (แบบฟอร์ม) อย่างไร หากเราข้ามการตัดคำและพุชการอัปเดตบนคอนเทนเนอร์ที่ห่อโดยตรงแทน แท็ก rendered ของคอนเทนเนอร์จะไม่ได้รับการอัปเดตในระหว่างการรีเฟรช และดังนั้น div จะไม่แสดงขึ้นมา ในกรณีนี้ นี่คือสาเหตุที่แบบฟอร์มถูกกำหนดไว้ภายนอกคอนเทนเนอร์แทนที่จะเป็นภายใน

ตัวอย่างนี้ใช้ @ViewScoped bean ดังนั้นตราบใดที่คุณยังคงอยู่ในเพจ ข้อมูลสำรองก็ควรคงเหมือนเดิม หากคุณโหลดหน้านี้ซ้ำ คุณจะได้รับชุดข้อมูลใหม่ที่มีเอนทิตีใหม่ เนื่องจากจะเป็นการเริ่มต้น Backing Bean ใหม่และเรียก @PostConstruct อีกครั้ง

ดูเพิ่มเติม

person Adam Waldenberg    schedule 11.01.2019
comment
และคุณไม่สามารถสร้างรหัสแบบไดนามิกในเวลาเรนเดอร์ได้ (และแทบไม่มีความจำเป็น) - person Kukeltje; 11.01.2019
comment
JSF ทำสิ่งนี้ตามค่าเริ่มต้นแล้ว ส่วนประกอบจะได้รับ ID "...sub-sub-component:sub-component:component" เสมอ นอกจากนี้ เมื่อใช้ไพรม์เฟซ คุณสามารถใช้ประโยชน์จากตัวเลือก JQuery ภายในแอตทริบิวต์ update ของคุณได้ ซึ่งบางครั้งอาจทำให้สิ่งต่างๆ ง่ายขึ้นมาก อย่างไรก็ตาม ในกรณีนี้ คุณไม่จำเป็นต้องคิดถึงเรื่องนั้นด้วยซ้ำ ปฏิบัติตามหลักการ KISS เสมอ en.wikipedia.org/wiki/KISS_principle - person Adam Waldenberg; 12.01.2019
comment
ฉันอยากจะเพิ่มสิ่งนั้นเป็นคำถาม / คำตอบที่เชื่อมโยง (stackoverflow.com/questions/9147771/) ให้กับคำตอบของคำถามนี้ได้อย่างไร คุณสามารถใช้ JSTL (ซึ่งทำงานในช่วงเวลาสร้าง) เพื่อ สร้าง ID แต่สำหรับกรณีการใช้งานเฉพาะนี้ โปรดอย่าทำเช่นนั้น - person Adam Waldenberg; 12.01.2019