Primefaces p:confirmDialog inside tabView

2019-05-28 06:12发布

I now have problem with using confirmDialog inside tabView. Here is my confirmDialog

<p:confirmDialog global="true" showEffect="fade" hideEffect="explode">
    <h:form>
        <p:commandButton value="Yes" type="button"
            styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
        <p:commandButton value="No" type="button"
            styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
    </h:form>
</p:confirmDialog>

In the 1st tabView, I have a button with confirmation

<p:commandButton value="Import" icon="ui-icon-arrowrefresh-1-w"
    update=":form:growl">
    <p:confirm header="Confirmation" message="Are you sure?" />
</p:commandButton>

In the 2nd tabView, I have exactly that button.

And now my problem is: In the 1st tab, my confirmDialog have full text as I want: header and message, however in the 2nd tab, the header and message all become "null". Only button yes and no of confirmDialog still work. I don't know what is happening, please help me, how to make confirmDialog display full content in all tabView

3条回答
叼着烟拽天下
2楼-- · 2019-05-28 06:26

p:confirm does not implement state saving, thus it loses its attributes' values after the first JSF lifecycle. It also evaluates EL only once at view build time.

How to fix state saving.

You can extends PrimeFaces' ConfirmBehavior, implement saveState, restoreState, and override the original behavior in faces-config.xml by behavior-id org.primefaces.behavior.ConfirmBehavior. Then you'll be able to render and re-render p:confirm on subsequent requests.

How to fix state saving and reevaluate EL bound attribute values.

You should create your own my:confirm, because you need a custom taghandler, and you can't substitute a taghandler of another taglibrary's tag in a non-ugly way.

Create ConfirmBehavior.

package my;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.context.FacesContext;

import org.primefaces.behavior.base.AbstractBehavior;
import org.primefaces.component.api.Confirmable;
import org.primefaces.json.JSONObject;

public class ConfirmBehavior extends AbstractBehavior {

    public final static String BEHAVIOR_ID = "my.ConfirmBehavior";

    @Override
    public String getScript(ClientBehaviorContext behaviorContext) {
        FacesContext context = behaviorContext.getFacesContext();
        UIComponent component = behaviorContext.getComponent();
        String source = component.getClientId(context);
        String headerText = JSONObject.quote(this.getHeader());
        String messageText = JSONObject.quote(this.getMessage());

        if (component instanceof Confirmable) {
            String script = "PrimeFaces.confirm({source:\"" + source + "\",header:" + headerText + ",message:"
                    + messageText + ",icon:\"" + getIcon() + "\"});return false;";
            ((Confirmable) component).setConfirmationScript(script);

            return null;
        } else {
            throw new FacesException("Component " + source + " is not a Confirmable. ConfirmBehavior can only be "
                    + "attached to components that implement org.primefaces.component.api.Confirmable interface");
        }
    }

    public String getHeader() {
        return eval(PropertyKeys.header, null);
    }

    public void setHeader(String header) {
        setLiteral(PropertyKeys.header, header);
    }

    public String getMessage() {
        return eval(PropertyKeys.message, null);
    }

    public void setMessage(String message) {
        setLiteral(PropertyKeys.message, message);
    }

    public String getIcon() {
        return eval(PropertyKeys.icon, null);
    }

    public void setIcon(String icon) {
        setLiteral(PropertyKeys.icon, icon);
    }

    public enum PropertyKeys {
        header(String.class), message(String.class), icon(String.class);

        final Class<?> expectedType;

        PropertyKeys(Class<?> expectedType) {
            this.expectedType = expectedType;
        }
    }

    @Override
    protected Enum<?>[] getAllProperties() {
        return PropertyKeys.values();
    }

}

Create ConfirmBehaviorHandler.

package my;

import javax.faces.application.Application;
import javax.faces.view.facelets.BehaviorConfig;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.TagAttribute;

import org.primefaces.behavior.base.AbstractBehaviorHandler;

public class ConfirmBehaviorHandler extends AbstractBehaviorHandler<ConfirmBehavior> {

    private final TagAttribute header;
    private final TagAttribute message;
    private final TagAttribute icon;

