151

次のコードは、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>と、コードが機能しなくなり、次のメッセージが表示されます。

「tabs:insTable:select」から参照される式「insTable:display」を含むコンポーネントが見つかりません。

を使用して同じことを試みると、基本的に同じことを伝える別のメッセージ<f:ajax>で失敗します。

<f:ajax>不明な ID "insTable:display" が含まれています コンポーネント "tabs:insTable:select" のコンテキストで見つけることができません

別の Ajax ポストバック中に発生し、JSF プロジェクト ステージが に設定されている場合、次のメッセージDevelopmentを含む JavaScript アラートで失敗します。

malformedXML: 更新中: insTable:display not found

これはどのように発生し、どうすれば解決できますか?

4

5 に答える 5

331

実際のクライアント ID については HTML 出力を参照してください

正しいクライアント ID を見つけるには、生成された HTML 出力を調べる必要があります。ブラウザーでページを開き、右クリックして[ソースを表示]を実行します。対象の JSF コンポーネントの HTML 表現を見つけて、それidをクライアント ID として取得します。現在の名前付けコンテナーに応じて、絶対的または相対的な方法で使用できます。次の章を参照してください。

注: 、 などの反復インデックスが含まれている場合:0:(:1:反復コンポーネント内にあるため)、特定の反復ラウンドの更新が常にサポートされているわけではないことに注意する必要があります。詳細については、回答の下部を参照してください。

コンポーネントを記憶NamingContainerし、常に固定 ID を付与する

ajax プロセス/実行/更新/レンダリングによって参照したいコンポーネントが同じ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を与えることで、それを絶対に避けるべきです. OmniFacesNoAutoGeneratedIdViewHandlerは、開発中にこれに役立つ場合があります。

問題の javadoc を見つけることがわかっている場合は、そこにインターフェイスUIComponentが実装されているかどうかを確認することもできます。NamingContainerたとえば、HtmlFormUIComponentビハインド<h:form>タグ)は を実装していることを示していますNamingContainerが、HtmlPanelGroupUIComponentビハインド<h:panelGroup>タグ)はそれを示していないため、実装していませんNamingContainerここにすべての標準コンポーネントの javadoc がありここに PrimeFaces の javadoc があります

問題を解決する

したがって、あなたの場合:

<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 の外部参照

UIComponent#getNamingContainer()このコマンド リンクがインクルード/タグファイル内にあり、ターゲットがその外にある場合、現在の名前付けコンテナーの名前付けコンテナーの親の ID を必ずしも知らない場合は、次のように動的に参照できます。

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

または、このコマンド リンクが複合コンポーネント内にあり、ターゲットがその外にある場合:

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

または、コマンド リンクとターゲットの両方が同じ複合コンポーネント内にある場合:

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

render / update 属性のテンプレートで親ネーミング コンテナーの ID を取得するも参照してください。

カバーの下でどのように機能しますか

これはすべてjavadoc「検索式」として指定されています。UIComponent#findComponent()

検索式は、識別子 ( の id プロパティと正確に一致するものUIComponent)、または文字値によってリンクされた一連のそのような識別子のいずれかで構成されUINamingContainer#getSeparatorCharます。検索アルゴリズムは次のように動作する必要があります。最終結果は同じです:

  • UIComponent次のいずれかの条件が満たされるとすぐに停止して、検索のベースとなる を 特定します。
    • 検索式が区切り文字で始まる場合 (「絶対」検索式と呼ばれます)、ベースはUIComponentコンポーネント ツリーのルートになります。先頭の区切り文字は取り除かれ、検索式の残りの部分は、以下で説明する「相対」検索式として扱われます。
    • それ以外の場合UIComponentは、これがNamingContainerベースとして機能します。
    • それ以外の場合は、このコンポーネントの親を検索します。aNamingContainerが検出された場合、それがベースになります。
    • それ以外の場合 (noNamingContainerが検出された場合)、ルートUIComponentがベースになります。
  • 検索式 (前のステップで変更された可能性があります) は、基本コンポーネントのスコープ内で一致する ID を持つコンポーネント (存在する場合) を見つけるために使用される「相対」検索式になりました。試合は次のように行われます。
    • 検索式が単純な識別子の場合、この値は id プロパティと比較され、次にベースのファセットと子が再帰的に比較されますUIComponent(ただし、子孫NamingContainerが見つかった場合、それ自体のファセットと子は検索されません)。
    • 検索式に区切り文字で区切られた複数の識別子が含まれている場合、最初の識別子を使用してNamingContainer、前の箇条書きの規則に従って a を検索します。次に、この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 バージョンではまだ機能しません。将来のバージョンでサポートされる可能性があります。それまでの間、あなたの最善の策は、反復コンポーネント自体を更新することです<ui:repeat>

PrimeFaces を使用する場合は、検索式またはセレクターを検討してください

PrimeFaces 検索式を使用すると、JSF コンポーネント ツリー検索式を介してコンポーネントを参照できます。JSF にはいくつかの組み込み機能があります。

  • @this: 現在のコンポーネント
  • @form: 親UIForm
  • @all: ドキュメント全体
  • @none: なし

PrimeFaces は、新しいキーワードと複合表現のサポートにより、これを強化しました。

  • @parent: 親コンポーネント
  • @namingcontainer: 親UINamingContainer
  • @widgetVar(name): 指定されたコンポーネントによって識別されるwidgetVar

これらのキーワードを 、 などの複合式に混在させることもでき@form:@parentます@this:@parent:@parent

PrimeFaces Selectors (PFS) as in を@(.someclass)使用すると、jQuery CSS セレクター構文を介してコンポーネントを参照できます。たとえば、HTML 出力ですべての共通スタイル クラスを持つコンポーネントを参照します。これは、「大量の」コンポーネントを参照する必要がある場合に特に役立ちます。これは、ターゲット コンポーネントが HTML 出力にすべてのクライアント ID を持っていることのみを前提としています (固定か自動生成かは関係ありません)。update="@(.myClass)" のような PrimeFaces セレクターはどのように機能しますか?も参照してください。

于 2011-12-27T12:42:53.870 に答える
9

まず第一に、私が知る限り、タブビュー内にダイアログを配置することは悪い習慣です...あなたはそれを取り除いたほうがいいです...

そして今あなたの質問に:

申し訳ありませんが、実装したいものを正確に取得するのに時間がかかりました。

ちょうど今、自分の Web アプリで自分でやったのですが、うまくいきました

前に言ったように、 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>  

同じことが私の Web アプリでも機能します。それが機能しない場合は、Java Bean コードに何か問題があると思います...

于 2011-12-26T09:11:19.593 に答える
5

これは、タブが名前付けコンテナーでもあるためです...更新は次のようにする必要がありupdate="Search:insTable:display"ます。ダイアログをフォームの外側に配置し、タブの内側に配置するだけで、次のようになります。update="Search:display"

于 2011-12-26T10:59:36.327 に答える
1

これには 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: タブから参照される式 "BogusUpdate" のコンポーネントが見つかりません :insTable: BogusButton

したがって、使用する正しい clientId は、太字にターゲット コンテナーの ID (この場合は表示) を加えたものになります。

tabs:insTable:display
于 2019-03-21T14:20:27.260 に答える
0

に変更update="insTable:display"してみてくださいupdate="display"。そのようなフォーム ID を id の前に付けることはできないと思います。

于 2011-12-26T09:25:56.717 に答える