Search code examples
jsfviewparams

JSF - built-in methods that create url query string from f:param and includeViewParams


Most of my page navigation uses get requests and now I have a form where the parameters should be included as query-string parameters using f:param inside h:commandButton or checking attributes for includeViewParams to use UIViewParameter.

I do not want to use includeViewParams since this would include all view defined parameters, I just want to use the ones provided as child's of the command component.

<h:form>
    <p:inputText value="#{bean.value1}"/>
    <p:selectOneMenu value="#{bean.value2}"/>
    <p:commandButton action="#{utilBean.performActionParams(outcome)}">
        <f:param name="key1" value="#{bean.value1}"/>
        <o:param name="key1" value="#{bean.value2}" converter="#{bean.converter}/>
    </p:commandButton>
</h:form>

public String performActionParams(final String outcome)
{
    final UriBuilder uriBuilder = UriBuilder.fromPath(outcome);

    final FacesContext context = FacesContext.getCurrentInstance();
    final UIComponent component = UIComponent.getCurrentComponent(context);

    for (final UIComponent child : component.getChildren())
        if (child instanceof UIParameter)
        {
            final UIParameter param = (UIParameter) child;

            if (!param.isDisable() && !StringUtils.isBlank(param.getName()))
            {
                final Object value = param.getValue();

                if (value != null)
                    uriBuilder.queryParam(param.getName(), value);
            }
        }

    return uriBuilder.build().toString();
}

This logic is not really complicated but it seems so redundant since it seems to be the same logic as in h:link and h:button.

So does someone knows where this logic is implemented?


Solution

  • In Mojarra, this kind of logic is also buried in OutcomeTargetRenderer#getEncodedTargetURL() (and in HtmlBasicRenderer#getParamList()). The only public part which is provided by the API is the ViewHandler#getBookmarkableURL(), however it takes a Map as parameter map, not a list of UIParameter components.

    I'm not sure what the concrete functional requirement is, but so far it seems that you actually want to fire a simple GET request and not a POST request. In that case, you should be using <h:link> or <h:button> (or <p:button>). Their renderers extend from OutcomeTargetRenderer having this logic internally implemented. You can just use EL in outcome attribute (the probable assumption that this is not possible was perhaps your reason why you tried a command button).

    <p:button outcome="#{outcome}">
        <f:param name="key1" value="#{value1}" />
        <o:param name="key1" value="#{value2}" converter="#{bean.converter}" />
    </p:button>
    

    Update: as per the comments, the concrete functional requirement is basically to turn a JSF POST form along with the submitted data into a GET request. In that case, it'd be easier if you bind the inputs to a Map which is ready for use in getBookmarkableURL().

    <h:inputText value="#{bean.params.key1}" />
    <h:inputText value="#{bean.params.key2}" />
    <p:commandButton value="#{bean.submit(outcome)}" />
    

    with

    private Map<String, String> params;
    
    @PostConstruct
    public void init() {
        params = new HashMap<>();
    }
    
    public String submit(outcome) {
        // ...
    
        return context.getApplication().getViewHandler()
            .getBookmarkableURL(context, outcome, params, false);
    
        // TODO: Is faces-redirect=true also considered?
    }