จะค้นหารหัสลูกค้าของส่วนประกอบสำหรับ ajax update / render ได้อย่างไร ไม่พบส่วนประกอบที่มีนิพจน์“ foo” อ้างอิงจาก“ bar”


140

รหัสต่อไปนี้เป็นแรงบันดาลใจจาก PrimeFaces DataGrid + DataTable สอนและใส่ลงไปใน<p:tab>การ<p:tabView>พำนักอยู่ในของ<p:layoutUnit> <p:layout>นี่คือส่วนด้านในของรหัส (เริ่มต้นจากp:tabองค์ประกอบ); ส่วนนอกเป็นเรื่องเล็กน้อย

<p:tabView id="tabs">
    <p:tab id="search" title="Search">                        
        <h:form id="insTable">
            <p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
                <p:column>
                    <p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()">
                        <f:setPropertyActionListener value="#{lndInstrument}" 
                                        target="#{instrumentBean.selectedInstrument}" />
                        <h:outputText value="#{lndInstrument.name}" />
                    </p:commandLink>                                    
                </p:column>
            </p:dataTable>
            <p:dialog id="dlg" modal="true" widgetVar="dlg">
                <h:panelGrid id="display">
                    <h:outputText value="Name:" />
                    <h:outputText value="#{instrumentBean.selectedInstrument.name}" />
                </h:panelGrid>
            </p:dialog>                            
        </h:form>
    </p:tab>
</p:tabView>

เมื่อฉันคลิก<p:commandLink>รหัสจะหยุดทำงานและให้ข้อความ:

ไม่พบส่วนประกอบที่มีนิพจน์ "insTable: display" อ้างอิงจากแท็บ ": insTable: select"

เมื่อฉันลองใช้แบบเดียวกัน<f:ajax>มันจะล้มเหลวด้วยข้อความที่แตกต่างกันโดยทั่วไปบอกว่า:

<f:ajax> มี id ที่ไม่รู้จัก "insTable: display" ไม่สามารถค้นหาได้ในบริบทของแท็บ "แท็บ: insTable: select"

มันเกิดจากอะไรและฉันจะแก้มันได้อย่างไร

คำตอบ:


313

ค้นหาเอาต์พุต HTML เพื่อหารหัสลูกค้าที่แท้จริง

คุณต้องมองหาผลลัพธ์ HTML ที่สร้างขึ้นเพื่อหารหัสลูกค้าที่ถูกต้อง เปิดหน้าในเบราว์เซอร์, คลิกขวาทำและดูแหล่งที่มา ค้นหาการเป็นตัวแทน HTML ขององค์ประกอบ JSF ที่น่าสนใจและใช้idเป็น ID ลูกค้า คุณสามารถใช้มันในแบบสัมบูรณ์หรือแบบสัมพันธ์โดยขึ้นอยู่กับคอนเทนเนอร์การตั้งชื่อปัจจุบัน ดูบทต่อไปนี้

หมายเหตุ: หากมีดัชนีการทำซ้ำเช่น:0:, :1:ฯลฯ (เนื่องจากอยู่ในองค์ประกอบการทำซ้ำ) คุณจะต้องตระหนักว่าการอัพเดตรอบการทำซ้ำที่เฉพาะเจาะจงนั้นไม่ได้รับการสนับสนุนเสมอไป ดูคำตอบด้านล่างเพื่อดูรายละเอียดเพิ่มเติม

จดจำNamingContainerส่วนประกอบและให้รหัสประจำตัวแก่พวกเขาเสมอ

หากส่วนประกอบที่คุณต้องการอ้างอิงโดย ajax process / execute / update / render อยู่ในพาเรนต์เดียวกันNamingContainerให้อ้างอิง ID ของตัวเอง

<h:form id="form">
    <p:commandLink update="result"> <!-- OK! -->
    <h:panelGroup id="result" />
</h:form>

หากไม่ใช่ภายในเดียวกันNamingContainerคุณจำเป็นต้องอ้างอิงโดยใช้รหัสลูกค้าแบบสัมบูรณ์ รหัสลูกค้าแน่นอนเริ่มต้นด้วยตัวอักษรที่คั่นซึ่งเป็นค่าเริ่มต้นNamingContainer:

