asked
2021-06-05 06:23:16 +0800
Jtt 107 ● 4 As per design, I need to validate if some fields are complete or not in two separate methods, one to move to another part of the form and another when trying to finish.
I wanted to use ZK as much as possible since the code can get very verbose for this type of forms in Java. So, I used validators for my required fields, getting the expected result when trying to move the next part of the form with invalid inputs.
When trying to finish the form, I also need to check other fields in the backend and display a showNotification popup alongside the errorMessage in my inputs, but so far I'm not able to do so. My first idea was to "time" differently the validators depending on what action is taking, as follows (there are textbox too, with value instead of selectedItem)
<listbox selectedItem="@load(vm.list.item) @save(vm.list.item, before={'nextPage'}, after={'finish'}) @validator(vm.validator)" >
But the result wasn't the one desired.
I can do all these validations without* Validator, but that's exactly what I'm trying to avoid, and that's why I ask now, is there a way to let a command run BEFORE the validators or something like that?
I've tried using the snippet above, both commands on before, and 'finish' before 'nextPage' with the same not desired result: All the errorMessages but not the showNotification.
Any help would be appreciated! Thank you and have a great weekend!
EDIT
Further details:
When the validator triggers for the 'nextPage' command, all the invalid inputs should show the corresponding error message. This is working as intended.
When the validator triggers for the 'finish' command, an aditional validation takes place and, if said validation fails, a showNotification popup is created, along with the behaviour of the 'nextPage' command. I also need to add, this showNotification only happens when the 'finish' command is called and the 'nextPage' hasn't been triggered yet. Inside this so called 'nextPage' form, users can't leave until completition (All this events are independent and working as intenteded already), meaning that there's only one case when this behaviour differs. This is the one I'm having problems with.
I thought of adding the additional behaviour on every validator, but that would mean having the showNotification triggered up to 6 times, and other methods seem too hacky to my liking.
Aditional code (I'm omiting divs and other attributes not really important):
<textbox name="required" value="@load(vm.uF.nombre ne null ? vm.uF.nombre : '') @save(vm.uF.nombre, before={'finish', 'nextPage'}) @validator(vm.validatorNombre)"/>
<textbox value="@load(vm.uF.nombres ne null ? vm.uF.nombres : '') @save(vm.uF.nombres)"/>
<textbox name="required" value="@load(vm.uF.primerApellido ne null ? vm.uF.primerApellido : '') @save(vm.uF.primerApellido, before={'finish', 'nextPage'}) @validator(vm.validatorApellido)"/>
<textbox placeholder="Segundo apellido" value="@load(vm.uF.segundoApellido ne null ? vm.uF.segundoApellido : '') @save(vm.uF.segundoApellido)"/>
<textbox name="required" value="@load(vm.uC.numNomina ne null ? vm.uC.numNomina : '') @save(vm.uC.numNomina, before={'finish', 'nextPage'}) @validator(vm.validatorNomina)"/>
<textbox placeholder="RFC *" name="required" value="@load(vm.uP.rfc ne null ? vm.uP.rfc : '') @save(vm.uP.rfc, before={'finish', 'nextPage'}) @validator(vm.validatorRfc)"/>
<bandbox id="bDepto" name="required" value="@load(vm.listaDeptos.itemSeleccionado.nombreTipo)">
<bandpopup>
<div>
<listbox model="@load(vm.listaDeptos.items)" selectedItem="@load(vm.listaDeptos.itemSeleccionado) @save(vm.listaDeptos.itemSeleccionado, before={'finish', 'nextPage'}) @validator(vm.validatorDepto)">
<template name="model">
<listitem>
<listcell>
<label/>
</listcell>
</listitem>
</template>
</listbox>
</div>
</bandpopup>
</bandbox>
<bandbox id="bPuesto" name="required" value="@load(vm.listaPuestos.itemSeleccionado.nombreTipo)">
<bandpopup>
<div>
<listbox model="@load(vm.listaPuestos.items)" selectedItem="@load(vm.listaPuestos.itemSeleccionado) @save(vm.listaPuestos.itemSeleccionado, before={'finish', 'nextPage'}) @validator(vm.validatorPuestos)">
<template name="model">
<listitem>
<listcell>
<label/>
</listcell>
</listitem>
</template>
</listbox>
</div>
</bandpopup>
</bandbox>
And the validators are:
public void validatorNombre(ValidationContext ctx) {
Textbox input = (Textbox) ctx.getBindContext().getComponent();
if (input.getValue() == null || input.getValue().isEmpty()) {
input.setErrorMessage(REQUERIDO);
ctx.setInvalid();
}
else if (!validaciones.unaPalabra(sn.normalize(input.getValue()))) {
input.setErrorMessage(FORMATO);
ctx.setInvalid();
}
}
public void validatorApellido(ValidationContext ctx) {
Textbox input = (Textbox) ctx.getBindContext().getComponent();
if (input.getValue() == null || input.getValue().isEmpty()) {
input.setErrorMessage(REQUERIDO);
ctx.setInvalid();
}
else if (!validaciones.dosOMasPalabras(sn.normalize(input.getValue()))) {
input.setErrorMessage(FORMATO);
ctx.setInvalid();
}
}
public void validatorRfc(ValidationContext ctx) {
Textbox input = (Textbox) ctx.getBindContext().getComponent();
if (input.getValue() == null || input.getValue().isEmpty()) {
input.setErrorMessage(REQUERIDO);
ctx.setInvalid();
}
else if (!validaciones.validarRFCFisica(sn.normalize(input.getValue()))) {
input.setErrorMessage(FORMATO);
ctx.setInvalid();
}
else if (personaRepository.findThisRfc(input.getValue().toUpperCase()).isPresent()) {
Clients.showNotification(EXISTENTE, "warning", input, "end_center", 0, false);
ctx.setInvalid();
}
}
public void validatorNomina(ValidationContext ctx) {
Textbox input = (Textbox) ctx.getBindContext().getComponent();
String num = input.getValue();
if (num == null || num.isEmpty()) {
input.setErrorMessage(REQUERIDO);
ctx.setInvalid();
}
else if (!num.matches("\\d+")) {
input.setErrorMessage(FORMATO);
ctx.setInvalid();
}
else if (colaboradoresRepository.findNumeroNomina(num.trim()).isPresent()) {
Clients.showNotification(EXISTENTE, "warning", input, "end_center", 0, false);
ctx.setInvalid();
}
}
public void validatorDepto() {
if(uC.getTiposDepartamentos() == null) {
bDepto.setErrorMessage(REQUERIDO);
bDepto.invalidate();
}
}
public void validatorPuesto() {
if(uC.getTiposPuestos() == null) {
bPuesto.setErrorMessage(REQUERIDO);
bPuesto.invalidate();
}
}
Note: I currently have them as void because I kept experimenting, but all these methods started as Validators as per the documentation.
Aditionally, the added behaviour for the 'finish' command is validated with the following code, that checks on the fields of the next page of the form.
if(ctx.getCommand().equals("finish") && !isSecondPageSet())
Clients.showNotification(INCOMPLETO, "error", null, "middle_center", 0, false);
EDIT 2:
This form is a popup window. In it, users have access to two pages.
In the first one, users have 6 required inputs (Everyone with an independent validator). To access the second page, users must have filled the required inputs with no errors.
They just can't finish at this point as the data in the second page is required.
In the second page, users have 4 fields to select nationality and current residence (one for national and one for foreigner for each pair). If neither nationality nor residence is selected, users can't go back to the first page nor finish the form.
The problem/complicated bit about 'finish' in the first page:
The finish button is always present in this window due a design choise upon wich I have no control over (Not to mention that at this point this template is standard in our webapp and changing it would be a lot of work for our front-end team). Because of this, users can use the 'finish' button at any given point, but we will prevent it working depending of the nature of each window.
In the case of the one I'm working on, the 'finish' button checks the completition of both pages of the form. If the first page is ready but the second page is not, then the showNotification shall pop up. That's the only case where that should happen. If the user tries to change pages without filling the required fields, the validators will do their work. As you mentioned, thanks to ctx.getCommand() I can control if the showNotification pops up or not for this case.
As a summary:
If user:
'finish' -> With filled form (Both pages) -> Proceeds
-> With filled form (First page) -> showNotification
-> Incorrectly filled form -> invalidate + showNotification *
- Since the validation for the Notification is handled by a command, the execution stops before it taking place, now I understand.
One workaround (the easiest one, at least) is to add my needed validation in every validator, meaning that it would be triggered up to 6 times, which while I doubt is particulary bad for performance, is not really an ideal solution.
This is how this window should work. As of right now, I used the workaround but I will change it as soon I find a better way to do it. It does the job since I check along the validators, is just the amount of time it has to be called what's bugging me.
By the way, thank you very much for the time you're putting helping me out. I really appreciate it.