Ajax güncelleme / oluşturma bileşeninin istemci kimliğini nasıl bulabilirim? “Bar” dan başvurulan “foo” ifadesine sahip bileşen bulunamıyor


140

Aşağıdaki kod PrimeFaces DataGrid + DataTable Öğreticiler ilham ve bir konur <p:tab>a <p:tabView>bir ikamet eden <p:layoutUnit>a <p:layout>. İşte kodun iç kısmı ( p:tabbileşenden başlayarak ); dış kısım önemsizdir.

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

Tıkladığımda <p:commandLink>, kod çalışmayı durdurur ve iletiyi verir:

"Sekmeler: insTable: select" ifadesinden başvurulan "insTable: display" ifadesi olan bileşen bulunamıyor.

Aynı kullanarak denediğinizde, <f:ajax>temelde aynı söyleyen farklı bir mesajla başarısız:

<f:ajax> bilinmeyen bir kimlik içeriyor "insTable: display" bu bileşeni "tabs" bağlamında bulamıyor: insTable: select "

Bunun nedeni nedir ve nasıl çözebilirim?

Yanıtlar:


313

Gerçek müşteri kimliği için HTML çıktısına bakın

Doğru istemci kimliğini bulmak için oluşturulan HTML çıktısına bakmanız gerekir. Sayfayı tarayıcıda açın, sağ tıklayın ve Kaynağı Görüntüle . İlgili JSF bileşeninin HTML temsilini bulun ve idistemci kimliği olarak alın. Geçerli adlandırma kapsayıcısına bağlı olarak mutlak veya göreli bir şekilde kullanabilirsiniz. Aşağıdaki bölüme bakın.

Not: gibi yineleme indeksi barındırıyorsa bu :0:, :1:(bir yineleme bileşenlerin içinde olduğu için), vs, o zaman belirli bir yineleme yuvarlak güncellenmesi her zaman desteklenmediğini gerçekleştirmek gerekir. Bununla ilgili daha fazla ayrıntı için cevabın alt kısmına bakınız.

NamingContainerBileşenleri ezberleyin ve onlara her zaman sabit bir kimlik verin

Ajax process / execute / update / render ile referans vermek istediğiniz bir bileşen aynı NamingContainerebeveynin içindeyse, sadece kendi kimliğine referans verin.

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

E? Er değil aynı iç NamingContainer, o zaman mutlak bir istemci kimliği kullanarak başvuru gerekiyor. Mutlak bir istemci kimliği NamingContainer, varsayılan olarak ayırıcı karakterle başlar :.

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

NamingContainerbileşkenler şunlardır <h:form>, <h:dataTable>, <p:tabView>, <cc:implementation>(böylece, tüm kompozit parçalar vs.) Sen oluşturulan HTML çıktısı bakarak onları kolayca tanımak, kimlik tüm alt bileşenlerinin oluşturulan müşteri kimliği başına eklenecektir. Sabit bir kimliğe sahip olmadıklarında, JSF'nin otomatik olarak oluşturulmuş bir kimliği j_idXXXbiçiminde kullanacağını unutmayın . Onlara sabit bir kimlik vererek kesinlikle bundan kaçınmalısınız. OmniFacesNoAutoGeneratedIdViewHandler gelişimi sırasında bu faydalı olabilir.

Söz konusu javadocu bulmayı biliyorsanız UIComponent, o zaman sadece NamingContainerarayüzü uygulayıp uygulamadığını da kontrol edebilirsiniz . Örneğin, HtmlForm( UIComponentarka <h:form>etiket) uyguladığını gösterir NamingContainer, ancak HtmlPanelGroup( UIComponentarka <h:panelGroup>etiket) bunu göstermez, bu nedenle uygulanmaz NamingContainer. İşte tüm standart bileşenlerin javadocu ve burada PrimeFaces'in javadocu .

Sorununuzu çözme

Yani sizin durumunuzda:

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

