Search code examples
jsfjsf-2composite-component

Get form data in Backing Component from Composite Component


My Composite Component contains the following form:

<cc:interface componentType="answerCompositeComponent">
    <cc:attribute name="AnswerType" type="code.elephant.domainmodel.AnswerType" required="true" />
    <cc:attribute name="ItemSource" type="code.elephant.domainmodel.Answer" required="true" />
    <cc:attribute name="QuestionId" type="java.lang.Long" required="true" />
</cc:interface>
<cc:implementation>
    <input jsf:id="sc#{cc.attrs.ItemSource.answerId}" />
</cc:implementation>

How can I access the value of the <input jsf:id="sc#{cc.attrs.ItemSource.answerId}" /> in my Backing Component? I tried the following in my backing bean in the overriden processUpdates method.

Answer ItemSource = (Answer) getValueExpression("ItemSource").getValue(context.getELContext());
String formid = String.format("sc%d", ItemSource.getAnswerId());
String get = context.getExternalContext().getRequestParameterMap().get(formid);

String get is always null. Is there a way to get the value of the input?

PS: I know that using plain html in jsf is not the purpose of it. I'm just interessted how my plan is achievable.


Solution

  • I never used plain html with jsf attributes, so I don't know if it's applicable.

    Generally, this is a common way to access nested components in a composite:

    <cc:interface componentType="answerCompositeComponent">
        <cc:attribute name="AnswerType" type="code.elephant.domainmodel.AnswerType" required="true" />
        <cc:attribute name="ItemSource" type="code.elephant.domainmodel.Answer" required="true" />
        <cc:attribute name="QuestionId" type="java.lang.Long" required="true" />
    </cc:interface>
    <cc:implementation>
        <h:inputText id="questionInput" binding="#{cc.input}" />
    
        <!-- maybe something like this might work
            <input jsf:id="questionInput" jsf:binding="#{cc.input}" />
        -->
    </cc:implementation>
    

    where

    @FacesComponent("answerCompositeComponent")
    public class AnswerCompositeComponent extends UINamingContainer
    {
        private UIInput input;
    
        @Override
        public void processUpdates(FacesContext context)
        {
            super.processUpdates(context);
    
            Object value = input.getValue();
            Object localValue = input.getLocalValue();
            Object submittedValue = input.getSubmittedValue();
    
            // do your things with values 
        }
    
        public UIInput getInput()
        {
            return input;
        }
    
        public void setInput(UIInput input)
        {
            this.input = input;
        }
    }
    

    Note that a composite backing component is a NamingContainer, so prefer static (or none at all) nested component IDs. Avoid dynamic IDs, unless you really need them and you know exactly what you're doing.