ajax 업데이트 / 렌더링을위한 컴포넌트의 클라이언트 ID를 찾는 방법은 무엇입니까? “bar”에서 참조 된“foo”표현을 가진 구성 요소를 찾을 수 없습니다


140

다음 코드는 PrimeFaces DataGrid + DataTable Tutorials에서 영감을 얻어 <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>코드 작동이 중지되고 메시지가 나타납니다.

"tabs : insTable : select"에서 "insTable : display"표현식을 가진 구성 요소를 찾을 수 없습니다.

을 사용하여 동일하게 시도하면 <f:ajax>기본적으로 동일한 메시지를 나타내는 다른 메시지와 함께 실패합니다.

<f:ajax> 알 수없는 ID "insTable : display"를 포함하고 "tabs : insTable : select"구성 요소의 컨텍스트에서 찾을 수 없습니다.

이 문제는 어떻게 발생하며 어떻게 해결할 수 있습니까?

답변:


313

실제 클라이언트 ID에 대한 HTML 출력을 찾습니다

올바른 클라이언트 ID를 찾으려면 생성 된 HTML 출력을 조사해야합니다. 브라우저에서 페이지를 열고 마우스 오른쪽 단추를 클릭하고 소스보기를 수행하십시오 . 관심있는 JSF 구성 요소의 HTML 표시를 찾아 id클라이언트 ID로 사용하십시오. 현재 이름 지정 컨테이너에 따라 절대적 또는 상대적 방식으로 사용할 수 있습니다. 다음 장을 참조하십시오.

참고 :이 같은 반복 인덱스 포함 발생할 경우 :0:, :1:(그것이 반복하는 구성 요소 내부에 있기 때문에), 등, 당신은 특정의 반복 라운드를 업데이트하는 것은 항상 지원되지 않는다는 것을 인식 할 필요가있다. 이에 대한 자세한 내용은 답변 하단을 참조하십시오.

NamingContainer구성 요소를 외우고 항상 고정 ID를 부여하십시오

ajax process / execute / update / render에서 참조하려는 구성 요소가 동일한 NamingContainer상위 내에 있으면 자체 ID를 참조하십시오.

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

그것이 있다면 하지 같은 내부 NamingContainer, 당신은 절대 클라이언트 ID를 사용하여 참조 할 필요가있다. 절대 클라이언트 ID는 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는 모든 하위 구성 요소의 생성 된 클라이언트 ID 앞에 추가됩니다. 고정 ID가 없으면 JSF는 자동 생성 ID를 j_idXXX형식으로 사용 합니다. 당신은 그들에게 고정 ID를 부여함으로써 그것을 피해야합니다. OmniFaces는NoAutoGeneratedIdViewHandler 개발 과정이 도움이 될 수 있습니다.

UIComponent문제 의 javadoc을 찾으면 NamingContainer인터페이스를 구현하는지 여부를 확인할 수도 있습니다 . 예를 들어 HtmlForm( UIComponent뒤 <h:form>태그)는 구현 NamingContainer을 표시하지만 HtmlPanelGroup( UIComponent뒤 <h:panelGroup>태그)는이를 표시하지 않으므로 구현하지 않습니다 NamingContainer. 여기에 모든 표준 구성 요소의 자바 독입니다 및 여기 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클라이언트 ID로 사용하고 다음 :에서 사용하기 위해 접두사를 사용해야합니다 update.

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

include / 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()