<h:form id="form">
    <p:commandLink update="result"> <!-- FAIL! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
    <p:commandLink update=":result"> <!-- OK! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
    <p:commandLink update=":result"> <!-- FAIL! -->
</h:form>
<h:form id="otherform">
    <h:panelGroup id="result" />
</h:form>
<h:form id="form">
    <p:commandLink update=":otherform:result"> <!-- OK! -->
</h:form>
<h:form id="otherform">
    <h:panelGroup id="result" />
</h:form>

NamingContainerเป็นส่วนประกอบเช่น<h:form>, <h:dataTable>, <p:tabView>, <cc:implementation>(ดังนั้นทุกองค์ประกอบคอมโพสิต) ฯลฯ คุณรู้จักพวกเขาได้อย่างง่ายดายโดยดูที่การแสดงผล HTML สร้าง ID ของพวกเขาจะใช้ได้กับรหัสลูกค้าที่สร้างขึ้นของทุกองค์ประกอบเด็ก โปรดทราบว่าเมื่อพวกเขาไม่มีรหัสคงที่ JSF จะใช้รหัสที่สร้างอัตโนมัติในj_idXXXรูปแบบ คุณควรหลีกเลี่ยงอย่างนั้นด้วยการให้รหัสประจำตัวแก่พวกเขา OmniFacesNoAutoGeneratedIdViewHandlerอาจจะเป็นประโยชน์ในเรื่องนี้ในระหว่างการพัฒนา

หากคุณรู้ที่จะหา javadoc ของUIComponentคำถามนั้นคุณสามารถเพียงแค่เช็คอินที่นั่นไม่ว่าจะใช้NamingContainerอินเทอร์เฟซหรือไม่ ยกตัวอย่างเช่นHtmlForm(คนUIComponentที่อยู่เบื้องหลัง<h:form>แท็ก) แสดงให้เห็นว่าการดำเนินการNamingContainerแต่HtmlPanelGroup(คนUIComponentที่อยู่เบื้องหลัง<h:panelGroup>แท็ก) NamingContainerไม่ได้แสดงมันจึงไม่ได้ดำเนินการ นี่คือ Javadoc ของส่วนประกอบทั้งหมดมาตรฐานและนี่คือ Javadoc ของ PrimeFaces

การแก้ปัญหาของคุณ

ดังนั้นในกรณีของคุณ:

<p:tabView id="tabs"><!-- This is a NamingContainer -->
    <p:tab id="search"><!-- This is NOT a NamingContainer -->
        <h:form id="insTable"><!-- This is a NamingContainer -->
            <p:dialog id="dlg"><!-- This is NOT a NamingContainer -->
                <h:panelGrid id="display">

ผลลัพธ์ HTML ที่สร้างขึ้น<h:panelGrid id="display">มีลักษณะดังนี้:

<table id="tabs:insTable:display">

คุณต้องปฏิบัติตามนั้นidเหมือนเป็นรหัสลูกค้าจากนั้นนำหน้าด้วย:สำหรับการใช้งานในupdate:

<p:commandLink update=":tabs:insTable:display">

การอ้างอิงภายนอก ได้แก่ / tagfile / composite

หากลิงก์คำสั่งนี้อยู่ใน include / tagfile และเป้าหมายอยู่ข้างนอกและทำให้คุณไม่จำเป็นต้องทราบ ID ของพาเรนต์คอนเทนเนอร์หลักของคอนเทนเนอร์การตั้งชื่อปัจจุบันของคอนเทนเนอร์การตั้งชื่อปัจจุบันคุณสามารถอ้างอิงได้แบบไดนามิกUIComponent#getNamingContainer()ดังนี้:

<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">

หรือหากลิงก์คำสั่งนี้อยู่ในส่วนประกอบคอมโพสิตและเป้าหมายอยู่ข้างนอก:

<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">

หรือถ้าทั้งลิงค์คำสั่งและเป้าหมายอยู่ในองค์ประกอบคอมโพสิตเดียวกัน:

