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.