검색 식 (A)의 ID 속성에 대해 정확히 일치하는 식별자 (어느 구성 UIComponent이나 의해 연결된 같은 식별자의 일련의 UINamingContainer#getSeparatorChar문자 값. 대체 alogrithms는만큼 사용될 수 있지만 검색 알고리즘 으로서는, 다음하여 동작한다 최종 결과는 같습니다 :

  • UIComponent다음 조건 중 하나가 충족되는 즉시 중지하여 검색의 기초가 되는 것을 식별하십시오 .
    • 검색 표현식이 분리 자 문자 ( "절대"검색 표현식이라고 함)로 시작하면 밑이 UIComponent컴포넌트 트리 의 루트 가됩니다. 선행 분리 문자가 제거되고 나머지 검색 표현식은 아래 설명 된대로 "상대적"검색 표현식으로 취급됩니다.
    • 이 경우 그렇지 UIComponent않은 NamingContainer그것은 기반이 될 것입니다.
    • 그렇지 않으면이 구성 요소의 상위를 검색하십시오. a NamingContainer가 있으면 기본이됩니다.
    • 그렇지 않으면 (아니오 NamingContainer가 있을 경우 ) 루트 UIComponent가 기본이됩니다.
  • 검색 표현식 (이전 단계에서 수정되었을 수 있음)은 이제 기본 컴포넌트의 범위 내에서 일치하는 ID를 가진 컴포넌트 (있는 경우)를 찾는 데 사용되는 "상대적"검색 표현식입니다. 일치는 다음과 같이 수행됩니다.
    • 검색 표현식이 단순 식별자 인 경우이 값은 id 특성과 비교 된 후 기본의 패싯 및 하위를 통해 재귀 적으로 검색됩니다 UIComponent(자손 NamingContainer이 발견되면 자체 패싯 및 하위는 검색되지 않음).
    • 검색 표현식에 구분 문자로 구분 된 둘 이상의 식별자가 포함 된 경우 첫 번째 식별자는 NamingContainer이전 글 머리 기호의 규칙 으로 위치를 찾는 데 사용됩니다 . 그런 다음 나머지 검색 식을 전달 findComponent()하여이 메서드를 NamingContainer호출합니다.

PrimeFaces도 JSF 사양을 준수하지만 RichFaces는 "일부 추가 예외"를 사용 합니다.

"reRender" 는 UIComponent.findComponent()알고리즘 (일부 추가 예외 포함)을 사용하여 컴포넌트 트리에서 컴포넌트를 찾습니다.

이러한 추가 예외는 자세히 설명되어 있지 않지만 상대 구성 요소 ID (예 :로 시작하지 않는 :)는 가장 가까운 상위 컨텍스트 NamingContainer뿐만 아니라 NamingContainer동일한보기의 다른 모든 구성 요소 에서도 검색되는 것으로 알려져 있습니다. 그건 그렇고 비싼 일).

절대 사용하지 마십시오 prependId="false"

그래도 문제가 해결되지 않으면를 사용하지 않는지 확인하십시오 <h:form prependId="false">. 이것은 ajax 제출 및 렌더링 처리 중에 실패합니다. 이 관련 질문을 참조하십시오 : prependId = "false"인 UIForm은 <f : ajax render>를 중단 합니다.

반복 구성 요소의 특정 반복 라운드 참조

반복 구성 요소에서 특정 반복 항목을 다음 <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 버전에서는 아직 작동하지 않습니다. 향후 버전에서는 지원이 제공 될 수 있습니다. 한편, 가장 좋은 방법은 반복 구성 요소 자체 또는 HTML과 같이 HTML을 렌더링하지 않는 경우 부모를 업데이트하는 것 <ui:repeat>입니다.

PrimeFaces를 사용할 때 검색 표현식 또는 선택자를 고려하십시오

PrimeFaces 검색 표현식을 사용하면 JSF 컴포넌트 트리 검색 표현식을 통해 컴포넌트를 참조 할 수 있습니다. JSF에는 몇 가지 내장 기능이 있습니다.

  • @this: 현재 구성 요소
  • @form: 부모의 UIForm
  • @all: 전체 문서
  • @none: 아무것도

PrimeFaces는 새로운 키워드 및 복합 표현식 지원을 통해이를 개선했습니다.

  • @parent: 상위 구성 요소
  • @namingcontainer: 부모의 UINamingContainer
  • @widgetVar(name): 주어진 것으로 식별 된 구성 요소 widgetVar