<p:commandLink update=":#{cc.clientId}:display">

ดูเพิ่มเติมรับid ของการตั้งชื่อพาเรนต์คอนเทนเนอร์ในเทมเพลตสำหรับในแอตทริบิวต์การแสดงผล / อัปเดต

มันทำงานอย่างไรภายใต้ผ้าคลุม

ทั้งหมดนี้มีการระบุเป็น"การแสดงออกค้นหา"ในJavadoc :UIComponent#findComponent()

แสดงออกค้นหาประกอบด้วยทั้งระบุ (ซึ่งจะถูกจับคู่ตรงกับรหัสทรัพย์สินของUIComponentหรือชุดของตัวบ่งชี้ดังกล่าวเชื่อมโยงโดยที่UINamingContainer#getSeparatorCharค่าของตัวอักษร. วิธีการค้นหาควรดำเนินงานดังต่อไปนี้แม้ว่า alogrithms อื่นอาจจะใช้ตราบใดที่ ผลลัพธ์ที่ได้จะเหมือนกัน:

  • ระบุสิ่งUIComponentที่จะเป็นฐานในการค้นหาโดยหยุดทันทีที่พบเงื่อนไขใด ๆ
    • หากนิพจน์การค้นหาเริ่มต้นด้วยอักขระตัวคั่น (เรียกว่านิพจน์การค้นหา "สัมบูรณ์") ฐานจะเป็นรูทUIComponentของโครงสร้างคอมโพเนนต์ อักขระคั่นนำหน้าจะถูกตัดออกและส่วนที่เหลือของนิพจน์การค้นหาจะถูกใช้เป็นนิพจน์การค้นหา "สัมพัทธ์" ตามที่อธิบายไว้ด้านล่าง
    • มิฉะนั้นถ้านี่UIComponentคือสิ่งที่NamingContainerมันจะทำหน้าที่เป็นพื้นฐาน
    • มิฉะนั้นค้นหาผู้ปกครองของส่วนนี้ หากNamingContainerพบจะเป็นฐาน
    • มิฉะนั้น (หากไม่NamingContainerพบ) รูทUIComponentจะเป็นฐาน
  • นิพจน์การค้นหา (อาจแก้ไขในขั้นตอนก่อนหน้า) ตอนนี้เป็นนิพจน์การค้นหา "สัมพัทธ์" ที่จะถูกใช้เพื่อค้นหาส่วนประกอบ (ถ้ามี) ที่มีรหัสที่ตรงกันภายในขอบเขตขององค์ประกอบพื้นฐาน การแข่งขันจะดำเนินการดังนี้:
    • หากนิพจน์การค้นหาเป็นตัวบ่งชี้แบบง่ายค่านี้จะถูกเปรียบเทียบกับคุณสมบัติ id จากนั้นทำการวนซ้ำผ่าน facets และลูก ๆ ของฐานUIComponent(ยกเว้นว่าหากNamingContainerพบการสืบทอดตำแหน่ง facets และลูกของมันจะไม่ถูกค้นหา)
    • หากนิพจน์การค้นหามีตัวระบุมากกว่าหนึ่งตัวคั่นด้วยอักขระตัวคั่นตัวระบุแรกจะถูกใช้เพื่อค้นหาNamingContainerกฎโดยในสัญลักษณ์ก่อนหน้า จากนั้นจะเรียกfindComponent()วิธีการนี้NamingContainerผ่านส่วนที่เหลือของนิพจน์การค้นหา

โปรดทราบว่า PrimeFaces ยังยึดมั่นในข้อมูลจำเพาะ JSF แต่ RichFaces ใช้"ข้อยกเว้นเพิ่มเติมบางอย่าง"

"reRender"ใช้UIComponent.findComponent()อัลกอริทึม (มีข้อยกเว้นเพิ่มเติมบางอย่าง) เพื่อค้นหาส่วนประกอบในโครงสร้างองค์ประกอบ

ข้อยกเว้นเพิ่มเติมเหล่านั้นไม่มีรายละเอียดอธิบายไว้ แต่เป็นที่ทราบกันว่า ID ส่วนประกอบที่เกี่ยวข้อง (เช่นที่ไม่ได้ขึ้นต้นด้วย:) ไม่เพียงค้นหาในบริบทของพาเรนต์ที่ใกล้ที่สุดNamingContainerแต่ยังอยู่ในNamingContainerส่วนประกอบอื่น ๆ ทั้งหมดในมุมมองเดียวกัน งานแพง ๆ )

