Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
492 views
in Technique[技术] by (71.8m points)

validation - Validate readonly components anyway on form submit

We have a UI for an entity that either has an instrument or an issuer, but never both. You can select one of each from a popup search dialog and assign it to the entity.

The user can see the number and name of each of the two next to the "Search..." button. Both of these must be non-editable, that is we the the respective <p:inputText ... readonly="true" ... /> to grey out the inputs.

The requirement we have now is that not only a validation message is supposed to be shown when either none or both of the instrument and issuer are selected, but also that the text boxes tagged with readonly="true" are shown in red (along with their labels).

When adding, before pressing "Save":

enter image description here

When adding, after pressing "Save":

enter image description here

I tried a few things and then I ended up with OmniFaces <o:validateMultiple>, which seemed to go into the right direction. However, I then noticed that the validator didn't kick in, as you can see from the images... (I just removed the readonly="true" for you to see the effect)

Here's the code excerpt:

<!-- this panel is insider a form, yes -->
<h:panelGroup id="subpanel"
              layout="block">
    <o:validateMultiple id="instrument-or-issuer-validator"
                        validator="#{barrierCrossingManager.validateInstrumentOrIssuer}"
                        components="instrument-isin instrument-description issuer-number issuer-name"
                        message="..." />
    <!-- some panel grid with the inputs -->
    ...
        <p:panelGrid id="issuer-subpanel">
            <p:row>
                <p:column>
                    <p:outputLabel for="issuer-number" value="#{msg['common.number.label']}:" />
                </p:column>
                <p:column colspan="3">
                    <p:inputText id="issuer-number"
                                 value="#{barrierCrossingManager.selectedIssuer.nbr}"
                                 readonly="false" />
                </p:column>
                ...
            </p:row>
        </p:panelGrid>
    ...
    <h:messages id="msgs"
                layout="list"
                styleClass="subcontent-validation-msg-wrapper"
                showDetail="false"
                showSummary="true" />
</h:panelGroup>

Q:

How do you solve this?

The problem seems to be that OmniFaces or JSF(?) doesn't do validation of readonly components. I also looked at the OmniFaces VDL for <o:validateMultiple>, but there wasn't a flag like allowReadOnlyComponentHighlighting or similar.

Is there another way?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

JSF will for security reasons indeed skip readonly (and disabled) fields from processing (conversion, validation and model update). You don't want a hacker to be able to edit those values anyway by manipulating the request parameters, right? OmniFaces will also skip them the same way for obvious security reasons.

Your best bet is putting an EL expression in readonly attribute which evaluates false during apply request values and validations phases (the 2nd and 3rd phase), but true during all other phases. It suffices to check if the current phase ordinal is 4 or greater. This should allow JSF to perform validation on the value anyway. Then, you need to add an EL expression to the rendered attribute which evaluates false during update model values phase (the 4th phase), so that the model value won't be updated because readonly was false during apply request values and validations phases (and thus the component has its local value set, which triggers the model update).

You can obtain the current JSF phase by FacesContext#getCurrentPhaseId() which is in EL also available by #{facesContext.currentPhaseId}. The PhaseId has in turn a getOrdinal() method returning the phase index (from 1 until with 6 for the standard phases).

Summarized, this should do in order to validate them anyway, but prevent model update:

<p:inputText
    readonly="#{facesContext.currentPhaseId.ordinal ge 4}" 
    rendered="#{facesContext.currentPhaseId.ordinal ne 4}" 
/>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...