我想在纯java中编写自定义jsf组件而不使用xhtml .

我使用Mojarra 2.2和Primefaces 5.1 .

到目前为止这是它 .

import java.io.IOException;
import java.util.Date;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UINamingContainer;
import javax.faces.component.html.HtmlPanelGroup;
import javax.faces.context.FacesContext;
import javax.faces.event.FacesEvent;
import org.primefaces.behavior.ajax.AjaxBehavior;
import org.primefaces.component.autocomplete.AutoComplete;
import org.primefaces.component.commandbutton.CommandButton;
import org.primefaces.component.inputtext.InputText;

@FacesComponent(createTag = true, tagName = "picker", namespace = "http://jsdfdemo")
public class Picker extends UINamingContainer {

    private String text;

    public Picker() {

    }

    @Override
    public void processRestoreState(FacesContext context, Object state) {
        super.processRestoreState(context, state); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        if (!context.isPostback()) {
            HtmlPanelGroup rootPanel = new HtmlPanelGroup();
            rootPanel.setLayout("block");
            rootPanel.setId("root_panel");

            InputText autoComplete = new InputText();
            autoComplete.setId("autocomplete");
            autoComplete.setValue(this.text);
            CommandButton clearButton = new CommandButton();
            clearButton.setId("clear");
            clearButton.setValue("Clear");
            CommandButton pickButton = new CommandButton();
            pickButton.setAjax(true);
            pickButton.setUpdate("@form");
            pickButton.setId("pick");
            pickButton.setValue("Pick");

            AjaxBehavior pickClickBehavior = new AjaxBehavior();
            pickClickBehavior.setUpdate(autoComplete.getId());
            pickClickBehavior.setProcess("@this");
            pickButton.addClientBehavior(pickButton.getDefaultEventName(), pickClickBehavior);

            rootPanel.getChildren().add(autoComplete);
            rootPanel.getChildren().add(clearButton);
            rootPanel.getChildren().add(pickButton);

            this.getChildren().add(rootPanel);
        }
        super.encodeBegin(context); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void decode(FacesContext context) {
        super.decode(context); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void queueEvent(FacesEvent event) {
        super.queueEvent(event);
        if (event.getComponent().equals(this.getPickButton())) {
            this.getAutoComplete().setValue(new Date());
        }
    }

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

    public HtmlPanelGroup getRootPanel() {
        return (HtmlPanelGroup) this.findComponent("root");
    }

    public InputText getAutoComplete() {
        return (InputText) this.findComponent("autocomplete");
    }

    public CommandButton getClearButton() {
        return (CommandButton) this.findComponent("clear");
    }

    public CommandButton getPickButton() {
        return (CommandButton) this.findComponent("pick");
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

我想选择按钮来更改autoComplete的值(实际上是一个InputText) . 我在自定义组件的 queueEvent 方法中执行此操作 . 我不知道这是否适合这样做 .

我也不确定 encodeBegin 是构建组件树的正确位置 . if(!context.isPostback()) 确保组件仅在初始GET上创建一次,但不能用于回发请求 .

这是呈现给客户端的内容 .

<div id="j_idt43:j_idt44:root_panel">
    <input id="j_idt43:j_idt44:autocomplete" 
            name="j_idt43:j_idt44:autocomplete" 
            type="text" 
            class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all" 
            role="textbox" 
            aria-disabled="false"
            aria-readonly="false">
    <button id="j_idt43:j_idt44:clear" 
            name="j_idt43:j_idt44:clear" 
            class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" 
            onclick="PrimeFaces.ab({s:'j_idt43:j_idt44:clear'});return false;" 
            type="submit" 
            role="button" 
            aria-disabled="false">
        <span class="ui-button-text ui-c">Clear</span>
    </button>
    <button id="j_idt43:j_idt44:pick" 
            name="j_idt43:j_idt44:pick" 
            class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" 
            onclick="PrimeFaces.bcn(this,event,[function(event){PrimeFaces.ab({s:'j_idt43:j_idt44:pick',e:'click',p:'j_idt43:j_idt44:pick',u:'j_idt43:j_idt44:autocomplete'});},function(event){PrimeFaces.ab({s:'j_idt43:j_idt44:pick',u:'j_idt43'});return false;}]);" 
            type="submit" 
            role="button" 
            aria-disabled="false">
            <span class="ui-button-text ui-c">Pick</span>
    </button>
</div>

这里的问题是,单击选择按钮时会触发两个AJAX请求,尽管只注册了一个 AjaxBehavior . 第一个表现得像预期的那样 . 视图已更新,我可以在输入文本组件中看到当前日期 . 但随后会触发第二个AJAX请求(在第一次完成之后)并清除输入文本 .

第一个请求的参数是 .

javax.faces.partial.ajax:true
javax.faces.source:j_idt43:j_idt44:pick
javax.faces.partial.execute:j_idt43:j_idt44:pick
javax.faces.partial.render:j_idt43:j_idt44:autocomplete
javax.faces.behavior.event:click
javax.faces.partial.event:click
j_idt43:j_idt43
j_idt43:j_idt44:autocomplete:
javax.faces.ViewState:3283049963151483162:-8986718217282610712

第二是 .

javax.faces.partial.ajax:true
javax.faces.source:j_idt43:j_idt44:pick
javax.faces.partial.execute:@all
javax.faces.partial.render:j_idt43
j_idt43:j_idt44:pick:j_idt43:j_idt44:pick
j_idt43:j_idt43
j_idt43:j_idt44:autocomplete:Mon Jan 25 11:17:05 CET 2016
javax.faces.ViewState:3283049963151483162:-8986718217282610712

有什么建议?