6

When I create a composite component with a facet in it and place a command link within that facet, I get an error message: This link is disabled as it is not nested within a JSF form.

A commandButton does not behave in the same way, so I am inclined to this this is a bug.

index.xhtml :

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:mycomp="http://xmlns.jcp.org/jsf/composite/mycomp"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
    </h:head>
    <h:body>
        <mycomp:component>
            <f:facet name="someFacet">
                <h:commandLink value="this link should work, but does not (within form, within facet)"/><br/>
                <h:commandButton value="this button works as expected (within form, within facet)"/><br/>
            </f:facet>
        </mycomp:component>
    </h:body>
</html>

/resources/mycomp/component.xhtml :

<?xml version='1.0' encoding='UTF-8' ?>
<ui:component
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:cc="http://xmlns.jcp.org/jsf/composite"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:a="http://xmlns.jcp.org/jsf/passthrough"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    >
    <cc:interface>
        <cc:facet name="someFacet" required="true"/>
    </cc:interface>
    <cc:implementation>
        <h:commandLink value="this link should not work (not in a form)"/><br/>
        <h:form>
            <h:commandLink value="this link works as expected (within form, but not in facet)"/><br/>
            <cc:renderFacet name="someFacet"/>
        </h:form>
    </cc:implementation>
</ui:component>

This is what my browser makes of it:

enter image description here

Any ideas as to what I may be doing wrong or is this indeed a bug in Mojarra 2.2.7? (which came bundled with NetBeans 8.0.2)

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Leo Mekenkamp
  • 217
  • 2
  • 7
  • Same output is rendered for Mojarra 2.1.6 (except for the orange bullet points). – DavidS Aug 13 '15 at 19:02
  • I wonder if you're maybe just misusing facets ([ref](https://stackoverflow.com/questions/24937757/ffacet-not-working-with-hform) and [ref](https://stackoverflow.com/questions/25251019/jsf-ffacet-contents-not-rendered)). I've never been entirely clear on facets myself, but they seems to be a way of providing inputs to the parent component. `form` does not accept a facet named `someFacet`, so the behaviour is undefined. I'm not certain though, so I won't post an "answer". – DavidS Aug 13 '15 at 19:07
  • This is indeed a bug. You'd best just report it. However, having a form inside a composite is in turn a design smell. Doesn't your composite do "too much"? See also http://stackoverflow.com/questions/6822000/when-to-use-uiinclude-tag-files-composite-components-and-or-custom-componen – BalusC Aug 13 '15 at 22:54
  • 1
    @DavidS It is not the `h:form` but *this component* that is accepting a facet called `someFacet`:presumably further content for the form. – user207421 Aug 14 '15 at 01:08
  • Yes, maybe I am trying too hard here; I was attempting to create a composite that takes two sets of `commandLink` components to build a menu structure. The html that needs to be rendered is already defined, so there is no getting around the two sets. – Leo Mekenkamp Aug 16 '15 at 19:31
  • This is still a problem in Mojarra 2.3.3. – Vsevolod Golovanov Dec 08 '20 at 13:16

2 Answers2

1

an old thread but i think the current behaviour is a bug, because the following works, and so it should work in a composite component:

component.xhtml:

<?xml version='1.0' encoding='UTF-8' ?>
<ui:component
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:a="http://xmlns.jcp.org/jsf/passthrough"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
>
<cc:interface>
    <cc:facet name="someFacet" required="true"/>
</cc:interface>
<cc:implementation>
    <h:commandLink value="this link should not work (not in a form)"/><br/>
        <h:commandLink value="this link works as expected (within form, but not in facet)"/><br/>
        <cc:renderFacet name="someFacet"/>
</cc:implementation>
</ui:component>

Using it (index.xhtml):

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:mycomp="http://xmlns.jcp.org/jsf/composite/mycomp"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
    </h:head>
    <h:body>
     <h:form>
        <mycomp:component>
            <f:facet name="someFacet">
                <h:commandLink value="this link should work, but does not (within form, within facet)"/><br/>
                <h:commandButton value="this button works as expected (within form, within facet)"/><br/>
            </f:facet>
        </mycomp:component>
      </h:form>
    </h:body>
</html>

Also the generated HTML output in both cases generates the button in the right place in the component tree (under the form). But the clientId generated for the button, differs in both cases:

  • First thread post --> clientId without form ID
  • My post --> clientId includes form ID

In my opinion this seems to be a bug, but perhaps someone can convince me that it is not ;D

Using Mojarra 2.2.13 (Primefaces 6.x).

Daniel K.
  • 41
  • 5
0

I'm doing the same thing, except I'm inserting a PrimeFaces' p:commandButton via the facet - the button works, the only problem are the warnings, so I'm providing a solution for those.

Add a componentType:

<cc:interface componentType="myComponent">

And a corresponing java class:

import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.UIOutput;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;

@FacesComponent
public class MyComponent extends UIOutput /* or UINamingContainer - depends on what you need */ {

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override
    public boolean visitTree(VisitContext context, VisitCallback callback) {
        // skip the form checks; we know the form is guaranteed by the component anyway
        String callbackName = callback.getClass().getName();
        if (callbackName.contains("ValidateFormNestingCallback") || callbackName.contains("FormOmittedChecker")) {
            return false;
        }

        return super.visitTree(context, callback);
    }

}

Tested with Mojarra 2.3.3.

Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65