    public ConfirmBehaviorHandler(BehaviorConfig config) {
        super(config);
        this.header = this.getAttribute(ConfirmBehavior.PropertyKeys.header.name());
        this.message = this.getAttribute(ConfirmBehavior.PropertyKeys.message.name());
        this.icon = this.getAttribute(ConfirmBehavior.PropertyKeys.icon.name());
    }

    @Override
    protected ConfirmBehavior createBehavior(FaceletContext ctx, String eventName) {
        Application application = ctx.getFacesContext().getApplication();
        ConfirmBehavior behavior = (ConfirmBehavior) application.createBehavior(ConfirmBehavior.BEHAVIOR_ID);

        setBehaviorAttribute(ctx, behavior, this.header, ConfirmBehavior.PropertyKeys.header.expectedType);
        setBehaviorAttribute(ctx, behavior, this.message, ConfirmBehavior.PropertyKeys.message.expectedType);
        setBehaviorAttribute(ctx, behavior, this.icon, ConfirmBehavior.PropertyKeys.icon.expectedType);

        return behavior;
    }

}

Register ConfirmBehavior in faces-config.xml.

<?xml version="1.0" encoding="utf-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

    <behavior>
        <behavior-id>my.ConfirmBehavior</behavior-id>
        <behavior-class>my.ConfirmBehavior</behavior-class>
    </behavior>

</faces-config>

Register ConfirmBehaviorHandler in your taglibrary my.taglib.xml.

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd"
    version="2.2">

    <namespace>http://mycompany.ru/my</namespace>

    <tag>
        <tag-name>confirm</tag-name>
        <behavior>
            <behavior-id>my.ConfirmBehavior</behavior-id>
            <handler-class>my.ConfirmBehaviorHandler</handler-class>
        </behavior>
    </tag>

</facelet-taglib>

Now you can use my:confirm, just as you would use p:confirm, but with state saving and dynamic EL evaluation.

查看更多
Melony?
3楼-- · 2019-05-28 06:42

I had the same problem with the component. The proposed solution of removing the dynamic true works, but when we have to work in a dialog does not meet because the data are no longer updated automatically resulting in that the fields are blank. If this happens you must perform the following action. Ex:.

       <p:commandButton  style="font-size: 12px;width:30px;height:20px;"  icon="ui-icon-trash">
            <p:confirm header="Confirmação" message="Você realmente quer excluir o item de despacho?" icon="ui-icon-alert" />
       </p:commandButton>
       <p:growl id="growl" showDetail="true" />
       <p:confirmDialog global="true" showEffect="fade" hideEffect="explode" style="font-size: 12px;" closeOnEscape="true" widgetVar="confir">
            <p:commandButton id="confirm" value="Sim" ajax="true"  type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check"  style="font-size: 12px;">
                <p:ajax event="click" listener="#{tableExpedicao.excluiItem}" update="confirm" oncomplete="confir.hide()"> </p:ajax>
            </p:commandButton>
            <p:commandButton value="Não" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" style="font-size: 12px;" oncomplete="confir.hide()"/>
     </p:confirmDialog>
查看更多
Evening l夕情丶
4楼-- · 2019-05-28 06:43

It seems to work ok for me. See example below

<?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:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>JSF User Dialog</title>
</h:head>
<h:body>
    <h3>This is a JSF view.</h3>
    <h:form id="form">
        <p:confirmDialog global="true" showEffect="fade" hideEffect="explode">
            <h:form>
                <p:commandButton value="Yes" type="button"
                    styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
                <p:commandButton value="No" type="button"
                    styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
            </h:form>
        </p:confirmDialog>

        <p:tabView id="tabView">

            <p:tab id="tab1" title="Tab one ">
                <p:commandButton value="Import" icon="ui-icon-arrowrefresh-1-w"
                    update=":form">
                    <p:confirm header="Confirmation" message="Are you sure?" />
                </p:commandButton>
            </p:tab>

            <p:tab id="tab2" title="Tab two">
                <p:commandButton value="Import" icon="ui-icon-arrowrefresh-1-w"
                    update=":form">
                    <p:confirm header="Confirmation" message="Are you sure?" />
                </p:commandButton>
            </p:tab>


        </p:tabView>
    </h:form>
</h:body>
</html>

Output:

Tab 1 with dialog box Tab 2 with dialog box

It would be good if you post your full xhtml code so we can see what could be the problem there.

查看更多
登录 后发表回答