Validate cell editing in Primefaces using a Validator

时间:2016-08-31 17:13:00

标签: validation jsf jsf-2 primefaces jsf-2.2

I have a datatable as following :

<p:dataTable id="dataTablePlanningSalleAppareil"
             styleClass="dataTablePlanningSalleAppareil"
             editable="true" editMode="cell"
             value="#{beanPlanningSalleAppareil.getListPlanningSalleAppareilBySalleOrACAndDay(entry, jour.key)}"
             var="planning"
             sortBy="#{planning.heureDebut}">

    <p:ajax event="cellEdit"
            listener="#{beanPlanningSalleAppareil.onCellEdit}"
            update=":#{p:component('gestionPlanningSalleAppareilMessage')}">
    </p:ajax>

    <p:columnGroup type="header">
        <p:row>
            <p:column colspan="3" headerText="#{jour.value}" style="width:100px" />
        </p:row>
    </p:columnGroup>

    <p:column>
        <p:cellEditor rendered="#{planning.id != 0}" >
            <f:facet name="output"> <h:outputText value="#{planning.heureDebut}" /></f:facet>
            <f:facet name="input">
                <p:inputMask mask="99:99" value="#{planning.heureDebut}"
                             required="true" maxlength="4"
                             requiredMessage="Heure de début : vous devez indiquer une valeur.">
                    <f:validator validatorId="planningSalleAppareilFormuleCremationValidator" />
                    <f:attribute name="planningId" value="#{planning.id}" />
                </p:inputMask>
            </f:facet>
        </p:cellEditor>
    </p:column>
    <p:column  rendered='#{beanListPlanningSalleAppareil.acceuil.valeur eq "1"}'>
        <p:cellEditor rendered="#{planning.id != 0}">
            <f:facet name="output">
                <f:facet name="output">
                    <h:outputText value="#{planning.formuleCremation.alias}" /></f:facet>
            </f:facet>
            <f:facet name="input">
                <h:selectOneMenu value="#{planning.formuleCremation}" converter="#{formuleCremationConverter}">
                    <f:selectItems value="#{beanPlanningSalleAppareil.formules}"
                                   var="formule"
                                   itemLabel="#{formule.alias}"
                                   itemValue="#{formule}" />
                    <f:validator validatorId="planningSalleAppareilFormuleCremationValidator" />
                    <f:attribute name="planningId" value="#{planning.id}" />
                </h:selectOneMenu>
            </f:facet>
        </p:cellEditor>
    </p:column>
    <p:column >
        <p:row>
            <p:commandLink rendered="#{planning.id != 0}"
                           action="#{beanPlanningSalleAppareil.setSelectedPlanning(planning)}"
                           oncomplete="suppressionConfirmation.show()" process="@this" ajax="true">
                <h:graphicImage styleClass="ui-icon ui-icon-closethick" style="display: inline-block;"/>
            </p:commandLink>
        </p:row>
    </p:column>
</p:dataTable>

this datatable is editable and I can edit two cells planning.heureDebut and planning.formuleCremation.

So what I want to do is to do some verifications before the update can be performed, and I will check on the current row and the new value of the cell, so to know which row I'm modifying I added an attribute as following :

<f:attribute name="planningId" value="#{planning.id}" />

And for that I created a this validator :

@FacesValidator("planningSalleAppareilFormuleCremationValidator")
public class PlanningSalleAppareilFormuleCremationValidator implements Validator {
    private static final Logger LOG = Logger.getLogger(PlanningSalleAppareilFormuleCremationValidator.class);
    @Autowired
    private IPlanningSalleAppareilService planningSalleAppareilService;

    public PlanningSalleAppareilFormuleCremationValidator() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        ServletContext servletContext = (ServletContext) externalContext.getContext();
        WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).
                                   getAutowireCapableBeanFactory().
                                   autowireBean(this);
    }

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException {

        int id = (int) uic.getAttributes().get("planningId");

        //The selected Salle or Appareil
        Object selectedObject = null;
        //Current Planning
        PlanningSalleAppareil planningSalleAppareil = planningSalleAppareilService.trouver(id);

        if(planningSalleAppareil.getAppareil() != null)
            selectedObject = planningSalleAppareil.getAppareil();
        if(planningSalleAppareil.getSalle() != null)
            selectedObject = planningSalleAppareil.getSalle();

        if(o instanceof FormuleCremation)
            planningSalleAppareil.setFormuleCremation((FormuleCremation) o);

        if(o instanceof String)
            planningSalleAppareil.setHeureDebut((String) o);

        if(selectedObject != null){
            String errorMessage = planningSalleAppareilService.validPlanningSalleAppareil(planningSalleAppareil,selectedObject);
            if(!errorMessage.equals("1")){
                FacesMessage msg = new FacesMessage(errorMessage);
                    msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                throw new ValidatorException(msg);
            }
        }
    }
}

So what I'm doing is when I modify planning.heureDebut or planning.formuleCremation for the row that has the id I passed with <f:attribute name="planningId" value="#{planning.id}" /> and I get it from the database as following :

int id = (int) uic.getAttributes().get("planningId");
PlanningSalleAppareil planningSalleAppareil = planningSalleAppareilService.trouver(id);

Then I set the new value I've edited to this planningSalleAppareil and then I call the verification function from the service.

So the behavior I'm getting is that when I edit some cell, my application saves the new value to the database before it calls the validator, so when it calls the validator, the validation will always fail since the service method will always get the object with the new value.

For example if I have a row like this :

planning.id = 1
planning.heureDebut = 18:00
...

and then when I edit the column for planning.heureDebut like this :

planning.heureDebut = 20:00

It should perform validation before it updates the new value for planning.heureDebut so it will call the service method planningSalleAppareilService.trouver(id); which will return a planning with planning.heureDebut = 18:00, but the service method returns a planning with planning.heureDebut = 20:00 which means the update has been performed before it calls the validator.

So how can I prevent this to happen ? and how can I call the validation before the update ?

0 个答案:

没有答案