Why does a commandLink within a facet within a composite component renders an error?
Asked Answered
S

2

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)

Spearwort answered 13/8, 2015 at 18:40 Comment(6)
Same output is rendered for Mojarra 2.1.6 (except for the orange bullet points).Chane
I wonder if you're maybe just misusing facets (ref and ref). 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".Chane
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 #6822500Pollster
@DavidS It is not the h:form but this component that is accepting a facet called someFacet:presumably further content for the form.Pilchard
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.Spearwort
This is still a problem in Mojarra 2.3.3.Ment
M
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).

Mancunian answered 19/12, 2017 at 12:5 Comment(0)
M
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.

Ment answered 8/12, 2020 at 14:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.