ห้ามใช้ prependId="false"

<h:form prependId="false">หากทั้งหมดนี้ยังไม่ได้ทำงานแล้วตรวจสอบว่าคุณไม่ได้ใช้ สิ่งนี้จะล้มเหลวระหว่างการประมวลผล ajax submit และ render ดูเพิ่มเติมนี้คำถามที่เกี่ยวข้อง: UIForm กับ prependId = แบ่ง "false" <f: อาแจ็กซ์ทำให้>

การอ้างอิงรอบการวนซ้ำเฉพาะของส่วนประกอบการวนซ้ำ

มันเป็นเวลานานไม่ได้ที่จะอ้างอิงเฉพาะซ้ำรายการในการทำซ้ำเช่นส่วนประกอบ<ui:repeat>และ<h:dataTable>ชอบโดย:

<h:form id="form">
    <ui:repeat id="list" value="#{['one','two','three']}" var="item">
        <h:outputText id="item" value="#{item}" /><br/>
    </ui:repeat>

    <h:commandButton value="Update second item">
        <f:ajax render=":form:list:1:item" />
    </h:commandButton>
</h:form>

อย่างไรก็ตามเนื่องจาก Mojarra 2.2.5 ผู้<f:ajax>สนับสนุนเริ่มต้นแล้ว (เพียงแค่หยุดการตรวจสอบความถูกต้องเท่านั้นดังนั้นคุณจะไม่พบกับข้อยกเว้นในคำถามที่กล่าวถึงอีกต่อไป;

สิ่งนี้ไม่สามารถใช้งานได้ในเวอร์ชันปัจจุบันของ MyFaces 2.2.7 และ PrimeFaces 5.2 การสนับสนุนอาจมาในรุ่นอนาคต ในขณะเดียวกันทางออกที่ดีที่สุดของคุณคือการปรับปรุงองค์ประกอบ iterating ตัวเองหรือผู้ปกครองในกรณีที่ไม่สามารถแสดงได้ HTML <ui:repeat>เช่น

เมื่อใช้ PrimeFaces ให้พิจารณานิพจน์การค้นหาหรือตัวเลือก

PrimeFaces Search Expressionsอนุญาตให้คุณอ้างอิงคอมโพเนนต์ผ่านนิพจน์การค้นหาแผนผังองค์ประกอบ JSF JSF มีหลายบิลด์:

  • @this: องค์ประกอบปัจจุบัน
  • @form: ผู้ปกครอง UIForm
  • @all: เอกสารทั้งหมด
  • @none: ไม่มีอะไร

PrimeFaces ได้ปรับปรุงสิ่งนี้ด้วยคำหลักใหม่และการสนับสนุนการแสดงออกรวม:

  • @parent: องค์ประกอบหลัก
  • @namingcontainer: ผู้ปกครอง UINamingContainer
  • @widgetVar(name): องค์ประกอบตามที่ระบุโดยกำหนด widgetVar

นอกจากนี้คุณยังสามารถผสมคำหลักเหล่านั้นในการแสดงออกเช่นคอมโพสิต@form:@parent, @this:@parent:@parentฯลฯ

PrimeFaces Selectors (PFS)เช่นเดียวกับใน@(.someclass)ช่วยให้คุณสามารถอ้างอิงส่วนประกอบผ่านทางไวยากรณ์ตัวเลือก jQuery CSS เช่นการอ้างอิงส่วนประกอบที่มีคลาสสไตล์ทั่วไปทั้งหมดในเอาต์พุต HTML สิ่งนี้มีประโยชน์อย่างยิ่งในกรณีที่คุณต้องการอ้างอิงส่วนประกอบ "มาก" สิ่งนี้จำเป็นก่อนว่าองค์ประกอบเป้าหมายมีรหัสลูกค้าทั้งหมดในเอาต์พุต HTML (แก้ไขหรือสร้างอัตโนมัติไม่สำคัญ) ดูเพิ่มเติมPrimeFaces Selectors เช่นเดียวกับใน update = "@ (. myClass)" ทำงานอย่างไร


@jack: เพียงแค่อ่าน javadoc: docs.oracle.com/javaee/6/api/javax/faces/component/ตั้งแต่ JSF 2.0 มันสามารถปรับแต่งได้แทนค่าคงที่
BalusC

ไม่ได้SEPARATOR_CHARเลิก? คุณสามารถให้ตัวอย่างเกี่ยวกับวิธีการเรียกคอมโพเนนต์ที่ซ้อนกันได้เช่น: context.getViewRoot().findComponent(":inputform" + UINamingContainer.getSeparatorChar(context) + "inputtext" );โปรดรวมรหัส xhtml ด้วย
jacktrades

1
ขอขอบคุณทราบเกี่ยวกับความล้มเหลวของ ajax rerender ภายในฟอร์มพร้อมprependId="false"บันทึกวันของฉัน
Gaim

ความหมายที่แท้จริงของรหัสลูกค้าตามที่อธิบายไว้ในการอธิบายของคุณคืออะไร? มันเหมือนกับใน JSF -> "ตัวระบุฝั่งไคลเอ็นต์สำหรับส่วนนี้" ขอแสดงความนับถือ + ขอบคุณสำหรับการทำงานของคุณ
Steve Oh

1
@ antonu17: ตามที่ระบุไว้ในคำตอบมันได้รับการสนับสนุนเฉพาะใน f: ajax ของ Mojarra
BalusC

9

ก่อนอื่น: เท่าที่ฉันรู้ว่าการวางไดอะล็อกใน tabview เป็นการฝึกฝนที่ไม่ดี ... คุณควรนำมันออกไป ...

และตอนนี้คำถามของคุณ:

ขอโทษฉันใช้เวลาสักครู่เพื่อให้ได้สิ่งที่คุณต้องการนำไปใช้จริง

ทำที่เว็บแอปของฉันด้วยตัวเองในตอนนี้และใช้งานได้

อย่างที่ฉันพูดก่อนวาง p: โต้ตอบข้าง `p: tabView,

ปล่อยให้กล่องโต้ตอบ p: ตามที่คุณแนะนำในตอนแรก:

<p:dialog modal="true" widgetVar="dlg">
    <h:panelGrid id="display">
        <h:outputText value="Name:" />
        <h:outputText value="#{instrumentBean.selectedInstrument.name}" />
    </h:panelGrid>
</p:dialog>   

และ p: commandlink ควรมีลักษณะเช่นนี้ (ทั้งหมดที่ฉันทำคือเปลี่ยนแอตทริบิวต์การอัปเดต)

<p:commandLink update="display" oncomplete="dlg.show()">
    <f:setPropertyActionListener value="#{lndInstrument}" 
        target="#{instrumentBean.selectedInstrument}" />
    <h:outputText value="#{lndInstrument.name}" />
</p:commandLink>  

ผลงานเดียวกันในเว็บแอปของฉันและถ้ามันไม่ได้ผลสำหรับคุณฉันคิดว่ามีบางอย่างผิดปกติในรหัสถั่วของคุณ ...


ฉันขอแนะนำให้คุณลองการเปลี่ยนแปลงอื่น ๆ ที่ฉันเขียนไว้ในคำตอบของฉัน (ด้วยการผูกและ faces-config และอื่น ๆ ... ) นี่เป็นการแก้ปัญหาของคุณ "INFO: ไม่สามารถหา compone ... "
Daniel

ฉันได้ลองใช้คำแนะนำที่สองของคุณอีกครั้ง แต่ก็ยังไม่ทำงาน กล่องโต้ตอบจะเปิดขึ้น แต่ไม่มีข้อมูลของรายการที่เลือก บันทึกแสดง "ไม่พบส่วนประกอบที่มีตัวระบุ" j_idt31 "ในมุมมอง" และฉันไม่สามารถแก้ไขข้อบกพร่องได้มากกว่านี้
perissf

5

เป็นเพราะแท็บเป็นที่ตั้งชื่อคอนเทนเนอร์เช่นกัน ... การอัปเดตของคุณควรเป็นupdate="Search:insTable:display"สิ่งที่คุณสามารถทำได้เช่นกันเพียงแค่วางไดอะล็อกของคุณนอกฟอร์มและยังคงอยู่ในแท็บดังนั้นจึงเป็น:update="Search:display"


0

ลองเปลี่ยนแปลงไปupdate="insTable:display" update="display"ฉันเชื่อว่าคุณไม่สามารถใส่รหัสประจำตัวด้วยรูปแบบ ID ได้


2
คำตอบที่เก่ามาก แต่ทำให้เข้าใจผิด อ้างถึงโพสต์ของ BalusC ข้างต้นแสดงการเติมคำนำหน้าของ ID ส่วนประกอบอย่างชัดเจนด้วย ID ของแบบฟอร์มการปิดล้อม: <h: form id = "form"> <p: commandLink update = ": otherform: result"> <! - OK! -> </ h: form> <h: form id = "otherform"> <h: panelGroup id = "result" /> </ h: form>
J Slick

0

ฉันรู้ว่านี้แล้วมีคำตอบที่ดีโดย BalusC แต่นี่เป็นเคล็ดลับเล็ก ๆ น้อย ๆ ที่ผมใช้จะได้รับภาชนะที่จะบอกฉัน ClientID

  1. เอาการปรับปรุงบนคอมโพเนนต์ของคุณที่ไม่ทำงาน
  2. ใส่องค์ประกอบชั่วคราวด้วยการปรับปรุงปลอมภายในองค์ประกอบที่คุณพยายามอัปเดต
  3. กดปุ่มหน้าข้อผิดพลาดข้อยกเว้น servlet จะบอกคุณรหัสลูกค้าที่ถูกต้องคุณต้องอ้างอิง
  4. ลบองค์ประกอบปลอมและใส่ clientId ที่ถูกต้องในการอัพเดทดั้งเดิม

นี่คือตัวอย่างของรหัสเนื่องจากคำของฉันอาจไม่อธิบายได้ดีที่สุด

<p:tabView id="tabs">
    <p:tab id="search" title="Search">                        
        <h:form id="insTable">
            <p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
                <p:column>
                    <p:commandLink id="select"

ลบการอัพเดทที่ล้มเหลวภายในคอมโพเนนต์นี้

 oncomplete="dlg.show()">
                        <f:setPropertyActionListener value="#{lndInstrument}" 
                                        target="#{instrumentBean.selectedInstrument}" />
                        <h:outputText value="#{lndInstrument.name}" />
                    </p:commandLink>                                    
                </p:column>
            </p:dataTable>
            <p:dialog id="dlg" modal="true" widgetVar="dlg">
                <h:panelGrid id="display">

เพิ่มคอมโพเนนต์ภายในคอมโพเนนต์ของ id ที่คุณพยายามอัปเดตโดยใช้การอัปเดตที่จะล้มเหลว

   <p:commandButton id="BogusButton" update="BogusUpdate"></p:commandButton>

                    <h:outputText value="Name:" />
                    <h:outputText value="#{instrumentBean.selectedInstrument.name}" />
                </h:panelGrid>
            </p:dialog>                            
        </h:form>
    </p:tab>
</p:tabView>

ไปที่หน้านี้และดูข้อผิดพลาด ข้อผิดพลาดคือ: javax.servlet.ServletException: ไม่พบคอมโพเนนต์สำหรับนิพจน์ "BogusUpdate" ที่อ้างอิงจาก แท็บ: insTable: BogusButton

ดังนั้นรหัสลูกค้าที่ถูกต้องที่ใช้จะเป็นตัวหนาบวกกับรหัสของคอนเทนเนอร์เป้าหมาย (แสดงในกรณีนี้)

tabs:insTable:display
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.