Oluşturulan HTML çıktısı <h:panelGrid id="display">şuna benzer:

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

Bunu tam idolarak istemci kimliği olarak almanız ve ardından :kullanım için ön ekini kullanmanız gerekir update:

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

İnclude / tagfile / kompozit dışındaki referanslar

Bu komut bağlantısı bir include / tagfile içindeyse ve hedef onun dışındaysa ve bu nedenle geçerli adlandırma kapsayıcısının adlandırma kapsayıcı üst öğesinin kimliğini bilmiyorsanız, bu şekilde dinamik olarak bu şekilde başvurabilirsiniz UIComponent#getNamingContainer():

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

Veya, bu komut bağlantısı bileşik bir bileşenin içindeyse ve hedef bileşenin dışındaysa:

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

Veya hem komut bağlantısı hem de hedef aynı bileşik bileşenin içindeyse:

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

Ayrıca , oluşturma / güncelleme özelliği için şablonda üst adlandırma kapsayıcısının kimliğini alma konusuna bakın.

Örtülerin altında nasıl çalışır

Bu, tüm olarak belirtilir "ifadesini ara" in javadoc :UIComponent#findComponent()

Bir arama ifadesi bir kimliği özelliği karşı tam olarak eşleşen bir tanımlayıcı (birinden oluşur UIComponent, ya da bağlanmış gibi tanımlayıcıları bir dizi UINamingContainer#getSeparatorCharkarakter değerinden. Alternatif alogrithms sürece kullanılabilir olsa arama algoritması olarak, aşağıdaki çalışır olmalıdır sonuç aynıdır:

  • UIComponentAşağıdaki koşullardan biri karşılanır karşılanmaz durarak, arama için temel oluşturacağını belirleyin :
    • Arama ifadesi ayırıcı karakterle ("mutlak" arama ifadesi olarak adlandırılır) başlarsa, temel UIComponentbileşen ağacının kökü olur . Baştaki ayırıcı karakter çıkarılır ve arama ifadesinin geri kalanı, aşağıda tarif edildiği gibi "göreli" bir arama ifadesi olarak değerlendirilir.
    • Aksi takdirde, eğer bu bir esas UIComponentise NamingContainer, hizmet edecektir.
    • Aksi takdirde, bu bileşenin ebeveynlerini arayın. A NamingContainerile karşılaşılırsa, temel olacaktır.
    • Aksi takdirde (hayır NamingContainerile karşılaşılırsa) kök UIComponenttaban olacaktır.
  • Arama ifadesi (muhtemelen önceki adımda değiştirilmiştir), şimdi, temel bileşenin kapsamında eşleşen bir kimliği olan bileşeni (varsa) bulmak için kullanılacak "göreli" bir arama ifadesidir. Maç aşağıdaki gibi yapılır:
    • Arama ifadesi basit bir tanımlayıcıysa, bu değer id özelliğiyle karşılaştırılır ve daha sonra tabanın yönleri ve alt öğeleri aracılığıyla özyinelemeli olarak UIComponent(bir torun NamingContainerbulunursa, kendi yönleri ve alt öğeleri aranmaz).
    • Arama ifadesi, ayırıcı karakterle ayrılmış birden fazla tanımlayıcı içeriyorsa, ilk tanımlayıcı, bir NamingContainerönceki madde işaretindeki kurallara göre a'yı bulmak için kullanılır . Daha sonra, arama ifadesinin kalanını geçerek bunun findComponent()yöntemi NamingContainerçağrılacaktır.

PrimeFaces'in JSF spesifikasyonlarına da uyduğunu, ancak RichFaces "bazı ek istisnalar" kullandığını unutmayın .

"reRender"UIComponent.findComponent() bileşeni bileşen ağacında bulmak için algoritma (bazı ek istisnalar dışında) kullanır .

Bu ek istisnalar ayrıntılı olarak açıklanmamıştır, ancak göreceli bileşen kimliklerinin (yani, başlamayanların :) yalnızca en yakın ebeveyn bağlamında NamingContainerdeğil NamingContainer, aynı görünümdeki diğer tüm bileşenlerde (nispeten Bu arada pahalı bir iş).

Asla kullanma prependId="false"

Bunların hepsi hala çalışmıyorsa, kullanmadığınızı doğrulayın <h:form prependId="false">. Bu ajax gönderme ve oluşturma işlemi sırasında başarısız olur. Ayrıca bu ilgili soruya bakın: prependId = "false" sonlu UIForm <f: ajax render> .

Yinelemeli bileşenlerin spesifik yineleme turuna gönderme

Belirli bir benzeri bileşenleri yineleme öğeyi iterated başvurmak uzun süre mümkün değildi <ui:repeat>ve <h:dataTable>bu yüzden gibi:

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

Bununla birlikte, Mojarra 2.2.5 <f:ajax>onu desteklemeye başladığı için (basitçe doğrulamayı durdurdu; böylece söz konusu istisnada artık hiçbir zaman karşılaşmayacaksınız; bunun için başka bir geliştirme düzeltmesi planlanmaktadır).

Bu yalnızca geçerli MyFaces 2.2.7 ve PrimeFaces 5.2 sürümlerinde çalışmaz. Destek gelecek sürümlerde gelebilir. Bu arada, en iyi seçeneğiniz yineleme bileşeninin kendisini veya HTML'yi oluşturmaması durumunda bir üst öğeyi güncellemektir <ui:repeat>.

PrimeFaces kullanırken Arama İfadeleri veya Seçicileri düşünün

PrimeFaces Arama İfadeleri , JSF bileşen ağacı arama ifadeleri aracılığıyla bileşenlere başvurmanıza olanak tanır. JSF'de birkaç yerleşik vardır:

  • @this: geçerli bileşen
  • @form: ebeveyn UIForm
  • @all: tüm belge
  • @none: hiçbir şey değil

PrimeFaces bunu yeni anahtar kelimeler ve bileşik ifade desteği ile geliştirdi:

  • @parent: ana bileşen
  • @namingcontainer: ebeveyn UINamingContainer
  • @widgetVar(name): verilen bileşen widgetVar

Ayrıca gibi kompozit ifadelerde bu anahtar kelimeleri karıştırıp @form:@parent, @this:@parent:@parentvb

PrimeFaces Seçicileri (PFS) , @(.someclass)jQuery CSS seçici sözdizimi aracılığıyla bileşenlere başvurmanıza olanak tanır. Örneğin HTML çıktısında ortak bir stil sınıfına sahip referans bileşenleri. Bu, özellikle "çok" bileşene başvurmanız gerektiğinde yararlıdır. Bu, yalnızca hedef bileşenlerin HTML çıktısında tüm istemci kimliğine sahip olmasını gerektirir (sabit veya otomatik olarak oluşturulur, önemli değildir). Ayrıca bkz. PrimeFaces Seçicileri update = "@ (. MyClass)" daki gibi nasıl çalışır?


@jack: Sadece javadoc'u okuyun: docs.oracle.com/javaee/6/api/javax/faces/component/… JSF 2.0'dan beri sabit yerine yapılandırılabilir hale geldi.
BalusC

Değil mi SEPARATOR_CHAR kaldırılan? Yuvalanmış bir bileşenin nasıl çağrılacağına ilişkin bir örnek verebilir misiniz, örneğin: context.getViewRoot().findComponent(":inputform" + UINamingContainer.getSeparatorChar(context) + "inputtext" );Lütfen xhtml kodunu da ekleyin.
jacktrades

1
Teşekkür ederim, ajax formunun içindeki formun içinde başarısız olmasına dikkat prependId="false"ettim günümü kurtardım.
Gaim

açıklamanızda ana hatlarıyla belirtildiği gibi müşteri kimliğinin tam anlamı nedir? JSF -> "Bu bileşen için istemci tarafı tanımlayıcısı" ile aynı mı? Saygılarımızla + Çalışmanız için teşekkürler.
Steve Oh

1
@ antonu17: Yanıtta belirtildiği gibi, yalnızca Mojarra'nın f: ajax sürümünde desteklenmektedir.
BalusC

9

her şeyden önce: bir tabview içine diyalog yerleştirmek bildiğim kadarıyla kötü bir uygulama ... onu çıkarsan iyi olur ...

ve şimdi sorunuza:

üzgünüm, tam olarak uygulamak istediğin şeyi elde etmek için biraz zaman ayırdım,

web uygulamamda kendim yaptım ve işe yarıyor

daha önce söylediğim gibi p: iletişim kutusunu p: tabView tarafına,

p: iletişim kutusunu başlangıçta önerdiğiniz gibi bırakın:

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

ve p: komut bağlantısı şu şekilde görünmelidir (tüm yaptığım güncelleme özelliğini değiştirmek)

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

aynı benim web app çalışır, ve sizin için işe yaramazsa, o zaman java fasulye kodunda bir sorun var sanırım ...


": ... compone bulamıyor INFO" Sana senin çözmek için bu varsayalım (bağlayıcı ve yüzlerin-config ve diğer ... ile) benim cevap yazdım diğer değişiklikleri denemek için tavsiye
Daniel

Tekrar 2. önerinizi uygulamaya çalıştım, ama hala çalışmıyor. İletişim kutusu açılır, ancak seçilen öğenin verilerini içermez. Günlük "görünümünde" j_idt31 tanımlayıcı ile bileşen bulunamıyor "görüntüler ve bundan daha fazla hata ayıklamak mümkün değil.
perissf

5

Sekme de bir adlandırma kapsayıcısı olduğu için ... güncellemeniz olmalı update="Search:insTable:display"En iyi şekilde yapabileceğiniz şey iletişim kutusunu formun dışına ve hala sekmenin içine yerleştirmektir:update="Search:display"


0

Değişikliği deneyin update="insTable:display"için update="display". Kimliği form kimliğiyle önek ekleyemeyeceğinize inanıyorum.


2
Çok eski ama yanıltıcı bir cevap. Bileşen kimliğinin ön ekini ekteki formun kimliğiyle açıkça gösteren yukarıdaki BalusC'nin gönderisine bakın: <h: form id = "form"> <p: commandLink update = ": otherform: sonuç"> <! - Tamam! -> </ h: form> <h: form id = "diğer form"> <h: panelGroup id = "sonuç" /> </ h: form>
J Slick

0

Bunun BalusC tarafından zaten harika bir cevabı olduğunu biliyorum ama burada bana doğru müşteriyi anlatmak için kabı almak için kullandığım küçük bir numara var .

  1. Bileşeninizde çalışmayan güncelleştirmeyi kaldırın
  2. Güncellemeye çalıştığınız bileşenin içine sahte güncellemeyle geçici bir bileşen yerleştirin
  3. sayfaya bastığınızda, sunucu uygulaması istisna hatası size başvurmanız gereken doğru müşteri kimliğini söyleyecektir.
  4. Sahte bileşeni kaldırın ve orijinal güncellemeye doğru clientId'yi yerleştirin

İşte benim kod en iyi tarif olmayabilir gibi kod örneği.

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

Bu bileşendeki başarısız güncellemeyi kaldır

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

Güncellemeye çalıştığınız kimliğin bileşenine, başarısız olacak bir güncelleme kullanarak bir bileşen ekleyin

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

Bu sayfaya basın ve hatayı görüntüleyin. Hata: javax.servlet.ServletException: "BogusUpdate" ifadesi için sekmelerden başvurulan bileşen bulunamadı : insTable: BogusButton

Bu nedenle, kullanılacak doğru clientId, kalın artı hedef kabın kimliği olacaktır (bu durumda ekran)

tabs:insTable:display
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.