당신은 또한 다음과 같은 복합 표현식에서 해당 키워드를 혼합 할 수 있습니다 @form:@parent, @this:@parent:@parent등

PFS (PrimeFaces Selectors) 를 @(.someclass)사용하면 jQuery CSS 선택기 구문을 통해 구성 요소를 참조 할 수 있습니다. 예를 들어 HTML 출력에서 ​​모든 공통 스타일 클래스를 가진 컴포넌트를 참조합니다. "많은"구성 요소를 참조해야하는 경우에 특히 유용합니다. 이것은 대상 구성 요소가 HTML 출력의 모든 클라이언트 ID를 갖도록 요구합니다 (고정 또는 자동 생성, 중요하지 않음). update = "@ (. myClass)"에서와 같이 PrimeFaces 선택기 는 어떻게 작동합니까?를 참조하십시오.


@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
감사합니다, prependId="false"내 하루 를 구한 상태에서 양식 내부의 아약스 다시 렌더링에 실패 했습니다.
— Gaim

설명에 요약 된 고객 ID 의 정확한 의미는 무엇 입니까? JSF-> "이 구성 요소의 클라이언트 측 ID"에서와 동일합니까? 당신의 일에 대한 + 감사합니다.
— Steve Oh

1
@ antonu17 : 답변에 명시된 바와 같이 Mojarra의 f : ajax에서만 지원됩니다.
— BalusC

9

우선 : 탭보기 내에 대화 상자를 배치하는 것은 나쁜 습관입니다 ...

그리고 지금 당신의 질문에 :

죄송합니다. 정확히 구현하고 싶은 것을 얻기 위해 시간이 좀 걸렸습니다.

지금 내 웹 앱에서 직접 작동했으며 작동합니다.

p : dialog를`p : tabView 바깥에 배치하기 전에 말했듯이,

처음에 제안한대로 p : dialog를 그대로 두십시오.

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

내 웹 응용 프로그램에서도 동일하게 작동하며 작동하지 않으면 Java Bean 코드에 문제가있는 것 같습니다 ...


나는 바인딩과 faces-config와 다른 것들로 내 대답에 쓴 다른 변화들을 시도해 볼 것을 권한다. 이것은 "정보 : 구성 요소를 찾을 수 없다 ..."
— Daniel

두 번째 제안을 다시 시도했지만 여전히 작동하지 않습니다. 대화 상자가 열리지 만 선택한 항목의 데이터가 포함되어 있지 않습니다. 로그에 "보기에서 식별자가"j_idt31 "인 구성 요소를 찾을 수 없습니다"가 표시되고 이보다 더 이상 디버깅 할 수 없습니다.
— perissf

5

그것은 탭이 명명 컨테이너이기도하기 때문입니다 ... 업데이트해야 update="Search:insTable:display"할 일은 대화 상자를 양식 외부에 배치하고 탭 내부에 배치하는 것입니다.update="Search:display"


0

변화 시도 update="insTable:display"에를 update="display". 양식 ID로 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 2012

0

나는 이것이 BalusC에 의해 이미 훌륭한 대답을 가지고 있음을 알고 있지만 여기에 컨테이너가 올바른 clientId를 알려주는 데 약간의 트릭이 있습니다 .

  1. 작동하지 않는 구성 요소에서 업데이트를 제거하십시오.
  2. 업데이트하려는 구성 요소 내에 가짜 업데이트가 포함 된 임시 구성 요소를 넣습니다.
  3. 페이지를 누르면 서블릿 예외 오류가 참조해야 할 올바른 클라이언트 ID를 알려줍니다.
  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 : tabs : insTable : BogusButton 에서 참조 된 "BogusUpdate"표현식의 컴포넌트를 찾을 수 없습니다 .

따라서 사용할 올바른 clientId는 굵은 체와 대상 컨테이너의 ID입니다 (이 경우 표시).

tabs:insTable:display
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.