Script is not rendered after postback in a composite component added programmatically

柔情痞子 提交于 2019-12-06 11:14:24

The solution (workaround) is to remove all script from the composite component and create a backing component for it to do precisely what JSF was supposed to do:

package br.edu.company.project.view.inputmask;

import java.io.IOException;
import java.util.Map;

import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.omnifaces.util.FacesLocal;

@FacesComponent("inputMask")
public class InputMask extends UIInput implements NamingContainer
{
    private static final String SCRIPT_FILE_WRITTEN =
        "br.edu.company.project.SCRIPT_FILE_WRITTEN";

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

    @Override
    public void encodeBegin(FacesContext context) throws IOException
    {
        writeScriptFileIfNotWrittenYet(context);

        super.encodeBegin(context);
    }

    @Override
    public void encodeEnd(FacesContext context) throws IOException
    {
        super.encodeEnd(context);

        writeMaskDefinition(context);
    }

    private void writeScriptFileIfNotWrittenYet(FacesContext context) throws IOException
    {
        if (FacesLocal.getRequestMap(context).putIfAbsent(
            SCRIPT_FILE_WRITTEN, true) == null)
        {
            writeScript(context, w -> w.writeAttribute(
                "src", "resources/script/inputmask.js", null));
        }
    }

    private void writeMaskDefinition(FacesContext context) throws IOException
    {
        writeScript(context, w -> w.writeText(String.format(
            "defineMask('%s', '%s');", getClientId(),
            getAttributes().get("mask")), null));
    }

    private void writeScript(FacesContext context, WriteAction writeAction)
        throws IOException
    {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("script", this);
        writer.writeAttribute("type", "text/javascript", null);
        writeAction.execute(writer);
        writer.endElement("script");
    }

    @FunctionalInterface
    private static interface WriteAction
    {
        void execute(ResponseWriter writer) throws IOException;
    }
}

Again, you don't need this if your composite component won't be included programmatically. In this case, JSF works as expected and you don't need the backing component.

If someone have the time, I think it would be nice to file a bug report to the Mojarra team.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!