6. Client-side JavaScript-validatie
In het vorige hoofdstuk hebben we gekeken naar validatie aan de serverzijde. Laten we terugkeren naar de architectuur van een Spring-applicatie MVC:
![]() |
BD
Tot nu toe bevatten de pagina's die naar de client werden verzonden geen JavaScript. We gaan nu in op deze technologie, waarmee we in eerste instantie client-side validaties kunnen uitvoeren. Het principe is als volgt:
- het is JavaScript dat de waarden naar de webserver verstuurt;
- en dus kan het vóór deze POST de geldigheid van de gegevens controleren en de POST verhinderen als deze ongeldig zijn;
We gaan het formulier gebruiken dat we aan de serverzijde hebben gevalideerd. We gaan nu de mogelijkheid bieden om het zowel aan de clientzijde als aan de serverzijde te valideren.
Opmerking: dit is een complex onderwerp. Lezers die hier geen interesse in hebben, kunnen direct doorgaan naar paragraaf 7.
6.1. De functionaliteiten van het project
We presenteren enkele weergaven van het project om de functionaliteiten ervan te illustreren. De startpagina wordt gegenereerd met de URL [http://localhost:8080/js01.html]
![]() |
De validaties zijn aan beide kanten geïmplementeerd: aan de clientzijde en aan de serverzijde. Aangezien de POST alleen plaatsvindt als de waarden aan de clientzijde als geldig zijn beschouwd, slagen de validaties aan de serverzijde altijd. Er is daarom een link toegevoegd om de validaties aan de clientzijde uit te schakelen. In deze modus geldt dezelfde werkwijze die we al eerder hebben besproken. Hier volgt een voorbeeld:
123 ![]() |
- in [1], de ingevoerde waarden;
- in [2], de foutmeldingen met betrekking tot de invoer;
- in [3], een overzicht van de fouten met voor elke fout:
- de naam van het gevalideerde veld,
- de foutcode,
- de standaardmelding voor deze foutcode;
Laten we nu de validatie aan de clientzijde toestaan:
![]() |
- in [1], de ingevoerde waarden. We zien dat de foutieve invoer een specifieke opmaak heeft;
- in [2], de foutmeldingen die bij de foutieve invoer horen. Deze zijn identiek aan die welke door de server worden gegenereerd;
- in [3-4] staat niets meer, want zolang er foutieve invoer is, vindt de POST naar de server niet plaats;
6.2. Validatie aan de serverzijde
6.2.1. Configuratie
We beginnen met het aanmaken van een nieuw Maven-project [springmvc-validation-client]:
![]() |
We breiden het project als volgt uit:
![]() |
De klasse [Config] configureert het project. Deze is identiek aan die in de vorige projecten:
package istia.st.springmvc.config;
import java.util.Locale;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
@Configuration
@ComponentScan({ "istia.st.springmvc.controllers", "istia.st.springmvc.models" })
@EnableAutoConfiguration
public class Config extends WebMvcConfigurerAdapter {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
return messageSource;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Bean
public CookieLocaleResolver localeResolver() {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setCookieName("lang");
localeResolver.setDefaultLocale(new Locale("fr"));
return localeResolver;
}
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".xml");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCacheable(true);
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
@Bean
SpringTemplateEngine templateEngine(SpringResourceTemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
}
De klasse [Main] is de uitvoerbare klasse van het project:
package istia.st.springmvc.main;
import istia.st.springmvc.config.Config;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
public class Main {
public static void main(String[] args) {
// de applicatie wordt gestart
ApplicationContext context = SpringApplication.run(Config.class, args);
// de lijst met door Spring gevonden beans wordt weergegeven
System.out.println("Liste des beans Spring");
String[] beanNames = context.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
- regel 13: Spring Boot wordt gestart met het configuratiebestand [Config];
- regels 15-20: ter illustratie laten we zien hoe je de lijst met door Spring beheerde objecten kunt weergeven. Dit kan handig zijn als je soms het gevoel hebt dat Spring een van je componenten niet beheert. Zo kun je dit controleren. Het is ook een manier om de automatische configuratie door Spring Boot te controleren. In de console krijg je een lijst die er ongeveer zo uitziet:
We hebben de objecten gemarkeerd die zijn gedefinieerd in de klasse [Config].
6.2.2. Het formuliermodel
Laten we verdergaan met het verkennen van het project:
![]() |
De klasse [Form01] is de klasse die de verzonden waarden zal ontvangen. Deze ziet er als volgt uit:
package istia.st.springmvc.models;
import java.util.Date;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Future;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import org.springframework.format.annotation.DateTimeFormat;
public class Form01 {
// verzonden waarden
@NotNull
@AssertFalse
private Boolean assertFalse;
@NotNull
@AssertTrue
private Boolean assertTrue;
@NotNull
@Future
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInFuture;
@NotNull
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInPast;
@NotNull
@Max(value = 100)
private Integer intMax100;
@NotNull
@Min(value = 10)
private Integer intMin10;
@NotNull
@NotBlank
private String strNotEmpty;
@NotNull
@Size(min = 4, max = 6)
private String strBetween4and6;
@NotNull
@Pattern(regexp = "^\\d{2}:\\d{2}:\\d{2}$")
private String hhmmss;
@NotNull
@Email
@NotBlank
private String email;
@NotNull
@Length(max = 4, min = 4)
private String str4;
@Range(min = 10, max = 14)
@NotNull
private Integer int1014;
@NotNull
@DecimalMax(value = "3.4")
@DecimalMin(value = "2.3")
private Double double1;
@NotNull
private Double double2;
@NotNull
private Double double3;
@URL
@NotBlank
private String url;
// validatie door de client
private boolean clientValidation = true;
// lokaal
private String lang;
...
}
We zien hier validatoren terug die we al eerder zijn tegengekomen. Daarnaast introduceren we het begrip ‘specifieke validatie’. Dit is een validatie die niet met een vooraf gedefinieerde validator kan worden geformaliseerd. We gaan hier eisen dat [double1+double2] binnen het interval [10,13] valt.
6.2.3. De controller
De validator [JsController] ziet er als volgt uit:
![]() |
package istia.st.springmvc.controllers;
import istia.st.springmvc.models.Form01;
...
@Controller
public class JsController {
@RequestMapping(value = "/js01", method = RequestMethod.GET, produces = "text/html; charset=UTF-8")
public String js01(Form01 formulaire, Locale locale, Model model) {
setModel(formulaire, model, locale, null);
return "vue-01";
}
...
// voorbereiding van het view-sjabloon vue-01
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
...
}
}
- regel 9: de actie [/js01];
- regel 10: er wordt een object van het type [Form01] geïnstantieerd en automatisch in het sjabloon geplaatst, gekoppeld aan de sleutel [form01];
- regel 10: de locale en het sjabloon worden in de parameters ingevoerd;
- regel 11: met deze informatie wordt het model voorbereid;
- regel 12: de weergave [vue-01.xml] wordt weergegeven;
De methode [setModel] is als volgt:
// voorbereiding van het model voor de weergave vue-01
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
// er worden alleen de taalversies fr-FR en en-US ondersteund
String language = locale.getLanguage();
String country = null;
if (language.equals("fr")) {
country = "FR";
formulaire.setLang("fr_FR");
}
if (language.equals("en")) {
country = "US";
formulaire.setLang("en_US");
}
model.addAttribute("locale", String.format("%s-%s", language, country));
// de eventuele melding
if (message != null) {
model.addAttribute("message", message);
}
}
- het doel van de methode [setModel] is om in het sjabloon het volgende op te nemen:
- informatie over de locale,
- het bericht dat als laatste parameter is doorgegeven;
- regel 14: er wordt informatie over de locale (taal, land) in het sjabloon geplaatst;
- regels 16-18: het eventuele bericht dat als parameter is doorgegeven, wordt in de locale geplaatst;
- regels 8, 12: de informatie over de locale wordt ook opgeslagen in het formulier [Form01]. Het JavaScript zal deze informatie gebruiken;
De waarden die in het formulier [vue-01.xml] zijn ingevoerd, worden verzonden naar de volgende actie [/js02]:
@RequestMapping(value = "/js02", method = RequestMethod.POST, produces = "text/html; charset=UTF-8")
public String js02(@Valid Form01 formulaire, BindingResult result, RedirectAttributes redirectAttributes, Locale locale, Model model) {
Form01Validator validator = new Form01Validator(10, 13);
validator.validate(formulaire, result);
...
}
- regel 2: de annotatie [@Valid Form01 formulaire] zorgt ervoor dat de verzonden waarden worden onderworpen aan de validatoren van de klasse [Form01]. We weten dat er een specifieke validatie [double1+double2] bestaat binnen het interval [10,13]. Wanneer we bij regel 3 aankomen, is deze validatie nog niet uitgevoerd;
- regel 3: het volgende object [Form01Validator] wordt aangemaakt:
![]() |
package istia.st.springmvc.validators;
import istia.st.springmvc.models.Form01;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class Form01Validator implements Validator {
// het validatie-interval
private double min;
private double max;
// constructor
public Form01Validator(double min, double max) {
this.min = min;
this.max = max;
}
@Override
public boolean supports(Class<?> classe) {
return Form01.class.equals(classe);
}
@Override
public void validate(Object form, Errors errors) {
// gevalideerd object
Form01 form01 = (Form01) form;
// de waarde van [double1]
Double double1 = form01.getDouble1();
if (double1 == null) {
return;
}
// de waarde van [double2]
Double double2 = form01.getDouble2();
if (double2 == null) {
return;
}
// [double1+double2]
double somme = double1 + double2;
// validatie
if (somme < min || somme > max) {
errors.rejectValue("double2", "form01.double2", new Double[] { min, max }, null);
}
}
}
- regel 8: om een specifieke validatie te implementeren, maken we een klasse die de Spring-interface [Validator] implementeert. Deze interface heeft twee methoden: [supports] op regel 21 en [validate] op regel 26;
- regels 21-23: de methode [supports] ontvangt een object van het type [Class]. Deze moet true retourneren om aan te geven dat deze klasse wordt ondersteund, en false in het tegenovergestelde geval;
- regel 22: we stellen dat de klasse [Form01Validator] alleen objecten van het type [Form01] valideert;
- regels 15-18: laten we niet vergeten dat we de beperking [double1+double2] willen implementeren in het interval [10,13]. in plaats van ons aan dit interval te houden, gaan we de beperking [double1+double2] controleren binnen het interval [min, max]. Daarom hebben we een constructor met deze twee parameters;
- regel 26: de methode [validate] wordt aangeroepen met een instantie van het gevalideerde object, dus hier een instantie van [Form01], en met de verzameling van de momenteel bekende fouten [Errors errors]. Als de validatie door de methode [validate] mislukt, moet deze een nieuw element aanmaken in de verzameling [Errors errors];
- regel 43: de validatie is mislukt. Er wordt een element toegevoegd aan de verzameling [Errors errors] met de methode [Errors.rejectValue], waarvan de parameters als volgt zijn:
- parameter 1: meestal de naam van het foutieve veld. Hier zijn de velden [double1, double2] getest. Men kan een van beide opgeven,
- de bijbehorende foutmelding of, om precies te zijn, de sleutel ervan in de geëxternaliseerde foutmeldingsbestanden:
[messages_fr.properties]
form01.double2=[double2+double1] doit être dans l''intervalle [{0},{1}]
[messages_en.properties]
form01.double2=[double2+double1] must be in [{0},{1}
Dit zijn berichten die zijn geconfigureerd met {0} en {1}. Er moeten dus twee waarden aan dit bericht worden doorgegeven. Dit is wat de derde parameter van de methode [Errors.rejectValue] doet.
- De vierde parameter is een standaardfoutmelding;
Laten we teruggaan naar de actie [/js02]:
@RequestMapping(value = "/js02", method = RequestMethod.POST, produces = "text/html; charset=UTF-8")
public String js02(@Valid Form01 formulaire, BindingResult result, RedirectAttributes redirectAttributes, Locale locale, Model model) {
Form01Validator validator = new Form01Validator(10, 13);
validator.validate(formulaire, result);
if (result.hasErrors()) {
StringBuffer buffer = new StringBuffer();
for (ObjectError error : result.getAllErrors()) {
buffer.append(String.format("[name=%s,code=%s,message=%s]", error.getObjectName(), error.getCode(), error.getDefaultMessage()));
}
setModel(formulaire, model, locale, buffer.toString());
return "vue-01";
} else {
redirectAttributes.addFlashAttribute("form01", formulaire);
return "redirect:/js01.html";
}
}
- regel 4: de validator [Form01Validator] wordt uitgevoerd met de volgende parameters:
- parameter 1: het object dat wordt gevalideerd,
- parameter 2: de lijst met fouten van dit object. Dit is het object [BindingResult result] dat als parameter aan de actie is doorgegeven. Als de validatie mislukt, krijgt dit object er een fout bij;
- regel 5: er wordt gecontroleerd of er validatiefouten zijn;
- regels 7-10: we doorlopen de lijst met fouten om voor elke fout het volgende op te slaan:
- de naam van het gevalideerde object,
- de foutcode,
- de standaardfoutmelding;
- regel 10: met deze informatie wordt het model van de weergave [vue-01.xml] opgebouwd. Deze keer is er één bericht, namelijk de samengevoegde en verkorte versie van de verschillende foutmeldingen;
- regels 12-15: als alle verzonden waarden geldig zijn, wordt de klant doorgestuurd naar de actie [/js01], waarbij de verzonden waarden als Flash-attribuut worden meegestuurd;
6.2.4. De weergave
De weergave [vue-01.xml] is complex. We zullen slechts een klein deel ervan presenteren:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
<script type="text/javascript" src="/js/jquery/jquery-1.10.2.min.js"></script>
...
</head>
<body>
<!-- titel -->
<h3>
<span th:text="#{form01.title}"></span>
<span th:text="${locale}"></span>
</h3>
<!-- menu -->
<p>
...
</p>
<!-- formulier -->
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
<table>
<thead>
<tr>
<th class="col1" th:text="#{form01.col1}">Contrainte</th>
<th class="col2" th:text="#{form01.col2}">Saisie</th>
<th class="col3" th:text="#{form01.col3}">Validation client</th>
<th class="col4" th:text="#{form01.col4}">Validation serveur</th>
</tr>
</thead>
<tbody>
<!-- verplicht -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
...
</tbody>
</table>
<p>
<!-- validatieknop -->
<input type="submit" th:value="#{form01.valider}" value="Valider" onclick="javascript:postForm01()" />
</p>
</form>
<!-- bericht van de server-side validatoren -->
<br/>
<fieldset class="fieldset">
<legend>
<span th:text="#{server.error.message}"></span>
</legend>
<span th:text="${message}" class="error"></span>
</fieldset>
</body>
</html>
Deze pagina maakt gebruik van een aantal berichten uit de geëxternaliseerde berichtenbestanden:
[messages_fr.properties]
form01.title=Formulaire - Validations côté client - locale=
form01.col1=Contrainte
form01.col2=Saisie
form01.col3=Validation client
form01.col4=Validation serveur
form01.valider=Valider
server.error.message=Erreurs détectées par les validateurs côté serveur
[messages_en.properties]
form01.title=Form - Client side validation - locale=
form01.col1=Constraint
form01.col2=Input
form01.col3=Client validation
form01.col4=Server validation
form01.valider=Validate
server.error.message=Errors detected by the validators on the server side
Laten we teruggaan naar de code van de pagina:
- regel 8: een groot aantal imports van JavaScript-bibliotheken die we hier kunnen negeren;
- regel 14: geeft de locale weer die door de server in het sjabloon is geplaatst;
- regel 59: geeft het bericht weer dat door de server in het sjabloon is geplaatst;
De code op de regels 33-44 is nieuw. Laten we deze eens bekijken:
<!-- verplicht -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
Het is misschien het eenvoudigst om de code HTML te bekijken die door dit Thymeleaf-segment wordt gegenereerd:
<!-- verplicht -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" value="" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
</td>
</tr>
Aan de clientzijde gaan we een validatiebibliotheek gebruiken met de naam [jquery.validate]. Alle attributen [data-x] zijn daarvoor bedoeld. Wanneer de validatie aan de clientzijde wordt uitgeschakeld, worden deze attributen niet gebruikt. Het heeft dus voorlopig geen zin om ze te begrijpen. We kunnen ons gewoon concentreren op de volgende Thymeleaf-regel:
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
die de volgende regel HTML genereert:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" value="" />
Hierboven is er een probleem bij het genereren van het attribuut [data-val-required="Le champ est obligatoire"]. De waarde die aan het attribuut is gekoppeld, is namelijk afkomstig uit de geëxternaliseerde berichtbestanden. We zijn dus genoodzaakt om een Thymeleaf-uitdrukking te gebruiken om deze te verkrijgen. Dit is de volgende uitdrukking: [th:attr="data-val-required=#{NotNull}"]. Deze uitdrukking wordt geëvalueerd en de waarde ervan wordt ongewijzigd in de gegenereerde tag HTML geplaatst. Deze heet [th:attr] omdat we deze gebruiken om attributen te genereren die niet vooraf in Thymeleaf zijn gedefinieerd. We zijn vooraf gedefinieerde attributen tegengekomen met de naam [th:text, th:value, th:class, ...], maar er bestaat geen attribuut met de naam [th:data-val-required].
6.2.5. Het stylesheet
Hierboven komen we klassen tegen met de naam CSS, zoals [class="field-validation-valid"]. Sommige van deze klassen worden gebruikt door de JavaScript-validatiebibliotheek. Ze zijn gedefinieerd in het volgende bestand [form01.css]:
![]() |
@CHARSET "UTF-8";
/*aangepaste stijlen*/
body {
background-image: url("/images/standard.jpg");
}
.col1 {
background: lightblue;
}
.col2 {
background: Cornsilk;
}
.col3 {
background: AliceBlue;
}
.col4 {
background: Lavender;
}
.error {
color: red;
}
.fieldset{
background: Lavender;
}
/* Stijlen voor validatiehulpprogramma's
-----------------------------------------------------------*/
.field-validation-error {
color: #f00;
}
.field-validation-valid {
display: none;
}
.input-validation-error {
border: 1px solid #f00;
background-color: #fee;
}
.validation-summary-errors {
font-weight: bold;
color: #f00;
}
.validation-summary-valid {
display: none;
}
6.3. Validatie aan de clientzijde
6.3.1. Basisbegrippen van jQuery en JavaScript
Client-side validatie gebeurt met JavaScript. We maken gebruik van het framework jQuery, dat talrijke functies biedt die de ontwikkeling van JavaScript vergemakkelijken. We bespreken de basisbegrippen van jQuery die u moet kennen om de scripts in dit hoofdstuk en de volgende hoofdstukken te begrijpen.
We maken een statisch bestand HTML [JQuery-01.html] aan dat we in een map [static / vues] plaatsen:
![]() |
Dit bestand heeft de volgende inhoud:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
</head>
<body>
<h3>Rudiments de JQuery</h3>
<div id="element1">
Elément 1
</div>
</body>
</html>
- regel 6: import van jQuery;
- regels 10-12: een element van de pagina met id [element1]. We gaan met dit element aan de slag.
We moeten het bestand [jquery-1.11.1.min.js] downloaden. De nieuwste versie van jQuery is te vinden in URL [http://jquery.com/download/]:

We plaatsen het gedownloade bestand in de map [static / js]:
![]() |
Zodra dit is gebeurd, roepen we de statische weergave [jQuery-01.html] op met Chrome [1-2]:
![]() |
Gebruik in Google Chrome de opdracht [Ctrl-Maj-I] om de ontwikkeltools [3] weer te geven. Via het tabblad [Console] [4] kunt u JavaScript-code uitvoeren. Hieronder geven we enkele JavaScript-opdrachten die je kunt invoeren, samen met een uitleg.
JS | resultaat |
|
: geeft de verzameling van alle elementen met de id [element1] weer, dus normaal gesproken een verzameling van 0 of 1 element, omdat er op een pagina HTML geen twee identieke id’s kunnen voorkomen. | ![]() |
|
: wijst de tekst [blabla] toe aan alle elementen in de verzameling. Dit heeft tot gevolg dat de inhoud die door de pagina wordt weergegeven, verandert | ![]() |
|
verbergt de elementen van de collectie. De tekst [blabla] wordt niet meer weergegeven. | ![]() |
|
: toont de collectie weer. Zo kunnen we zien dat het element met id [element1] het attribuut CSS style='display: none;' heeft, waardoor het element verborgen is. | |
|
: geeft de elementen van de collectie weer. De tekst [blabla] verschijnt opnieuw. Dit wordt mogelijk gemaakt door het attribuut CSS style='display: block;'. | ![]() |
|
: wijst een attribuut toe aan alle elementen van de verzameling. Het attribuut is hier [style] en de waarde ervan is [color: red]. De tekst [blabla] wordt rood weergegeven. | ![]() |
![]() | |
![]() |
Merk op dat de URL van de browser tijdens al deze bewerkingen niet is veranderd. Er heeft geen communicatie met de webserver plaatsgevonden. Alles gebeurt binnen de browser. Laten we nu de broncode van de pagina bekijken:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JQuery-01</title>
<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
</head>
<body>
<h3>Rudiments de JQuery</h3>
<div id="element1">
Elément 1
</div>
</body>
</html>
Dit is de oorspronkelijke tekst. Deze weerspiegelt op geen enkele manier de bewerkingen die we hebben uitgevoerd op het element in de regels 10-12. Het is belangrijk om dit in gedachten te houden bij het debuggen van JavaScript. Het is dan vaak zinloos om de broncode van de weergegeven pagina te bekijken.
We weten nu genoeg om de jS-scripts die hierna volgen te begrijpen.
6.3.2. De jS-bibliotheken voor validatie
We gaan bibliotheken uit het jQuery-ecosysteem gebruiken. Rondom jQuery draait een aantal projecten die op hun beurt weer bibliotheken voortbrengen. We gaan de validatiebibliotheek [jquery.validate.unobstrusive] gebruiken, die door Microsoft is gemaakt en aan de stichting jQuery is geschonken. We zullen deze voortaan de validatiebibliotheek MS noemen, of kortweg de bibliotheek MS. Om deze te verkrijgen, is een Microsoft Visual Studio-omgeving nodig. Ik heb geen andere manier gevonden om deze te verkrijgen. Je kunt een gratis versie gebruiken, zoals [Visual Studio Community] of [http://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx] (dec. 2014). Lezers die geen zin hebben om de onderstaande stappen te volgen, kunnen deze bibliotheek en de bibliotheken waarop deze is gebaseerd, downloaden via de voorbeelden op de website van dit document.
Maak een consoleproject aan met Visual Studio [1-4]:
|
![]() |
- in [5], het consoleproject;
- in [6-7]: we gaan [NuGet]-pakketten aan het project toevoegen. [NuGet] is een functie van Visual Studio waarmee bibliotheken in de vorm van DLL, maar ook jS-bibliotheken kunnen worden gedownload.
![]() |
- naar [9-10], zoek dan op het trefwoord [jQuery];
- naar [11-13], download dan in de aangegeven volgorde de bibliotheken jS die nodig zijn voor validatie aan de clientzijde;
- in [14]: download ook de bibliotheek [Microsoft jQuery Unobtrusive Ajax] die we straks gaan gebruiken;
![]() |
- zoek in [15-16] naar pakketten met het trefwoord [globalize];
- voor [17]: download de bibliotheek [jQuery.Validation.Globalize];
![]() |
Deze verschillende downloads hebben een aantal bibliotheken met de naam jS geïnstalleerd in de map [Scripts] van het project [18]. Ze zijn niet allemaal nuttig. Van elk bestand zijn er twee exemplaren:
- [js]: de leesbare versie van de bibliotheek;
- [min.js]: de onleesbare, zogenaamde ‘geminimaliseerde’ versie van de bibliotheek. Deze is niet echt onleesbaar. Het is gewoon tekst. Maar ze is niet begrijpelijk. Dit is de versie die in productie moet worden gebruikt, omdat dit bestand kleiner is dan de overeenkomstige versie [js] en daardoor de snelheid van de communicatie tussen client en server verbetert;
De versies [min.map] zijn niet onmisbaar. In de map [cultures] kun je alleen de culturen bewaren die door de applicatie worden beheerd.
Met Windows Verkenner kopieert u deze bestanden naar de map [static / js / jquery] van het project [springmvc-validation-client] en behoudt u alleen de nuttige bestanden [20]:
![]() |
In [21] behoudt men slechts twee culturen:
- [fr-FR]: het Frans van Frankrijk;
- [en-US]: het Engels van USA;
6.3.3. Importeren van de validatiebibliotheken jS
Om te kunnen worden gebruikt, moeten deze bibliotheken worden geïmporteerd via de weergave [vue-01.xml]:
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
<script type="text/javascript" src="/js/jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="/js/jquery/jquery.validate.min.js"></script>
<script type="text/javascript" src="/js/jquery/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/globalize.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.en-US.js"></script>
<script type="text/javascript" src="/js/client-validation.js"></script>
<script type="text/javascript" src="/js/local.js"></script>
<script th:inline="javascript">
/*<![CDATA[*/
var culture = [[${locale}]];
Globalize.culture(culture);
/*]]>*/
</script>
</head>
- regel 11: het importeren van een bestand jS waarover we nog niet hebben gesproken;
- regels 13-18: een script jS dat door Thymelaf wordt geïnterpreteerd. Dit script regelt de locale aan de clientzijde;
6.3.4. Beheer van de locale aan de clientzijde
De lokalisatie aan de clientzijde gebeurt door het volgende script jS:
<script th:inline="javascript">
/*<![CDATA[*/
var culture = [[${locale}]];
Globalize.culture(culture);
/*]]>*/
</script>
- regels 3-4: code jS waarin de Thymeleaf-uitdrukking [[${locale}]] voorkomt. Let op de specifieke syntaxis van deze uitdrukking. Dit komt doordat deze in JavaScript is geschreven. De uitdrukking [[${locale}]] wordt vervangen door de waarde van de sleutel [locale] uit het weergavemodel;
Het resultaat in de uit deze regels gegenereerde stream HTML is als volgt:
<script>
/*<![CDATA[*/
var culture = 'en-US';
Globalize.culture(culture);
/*]]>*/
</script>
De regels 3-4 stellen de client-side cultuur in. We beheren er slechts twee: [fr-FR] en [en-US]. Daarom hebben we slechts twee cultuurbestanden geïmporteerd:
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="/js/jquery/globalize/cultures/globalize.culture.en-US.js"></script>
De te gebruiken taal aan de clientzijde wordt aan de serverzijde vastgelegd. Laten we teruggaan naar de code aan de serverzijde:
@RequestMapping(value = "/js01", method = RequestMethod.GET, produces = "text/html; charset=UTF-8")
public String js01(Form01 formulaire, Locale locale, Model model) {
setModel(formulaire, model, locale, null);
return "vue-01";
}
// voorbereiding van het sjabloon voor weergave vue-01
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
// er worden alleen de taalvarianten fr-FR en en-US ondersteund
String language = locale.getLanguage();
String country = null;
if (language.equals("fr")) {
country = "FR";
formulaire.setLang("fr_FR");
}
if (language.equals("en")) {
country = "US";
formulaire.setLang("en_US");
}
model.addAttribute("locale", String.format("%s-%s", language, country));
...
}
- regel 20: de locale [fr-FR] of [en-US] wordt in het sjabloon van de weergave [vue-01.xml] geplaatst (regel 4). Er is echter een bron van complicaties. Terwijl een Franse locale aan de clientzijde wordt aangeduid als [fr-FR], wordt deze aan de serverzijde aangeduid als [fr_FR]. Daarom wordt deze, in de regels 14 en 18, in deze vorm opgeslagen in het object [Form01 formulaire], dat de verzonden waarden ontvangt;
Let op het volgende belangrijke punt. Het script
<script>
/*<![CDATA[*/
var culture = 'en-US';
Globalize.culture(culture);
/*]]>*/
</script>
past de cultuur van de client aan op basis van de door de server doorgegeven lokale instelling. Dit zorgt er niet voor dat de berichten die op de pagina worden weergegeven, worden geïnternationaliseerd. Het verandert alleen de manier waarop bepaalde informatie, die afhankelijk is van de cultuur van een land, wordt geïnterpreteerd. Met de cultuur [fr_FR] is het reële getal [12,78] geldig, terwijl het ongeldig is met de cultuur [en-US]. In dat geval moet [12.78] worden geschreven. Evenzo is de datum [12/01/2014] een geldige datum in de cultuur [fr-FR], terwijl men in de cultuur [en-US] [01/12/2014] moet schrijven. De bestanden in de map [jquery / globalize] bieden een oplossing voor dit soort problemen:
![]() |
De internationalisering van foutmeldingen wordt uitsluitend aan de serverzijde afgehandeld. We zullen zien dat de pagina HTML / jS foutmeldingen meevert die overeenkomen met de door de server ondersteunde locale: in het Frans voor de locale [fr_FR] en in het Engels voor de locale [en_US].
6.3.5. De berichtenbestanden
De weergave [vue-01.xml] maakt gebruik van de volgende geïnternationaliseerde berichten:
![]() |
[messages_fr.properties]
NotNull=Le champ est obligatoire
NotEmpty=La donnée ne peut être vide
NotBlank=La donnée ne peut être vide
typeMismatch=Format invalide
Future.form01.dateInFuture=La date doit être postérieure ou égale à celle d''aujourd'hui
Past.form01.dateInPast=La date doit être antérieure ou égale à celle d''aujourd'hui
Min.form01.intMin10=La valeur doit être supérieure ou égale à 10
Max.form01.intMax100=La valeur doit être inférieure ou égale à 100
Size.form01.strBetween4and6=La chaîne doit avoir entre 4 et 6 caractères
Length.form01.str4=La chaîne doit avoir quatre caractères exactement
Email.form01.email=Adresse mail invalide
URL.form01.url=URL invalide
Range.form01.int1014=La valeur doit être dans l''intervalle [10,14]
AssertTrue=Seule la valeur True est acceptée
AssertFalse=Seule la valeur False est acceptée
Pattern.form01.hhmmss=Tapez l''heure sous la forme hh:mm:ss
form01.hhmmss.pattern=^\\d{2}:\\d{2}:\\d{2}$
DateInvalide.form01=Date invalide
form01.str4.pattern=^.{4,4}$
form01.int1014.max=14
form01.int1014.min=10
form01.strBetween4and6.pattern=^.{4,6}$
form01.intMax100.value=100
form01.intMin10.value=10
form01.double1.min=2.3
form01.double1.max=3.4
Range.form01.double1=La valeur doit être dans l'intervalle [2,3-3,4]
form01.title=Formulaire - Validations côté client - locale=
form01.col1=Contrainte
form01.col2=Saisie
form01.col3=Validation client
form01.col4=Validation serveur
form01.valider=Valider
form01.double2=[double2+double1] doit être dans l''intervalle [{0},{1}]
form01.double3=[double3+double1] doit être dans l''intervalle [{0},{1}]
locale.fr=Français
locale.en=English
client.validation.true=Activer la validation client
client.validation.false=Inhiber la validation client
DecimalMin.form01.double1=Le nombre doit être supérieur ou égal à 2,3
DecimalMax.form01.double1=Le nombre doit être inférieur ou égal à 3,4
server.error.message=Erreurs détectées par les validateurs côté serveur
[messages_en.properties]
NotNull=Field is required
NotEmpty=Field can''t be empty
NotBlank=Field can''t be empty
typeMismatch=Invalid format
Future.form01.dateInFuture=Date must be greater or equal to today''s date
Past.form01.dateInPast=Date must be lower or equal today''s date
Min.form01.intMin10=Value must be higher or equal to 10
Max.form01.intMax100=Value must be lower or equal to 100
Size.form01.strBetween4and6=String must have between 4 and 6 characters
Length.form01.str4=String must be exactly 4 characters long
Email.form01.email=Invalid mail address
URL.form01.url=Invalid URL
Range.form01.int1014=Value must be in [10,14]
AssertTrue=Only value True is allowed
AssertFalse=Only value False is allowed
Pattern.form01.hhmmss=Time must follow the format hh:mm:ss
form01.hhmmss.pattern=^\\d{2}:\\d{2}:\\d{2}$
DateInvalide.form01=Invalid Date
form01.str4.pattern=^.{4,4}$
form01.int1014.max=14
form01.int1014.min=10
form01.strBetween4and6.pattern=^.{4,6}$
form01.intMax100.value=100
form01.intMin10.value=10
form01.double1.min=2.3
form01.double1.max=3.4
Range.form01.double1=Value must be in [2.3,3.4]
form01.title=Form - Client side validation - locale=
form01.col1=Constraint
form01.col2=Input
form01.col3=Client validation
form01.col4=Server validation
form01.valider=Validate
form01.double2=[double2+double1] must be in [{0},{1}]
form01.double3=[double3+double1] must be in [{0},{1}]
locale.fr=Français
locale.en=English
client.validation.true=Activate client validation
client.validation.false=Inhibate client validation
DecimalMin.form01.double1=Value must be greater or equal to 2.3
DecimalMax.form01.double1=Value must be lower or equal to 3.4
server.error.message=Errors detected by the validators on the server side
Het bestand [messages.properties] is een kopie van het bestand met Engelse berichten. Uiteindelijk zal elke locale die verschilt van [fr] Engelse berichten gebruiken. Ter herinnering: het bestand [messages_fr.properties] wordt gebruikt voor alle locale-instellingen van het type [fr_XX], zoals [fr_CA] of [fr_FR].
De weergave [vue-01.xml] maakt gebruik van de sleutels van deze berichten. Als de lezer de waarde wil weten die aan deze sleutels is gekoppeld, wordt hij verzocht terug te keren naar deze paragraaf om deze te ontdekken.
6.3.6. Wijziging van de locale
De weergave [vue-01.xml] bevat vier links:
<body>
<!-- titel -->
<h3>
<span th:text="#{form01.title}"></span>
<span th:text="${locale}"></span>
</h3>
<!-- menu -->
<p>
<a id="locale_fr" href="javascript:setLocale('fr_FR')">
<span th:text="#{locale.fr}"></span>
</a>
<a id="locale_en" href="javascript:setLocale('en_US')">
<span style="margin-left:30px" th:text="#{locale.en}"></span>
</a>
<a id="clientValidationTrue" href="javascript:setClientValidation(true)">
<span style="margin-left:30px" th:text="#{client.validation.true}"></span>
</a>
<a id="clientValidationFalse" href="javascript:setClientValidation(false)">
<span style="margin-left:30px" th:text="#{client.validation.false}"></span>
</a>
</p>
<!-- formulier -->
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
...
waarvan sommige hieronder worden weergegeven [1]:
![]() |
Laten we de twee links bekijken waarmee de taalinstelling kan worden gewijzigd naar Frans of Engels:
<a id="locale_fr" href="javascript:setLocale('fr_FR')">
<span th:text="#{locale.fr}"></span>
</a>
<a id="locale_en" href="javascript:setLocale('en_US')">
<span style="margin-left:30px" th:text="#{locale.en}"></span>
</a>
Als je op deze links klikt, wordt het script jS uitgevoerd, dat zich in het bestand [local.js] [2] bevindt. In beide gevallen wordt de functie jS [setLocale] aangeroepen:
// lokale instellingen
function setLocale(locale) {
// de locale wordt bijgewerkt
lang.val(locale);
// het formulier wordt verzonden – dit activeert de validaties aan de clientzijde niet – daarom is de validatie aan de clientzijde niet uitgeschakeld
document.form.submit();
}
Om regel 4 te begrijpen, is wat achtergrondinformatie nodig. De weergave [vue-01.xml] bevat een verborgen veld met de naam [lang]:
<input type="hidden" th:field="*{lang}" th:value="*{lang}" value="true" />
dat overeenkomt met een veld [lang] in [Form01]:
// locale
private String lang;
Verborgen velden zijn handig wanneer men de verzonden waarden wil aanvullen. Met JavaScript kan men ze een waarde toekennen en deze waarde wordt verzonden als een normale invoer door de gebruiker. De door Thymeleaf gegenereerde code HTML is als volgt:
<input type="hidden" value="en_US" id="lang" name="lang" />
De waarde van de parameter [value] is de waarde van het veld [Form01.lang] op het moment dat HTML wordt gegenereerd. Belangrijk om op te merken is de identificatiecode jS van het knooppunt [id="lang"]. Deze identificatiecode wordt gebruikt door de volgende functie []:
// globale variabelen
var lang;
// document gereed
$(document).ready(function() {
// globale verwijzingen
lang = $("#lang");
});
// lokaal
function setLocale(locale) {
// de locale wordt bijgewerkt
lang.val(locale);
// het formulier wordt verzonden – om een onbekende reden worden de validaties aan de clientzijde niet geactiveerd
// daarom is de validatie niet uitgeschakeld
document.form.submit();
}
- regels 5-8: de functie jS [$(document).ready(f)] is een functie die wordt uitgevoerd wanneer de browser het volledige, door de server verzonden document heeft geladen. De parameter ervan is een functie. De functie jS [$(document).ready(f)] wordt gebruikt om de omgeving jS van het geladen document te initialiseren;
- regel 7: de uitdrukking [$("#lang")] is een uitdrukking van het type jQuery. De waarde ervan is een verwijzing naar het knooppunt van het attribuut [id='lang'] van DOM;
- regel 2: variabelen die buiten een functie worden gedeclareerd, zijn globaal voor alle functies. Dit betekent hier dat de variabele [lang], die in [$(document).ready()] is geïnitialiseerd, ook bekend is in de functie [setLocale] op regel 11;
- regel 13: wijzigt het attribuut [value] van het knooppunt met ID [lang]. Als lang gelijk is aan [xx_XX], dan wordt de tag HTML van het knooppunt:
<input type="hidden" value="xx_XX" id="lang" name="lang" />
Met JavaScript kan de waarde van de elementen van DOM (Document Object Model) worden gewijzigd.
- regel 16: [document] verwijst naar DOM. [document.form] verwijst naar het eerste formulier dat in dit document wordt gevonden. Een HTML-document kan meerdere <form>-tags bevatten en dus meerdere formulieren. Hier hebben we er slechts één. [document.form.submit] verzendt dit formulier alsof de gebruiker op een knop met het attribuut [type='submit'] heeft geklikt. Naar welke actie worden de waarden van het formulier verzonden? Om dat te weten te komen, moet je de tag [form] van het formulier in [vue-01.xml] bekijken:
<!-- formulier -->
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
De actie die de verzonden waarden ontvangt, is de actie die wordt aangeduid door het attribuut [th:action]. Dit is dus de actie [/js02.html]. Ter herinnering: in deze naam wordt het achtervoegsel [.html] verwijderd, waardoor uiteindelijk de actie [/js02] wordt uitgevoerd. Het is belangrijk om te begrijpen dat de nieuwe waarde [xx_XX] van het knooppunt [lang] zal worden verzonden in de vorm [lang=xx_XX]. We hebben onze applicatie echter zo geconfigureerd dat de parameter [lang] wordt onderschept en geïnterpreteerd als een wijziging van de locale. Aan de serverzijde wordt de locale dus [xx_XX]. Laten we eens kijken naar de actie [/js02] die zal worden uitgevoerd:
@RequestMapping(value = "/js02", method = RequestMethod.POST, produces = "text/html; charset=UTF-8")
public String js02(@Valid Form01 formulaire, BindingResult result, RedirectAttributes redirectAttributes, Locale locale, Model model) {
Form01Validator validator = new Form01Validator(10, 13);
validator.validate(formulaire, result);
if (result.hasErrors()) {
StringBuffer buffer = new StringBuffer();
for (ObjectError error : result.getAllErrors()) {
buffer.append(String.format("[name=%s,code=%s,message=%s]", error.getObjectName(), error.getCode(),
error.getDefaultMessage()));
}
setModel(formulaire, model, locale, buffer.toString());
return "vue-01";
} else {
redirectAttributes.addFlashAttribute("form01", formulaire);
return "redirect:/js01.html";
}
}
// voorbereiding van het sjabloon voor weergave vue-01
private void setModel(Form01 formulaire, Model model, Locale locale, String message) {
// er worden alleen de lokale instellingen fr-FR en en-US ondersteund
String language = locale.getLanguage();
String country = null;
if (language.equals("fr")) {
country = "FR";
formulaire.setLang("fr_FR");
}
if (language.equals("en")) {
country = "US";
formulaire.setLang("en_US");
}
model.addAttribute("locale", String.format("%s-%s", language, country));
...
}
- regel 2: de actie [/js02] ontvangt de nieuwe locale [xx_XX], ingekapseld in de parameter [Locale locale]:
- regels 5-12: als sommige van de verzonden waarden ongeldig zijn, wordt de weergave [vue-01.xml] weergegeven met foutmeldingen die gebruikmaken van de nieuwe locale [xx_XX]. Bovendien zorgt regel 11 ervoor dat de variabele [locale=xx-XX] in het sjabloon wordt geplaatst. Aan de clientzijde wordt deze waarde gebruikt om de locale aan de clientzijde bij te werken. We hebben dit proces beschreven;
- regels 14-15: als alle verzonden waarden geldig zijn, vindt er een omleiding plaats naar de volgende actie [/js01]:
@RequestMapping(value = "/js01", method = RequestMethod.GET, produces = "text/html; charset=UTF-8")
public String js01(Form01 formulaire, Locale locale, Model model) {
setModel(formulaire, model, locale, null);
return "vue-01";
}
- regel 2: de nieuwe locale [xx_XX] wordt ingevoegd;
- regel 3: de methode [setModel] stelt vervolgens de cultuur van de client in op [xx-XX];
Laten we nu eens kijken naar de invloed van de locale in de weergave [vue-01.xml]. We hebben deze tot nu toe nog niet in zijn geheel weergegeven, omdat deze meer dan 300 regels telt. Het grootste deel van de regels bestaat echter uit de herhaling van een reeks die lijkt op de volgende:
<!-- verplicht -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
Deze code geeft het volgende fragment [1] weer:
![]() |
De foutmelding [2] is afkomstig van het attribuut [th:attr="data-val-required=#{NotNull}"] in regel 5. [#{NotNull}] is een gelokaliseerde melding. Afhankelijk van de serverlocale genereert regel 5 de tag:
<input type="text" data-val="true" data-val-required="Field is required" id="strNotEmpty" name="strNotEmpty" />
of de tag:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" />
De attributen [data-x] worden verwerkt door de validatiebibliotheek jS.
Uiteindelijk onthouden we dat de twee links voor het wijzigen van de locale:
- een POST van de ingevoerde waarden veroorzaken;
- de locale zowel aan de serverzijde als aan de clientzijde wijzigen;
- een HTML-pagina genereren die de foutmeldingen voor de validatiebibliotheek jS bevat, en dat deze meldingen in de taal van de gekozen locale zijn;
6.3.7. De POST van de ingevoerde waarden
Laten we de knop [Valider] bekijken, die de ingevoerde waarden uit de weergave [vue-01.xml] verstuurt. De code HTML is als volgt:
<!-- bevestigingsknop -->
<input type="submit" value="Valider" onclick="javascript:postForm01()" />
Als JavaScript in de browser is ingeschakeld, zal het klikken op de knop de uitvoering van de methode [postForm01] activeren. Als deze functie de booleaanse waarde [False] retourneert, zal submit niet worden uitgevoerd. Als de functie iets anders retourneert, zal deze wel worden uitgevoerd. Deze functie bevindt zich in het bestand [local.js]:
![]() |
Deze wordt geïmporteerd door de weergave [vue-01.xml] via regel 6 hieronder:
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
...
<script type="text/javascript" src="/js/local.js"></script>
</head>
In dit bestand staat de volgende code:
// globale variabelen
var formulaire;
var clientValidation;
var double1;
var double2;
var double3;
...
$(document).ready(function() {
// globale verwijzingen
formulaire = $("#form");
clientValidation = $("#clientValidation");
double1 = $("#double1");
double2 = $("#double2");
double3 = $("#double3");
...
});
....
// formulier verzenden
function postForm01() {
...
}
- regels 8-16: de functie jS [$(document).ready(f)] is een functie die wordt uitgevoerd wanneer de browser het volledige document dat door de server is verzonden, heeft geladen. De parameter ervan is een functie. De functie jS [$(document).ready(f)] wordt gebruikt om de omgeving jS van het geladen document te initialiseren;
- regels 10-14: om deze regels te begrijpen, moet men zowel de Thymeleaf-code als de gegenereerde HTML-code bekijken;
De betreffende Thymeleaf-code is als volgt:
<form action="/someURL" th:action="@{/js02.html}" method="post" th:object="${form01}" name="form" id="form">
...
<input type="text" th:field="*{double1}" th:value="*{double1}" ... />
...
<input type="text" th:field="*{double2}" th:value="*{double2}" />
...
<input type="text" th:field="*{double3}" th:value="*{double3}" ... />
...
<input type="hidden" th:field="*{clientValidation}" th:value="*{clientValidation}" value="true" />
die de volgende HTML-code genereert:
<form action="/js02.html" method="post" name="form" id="form">
...
<input type="text" id="double1" name="double1" .../>
....
<input type="text" value="" id="double2" name="double2" />
...
<input value="" id="double3" name="double3" .../>
...
<input type="hidden" value="false" id="clientValidation" name="clientValidation" />
Elk attribuut [th:field='x'] genereert twee attributen: HTML, [name='x'] en [id='x']. Het attribuut [name] is de naam van de verzonden waarden. De aanwezigheid van de attributen [name='x'] en [value='y'] voor een tag HTML <input type='text'> zorgt ervoor dat de tekenreeks x=y in de verzonden waarden name1=val1&name2=val2&... wordt opgenomen. Het attribuut [id='x'] wordt daarentegen door JavaScript gebruikt. Het dient om een element van het DOM (Document Object Model) te identificeren. Het geladen document HTML wordt namelijk omgezet in een JavaScript-boom met de naam DOM, waarin elk knooppunt wordt geïdentificeerd door zijn attribuut [id].
Laten we teruggaan naar de code van de functie [$(document).ready()]:
// globale variabelen
var formulaire;
var clientValidation;
var double1;
var double2;
var double3;
...
$(document).ready(function() {
// globale verwijzingen
formulaire = $("#form");
clientValidation = $("#clientValidation");
double1 = $("#double1");
double2 = $("#double2");
double3 = $("#double3");
...
});
....
// formulierverzending
function postForm01() {
...
}
- regel 10: de uitdrukking [$("#form")] is een uitdrukking van het type jQuery. De waarde ervan is een verwijzing naar het knooppunt van DOM met het attribuut [id='form '];
- regels 10-14: er worden verwijzingen opgehaald naar vijf knooppunten van DOM;
- regels 2-6: variabelen die buiten een functie worden gedeclareerd, zijn globaal voor alle functies. Dit betekent hier dat de variabelen [formulaire, clientValidation , double1, double2, double3] die in [$(document).ready()] zijn geïnitialiseerd, ook bekend zijn in de functie [postForm01] op regel 19;
Laten we nu de functie [postForm01] bekijken:
// formulier verzenden
function postForm01() {
// validatiemodus aan de clientzijde
var validationActive = clientValidation.val() === "true";
if (validationActive) {
// fouten van de server worden gewist
clearServerErrors();
// formuliervalidatie
if (!formulaire.validate().form()) {
// geen verzending
return false;
}
}
// getallen in Angelsaksisch formaat
var value1 = double1.val().replace(",", ".");
double1.val(value1);
var value2 = double2.val().replace(",", ".");
double2.val(value2);
var value3 = double3.val().replace(",", ".");
double3.val(value3);
// het verzenden wordt doorgevoerd
return true;
}
Laten we niet vergeten dat deze functie jS wordt uitgevoerd vóór de functie [submit] van het formulier. Als deze functie de booleaanse waarde [false] (regel 11) retourneert, vindt de verzending niet plaats. Als deze functie iets anders retourneert (regel 22), vindt de verzending wel plaats.
- De belangrijke code staat in de regels 4-12;
- regel 4: we halen de waarde op van het verborgen veld [clientValidation]. Deze waarde is 'true' als de validatie aan de clientzijde moet worden geactiveerd, 'false' anders;
- regel 6: in geval van validatie aan de clientzijde worden de eventuele foutmeldingen van de server gewist die aanwezig kunnen zijn omdat de gebruiker zojuist de locale heeft gewijzigd;
- regel 9: ter herinnering: de variabele [formulaire] vertegenwoordigt het knooppunt van de tag HTML <form>, dus het formulier. Dit formulier bevat validatoren jS die we nog niet hebben besproken en die in de volgende paragrafen aan bod zullen komen. De uitdrukking [formulaire.validate().form()] zorgt ervoor dat alle validatoren jS in het formulier worden uitgevoerd. De waarde ervan is [true] als alle geteste waarden geldig zijn, en [false] in het tegenovergestelde geval;
- regel 11: de waarde [false] wordt geretourneerd als ten minste één van de geteste waarden ongeldig is. Dit voorkomt dat de [submit] van het formulier naar de server wordt verzonden;
- regels 15-20: de identificatiecodes [double1, double2, double3] vertegenwoordigen de drie reële getallen uit het formulier. Afhankelijk van de cultuur verschilt de ingevoerde waarde. Bij de cultuur [fr-FR] wordt [10,37] ingevoerd, terwijl bij de cultuur [en-US] [10.37] wordt ingevoerd. Dit geldt voor de invoer. Bij de cultuur [fr-FR] zal de verzonden waarde voor [double1] eruitzien als [double1=10,37]. Eenmaal aangekomen op de server wordt de waarde [10,37] geweigerd, omdat de server [10.37] verwacht, het standaardformaat voor reële getallen in Java. Daarom wordt in de regels 15-20 in de ingevoerde waarde voor deze getallen de komma vervangen door een punt;
- regel 15: de uitdrukking [double1.val()] levert de ingevoerde tekenreeks op voor het knooppunt [double1]. De uitdrukking [double1.val().replace(",", ".")] vervangt in deze tekenreeks de komma's door punten. Het resultaat is de tekenreeks [value1];
- regel 16: de instructie [double1.val(value1)] wijst deze waarde [value1] toe aan het knooppunt [double1].
Technisch gezien geldt dat, als de gebruiker [10,37] heeft ingevoerd voor de werkelijke waarde [double1], dan heeft het knooppunt [double1] na de voorgaande instructies de waarde [10.37] en zal de waarde die wordt verzonden [param1=val1&double1=10.37¶m2=val2] zijn, een waarde die door de server wordt geaccepteerd;
- regel 22: we geven de waarde [true] terug zodat de [submit] van het formulier wordt uitgevoerd;
Let op: de functie jS [postForm01]:
- alle validatoren jS van het formulier uitvoert als validatie aan de clientzijde is ingeschakeld en voorkomt dat de functie [submit] van het formulier naar de server wordt verzonden als een van de ingevoerde waarden als ongeldig is aangemerkt;
- laat de validatie [submit] doorgaan, hetzij omdat validatie aan de clientzijde niet is ingeschakeld, hetzij omdat deze wel is ingeschakeld en alle ingevoerde waarden geldig zijn;
Dan blijft de instructie op regel [3] over:
// serverfouten worden gewist
clearServerErrors();
De functie [clearServerErrors] is bedoeld om de berichten in kolom 4 van de weergave [vue-01.xml] te wissen:
![]() |
In de bovenstaande schermafbeelding is op de link [English] geklikt. We hebben gezien dat dit leidde tot een POST van de ingevoerde waarden, zonder dat de validaties jS werden geactiveerd. Na het terugkeren van de POST wordt de kolom [Server Validation] gevuld met eventuele foutmeldingen. Als je nu op de knop [Validate] [2] klikt terwijl de validaties jS zijn ingeschakeld [3], dan wordt de kolom [Client Validation] [4] gevuld met meldingen. Als er niets wordt gedaan, blijven de berichten die in de kolom [Server Validation] stonden behouden, wat voor verwarring zorgt, aangezien de server niet wordt benaderd wanneer er fouten worden gedetecteerd door de validators jS. Om dit te voorkomen, wissen we de kolom [Server Validation] in de functie [postForm01]. Dit wordt gedaan door de functie []:
function clearServerErrors() {
// de foutmeldingen van de server worden gewist
$(".error").each(function(index) {
$(this).text("");
});
}
Een bijzonderheid van de foutmeldingen is dat ze allemaal de klasse [error] hebben. Bijvoorbeeld voor de eerste regel van de tabel in [vue-01.html]:
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
En dit zijn de enige knooppunten van DOM die deze klasse hebben. We gebruiken deze eigenschap in de functie [clearServerErrors]:
function clearServerErrors() {
// de foutmeldingen van de server worden gewist
$(".error").each(function(index) {
$(this).text("");
});
}
- regel 3: de uitdrukking [$(".error")] retourneert de verzameling knooppunten van de DOM met de klasse [error];
- regel 3: de uitdrukking [$(".error").each(function(index){f}] voert de functie [f] uit voor elk van de knooppunten in de verzameling. Deze functie ontvangt een parameter [index] die hier niet wordt gebruikt; dit is het nummer van het knooppunt in de verzameling;
- regel 4: de uitdrukking [$(this)] verwijst naar het huidige knooppunt in de iteratie. Dit is een tag HTML <span>. De uitdrukking [$(this).text("")] wijst de lege tekenreeks toe aan de tekst die door de tag <span> wordt weergegeven;
We gaan nu verschillende validatoren jS bekijken.
6.3.8. Validator [required]
Laten we het eerste element van het formulier bekijken:
![]() |
De regel [1] wordt gegenereerd door de volgende reeks in de weergave [vue-01.xml]:
<!-- vereist -->
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strNotEmpty')}" th:errors="*{strNotEmpty}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [strNotEmpty] van het formulier [Form01]:
@NotNull
@NotBlank
private String strNotEmpty;
De beperkingen van [1-2] zorgen ervoor dat het veld [strNotEmpty] een bestaande tekenreeks [NotNull] moet zijn, die niet leeg mag zijn en niet uitsluitend uit spaties [NotBlank] mag bestaan. We willen deze beperking aan de clientzijde met JavaScript nabootsen.
Laten we de regels 5 en 8 eens bekijken. Regel 11 levert geen problemen op. Deze geeft de foutmelding weer die betrekking heeft op het veld [strNotEmpty]. Laten we beginnen met regel 5:
<input type="text" th:field="*{strNotEmpty}" data-val="true" th:attr="data-val-required=#{NotNull}" />
Op basis van deze code genereert Thymeleaf de volgende tag:
<input type="text" data-val="true" data-val-required="Field is required" id="strNotEmpty" name="strNotEmpty" value="x" />
- het attribuut [data-val='true'] wordt gebruikt door de validatiebibliotheken jQuery. De aanwezigheid ervan geeft aan dat de waarde van het knooppunt wordt gevalideerd;
- het attribuut [data-val-X='msg'] geeft twee soorten informatie. [X] is de naam van de validator, [msg] is de foutmelding die hoort bij een ongeldige waarde van het knooppunt waarop de validator wordt toegepast. Dit is slechts ter informatie. Het leidt niet tot de weergave van de foutmelding;
- [required] is een validator die wordt herkend door de validatiebibliotheek [jquery.validate.unobstrusive] van Microsoft. Het is niet nodig om deze te definiëren. Dit zal verderop niet altijd het geval zijn;
- de tags [data-x] worden genegeerd door HTML5. Ze zijn alleen nuttig als er JavaScript is om ze te benutten;
Laten we nu eens naar regel 8 kijken:
<span class="field-validation-valid" data-valmsg-for="strNotEmpty" data-valmsg-replace="true"></span>
Deze dient om de foutmelding van de validator [required] weer te geven. Als er een fout optreedt, zal de validatiebibliotheek jS de regel HTML in de tabel dynamisch vervangen door de volgende code:
<tr>
<td class="col1">required</td>
<td class="col2">
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" id="strNotEmpty" name="strNotEmpty" value="" aria-required="true" aria-invalid="true" aria-describedby="strNotEmpty-error" class="input-validation-error">
</td>
<td class="col3">
<span class="field-validation-error" data-valmsg-for="strNotEmpty" data-valmsg-replace="true">
<span id="strNotEmpty-error" class="">Le champ est obligatoire</span>
</span>
</td>
<td class="col4">
<span class="error"></span>
</td>
</tr>
</tr>
- regel 4: de klasse van het knooppunt [strNotEmpty] is gewijzigd. Deze is nu [input-validation-error], waardoor het foutieve veld rood wordt gemarkeerd;
- regel 7: de klasse van [span] is gewijzigd. Deze is nu [field-validation-error], waardoor de tekst van [span] in het rood wordt weergegeven;
- regel 8: de [span], die voorheen leeg was, bevat nu de tekst [Le champ est obligatoire]. Deze tekst is afkomstig van de tag [data-val-required="Le champ est obligatoire"] op regel 4;
- regel 7: om de foutmelding van het knooppunt [strNotEmpty] uit regel 4 weer te geven, moet je in regel 7 de attributen [data-valmsg-for="strNotEmpty"] en [data-valmsg-replace="true"] gebruiken;
6.3.9. Validator [assertfalse]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks uit de weergave [vue-01.xml]:
<!-- vereist, assertfalse -->
<tr>
<td class="col1">required, assertfalse</td>
<td class="col2">
<input type="radio" th:field="*{assertFalse}" value="true" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-assertfalse=#{AssertFalse}" />
<label th:for="${#ids.prev('assertFalse')}">true</label>
<input type="radio" th:field="*{assertFalse}" value="false" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-assertfalse=#{AssertFalse}" />
<label th:for="${#ids.prev('assertFalse')}">false</label>
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="assertFalse" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('assertFalse')}" th:errors="*{assertFalse}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [assertFalse] van het formulier [Form01]:
@NotNull
@AssertFalse
private Boolean assertFalse;
We willen deze beperking aan de clientzijde met JavaScript nabootsen. De regels 12-17 zijn inmiddels standaard:
- regels 12-14: geven bij een fout in het veld [assertFalse] het bericht weer dat wordt overgedragen door het attribuut [data-val-assertfalse] van regel 6 of dat wordt overgedragen door het attribuut [data-val-required] van dezelfde regel. Ter herinnering: deze berichten worden gelokaliseerd, d.w.z. in de taal die de gebruiker eerder heeft gekozen of in het Frans als hij geen keuze heeft gemaakt;
- regels 5-10: geven de keuzerondjes weer met JavaScript-validatoren die worden geactiveerd zodra de gebruiker op een van deze keuzerondjes klikt.
Beide knoppen zijn op dezelfde manier opgebouwd. We zullen de eerste bekijken:
<input type="radio" th:field="*{assertFalse}" value="true" data-val="true" th:attr="data-val-required=#{NotNull},data-val-assertfalse=#{AssertFalse}" />
Na verwerking door Thymeleaf wordt deze regel als volgt:
<input type="radio" value="true" data-val="true" data-val-required="Le champ est obligatoire" data-val-assertfalse="Seule la valeur False est acceptée" id="assertFalse1" name="assertFalse" />
We hebben validatoren [data-val="true"]. We hebben er twee. Een validator met de naam [required] [data-val-required="Le champ est obligatoire"] en een andere met de naam [assertfalse] [data-val-assertfalse="Seule la valeur False est acceptée"]. Ter herinnering: de waarde van het attribuut [data-val-X] is de foutmelding van validator X.
We hebben de validator [required] al gezien. Nieuw hier is dat er meerdere validatoren aan een ingevoerde waarde kunnen worden gekoppeld. Hoewel de validator [required] bekend is bij de validatiebibliotheek MS (Microsoft), geldt dit niet voor de validator [assertFalse]. We gaan daarom leren hoe we een nieuwe validator kunnen maken. We gaan er meerdere maken en deze worden in een bestand met de naam [client-validation.js] geplaatst:
![]() |
Dit bestand wordt, net als de andere, geïmporteerd via de weergave [vue-01.xml] (regel 6 hieronder):
<head>
<title>Spring 4 MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/form01.css" />
...
<script type="text/javascript" src="/js/client-validation.js"></script>
...
</head>
Het toevoegen van de validator [assertfalse] komt neer op het aanmaken van de volgende twee functies jS:
// -------------- assertfalse
$.validator.addMethod("assertfalse", function(value, element, param) {
return value === "false";
});
$.validator.unobtrusive.adapters.add("assertfalse", [], function(options) {
options.rules["assertfalse"] = options.params;
options.messages["assertfalse"] = options.message.replace("''", "'");
});
Eerlijk gezegd ben ik geen specialist in JavaScript, een programmeertaal die voor mij nog steeds een raadsel is. De basisprincipes zijn eenvoudig, maar de bibliotheken die daarop voortbouwen, zijn vaak erg complex. Voor het schrijven van de bovenstaande coderegels heb ik me laten inspireren door code die ik op internet heb gevonden. De link [http://jsfiddle.net/LDDrk/] heeft mij de weg gewezen. Mocht deze nog bestaan, dan raad ik de lezer aan deze te bekijken, want hij is volledig en bevat bovendien een werkend voorbeeld. Hierin wordt getoond hoe je een nieuwe validator kunt maken en dankzij deze uitleg heb ik alle validators in dit hoofdstuk kunnen maken. Laten we teruggaan naar de code:
- regels 2-4: definiëren de nieuwe validator. De functie [$.validator.addMethod] verwacht als eerste parameter de naam van de validator en als tweede parameter een functie die deze definieert;
- regel 2: de functie heeft drie parameters:
- [value]: de te valideren waarde. De functie moet [true] retourneren als de waarde geldig is, en [false] anders;
- [element]: het element HTML waartoe de te valideren waarde behoort,
- [param]: een object dat de waarden bevat die gekoppeld zijn aan de parameters van een validator. Dit begrip hebben we nog niet geïntroduceerd. In dit geval heeft de validator [assertFalse] geen parameters. We kunnen zonder aanvullende informatie vaststellen of de waarde [value] geldig is. Dat zou anders zijn als we moesten controleren of de waarde [value] een reëel getal is binnen het interval [min, max]. In dat geval zouden we [min] en [max] moeten kennen. Deze twee waarden worden de parameters van de validator genoemd;
- regels 6-9: een functie die nodig is voor de validatiebibliotheek MS. De functie [$.validator.unobtrusive.adapters.add] verwacht als eerste parameter de naam van de validator, als tweede parameter de array met parameters van de validator en als derde parameter een functie;
- de validator [assertFalse] heeft geen parameters. Daarom is de tweede parameter een lege array;
- de functie heeft slechts één parameter, een object [options] dat informatie bevat over het te valideren element en waarvoor twee nieuwe eigenschappen moeten worden gedefinieerd: [rules] en [messages];
- regel 7: we definiëren de regels [rules] voor de validator [assertFalse]. Deze regels zijn de parameters van de validator [assertFalse], dezelfde als die van de parameter [param] in regel 2. Deze parameters zijn te vinden in [options.params];
- regel 8: hierin wordt de foutmelding van de validator [assertFalse] gedefinieerd. Deze is te vinden in [options.message]. Er doet zich het volgende probleem voor met de foutmeldingen. In de berichtenbestanden vinden we de volgende melding:
Range.form01.int1014=La valeur doit être dans l''intervalle [10,14]
De dubbele apostrof is nodig voor Thymeleaf. Thymeleaf interpreteert deze als een enkele apostrof. Als we een enkele apostrof gebruiken, wordt deze niet weergegeven door Thymeleaf. Deze berichten zullen nu ook dienen als foutmeldingen voor de validatiebibliotheek MS. Het JavaScript zal echter beide apostrofs weergeven. Op regel 8 vervangen we dus de dubbele apostrof in de foutmelding door een enkele.
Om een beetje te zien wat er gebeurt, kunnen we wat jS-logcode toevoegen:
// logs
var logs = {
assertfalse : true
}
// -------------- assertfalse
$.validator.addMethod("assertfalse", function(value, element, param) {
// logs
if (logs.assertfalse) {
console.log(jSON.stringify({
"[assertfalse] value" : value
}));
console.log("[assertfalse] element");
console.log(element);
console.log(jSON.stringify({
"[assertfalse] param" : param
}));
}
// geldigheidstest
return value === "false";
});
$.validator.unobtrusive.adapters.add("assertfalse", [], function(options) {
// logs
if (logs.assertfalse) {
console.log(jSON.stringify({
"[assertfalse] options.params" : options.params
}));
console.log(jSON.stringify({
"[assertfalse] options.message" : options.message
}));
console.log(jSON.stringify({
"[assertfalse] options.messages" : options.messages
}));
}
// code
options.rules["assertfalse"] = options.params;
options.messages["assertfalse"] = options.message.replace("''", "'");
});
Deze code maakt gebruik van de bibliotheek jSON JSON3 [http://bestiejs.github.io/json3/]. Als we de logboeken inschakelen (regel 3), krijgen we de volgende uitvoer in de console:
Bij het eerste laden van de pagina verschijnen de volgende logberichten:
De functie jS [$.validator.unobtrusive.adapters.add] is uitgevoerd. Hieruit blijkt het volgende:
- [options.params] is een leeg object omdat de validator [assertFalse] geen parameters heeft;
- [options.message] is de foutmelding die we hebben opgesteld voor de validator [assertFalse] in het attribuut [data-val-assertFalse];
- [options.messages] is een object dat de andere foutmeldingen van het gevalideerde element bevat. Hier vinden we de foutmelding terug die we in het attribuut [data-val-required] hebben geplaatst;
Laten we nu een onjuiste waarde invoeren in het veld [assertFalse] en valideren:
We krijgen dan de volgende logberichten:
![]() |
Hierin zien we het volgende:
- de geteste waarde is [true] (regel 118);
- het geteste element HTML is de keuzeknop met id [assertFalse1] (regel 122);
- de validator [assertFalse] heeft geen parameter (regel 123);
Dat was het. Wat kunnen we hieruit concluderen?
Voor een X-validator jS moeten we het volgende definiëren:
- in de te valideren tag HTML het attribuut [data-val-X='msg'], dat zowel de X-validator als de bijbehorende foutmelding definieert;
- twee functies jS die in het bestand [client-validation.js] moeten worden opgenomen:
- [$.validator.addMethod("X", function(value, element, param)],
- [$.validator.unobtrusive.adapters.add("X", [param1, param2], function(options)] ;
Vervolgens bouwen we voort op wat er voor deze eerste validator is gedaan en presenteren we alleen wat er nieuw is.
6.3.10. Validator [asserttrue]
Deze validator is uiteraard vergelijkbaar met de validator [assertFalse].
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- vereist, asserttrue -->
<tr>
<td class="col1">asserttrue</td>
<td class="col2">
<select th:field="*{assertTrue}" data-val="true" th:attr="data-val-asserttrue=#{AssertTrue}">
<option value="true">True</option>
<option value="false">False</option>
</select>
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="assertTrue" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('assertTrue')}" th:errors="*{assertTrue}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [assertTrue] van het formulier [Form01]:
@NotNull
@AssertTrue
private Boolean assertTrue;
Er is niets nieuws in de regels 1-16. Ze maken gebruik van een validator [asserrtrue] die moet worden gedefinieerd in het bestand [client-validation.js]:
// -------------- asserttrue
$.validator.addMethod("asserttrue", function(value, element, param) {
return value === "true";
});
$.validator.unobtrusive.adapters.add("asserttrue", [], function(options) {
options.rules["asserttrue"] = options.params;
options.messages["asserttrue"] = options.message.replace("''", "'");
});
6.3.11. Validators [date] en [past]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks in de weergave [vue-01.xml]:
<!-- vereist, datum, verleden -->
<tr>
<td class="col1">required, date, past</td>
<td class="col2">
<input type="date" th:field="*{dateInPast}" th:value="*{dateInPast}" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-date=#{DateInvalide.form01},data-val-past=#{Past.form01.dateInPast}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="dateInPast" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('dateInPast')}" th:errors="*{dateInPast}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [dateInPast] van het formulier [Form01]:
@NotNull
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInPast;
De regel met de datumvalidatoren is als volgt:
<input type="date" th:field="*{dateInPast}" th:value="*{dateInPast}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-date=#{DateInvalide.form01},data-val-past=#{Past.form01.dateInPast}" />
Daarin staan drie validatoren [data-val-X]: required, date, past. We moeten in [client-validation.js] de functies definiëren die bij deze twee nieuwe validatoren horen:
logs.date = true;
// -------------- datum
$.validator.addMethod("date", function(value, element, param) {
// geldigheid
var valide = Globalize.parseDate(value, "yyyy-MM-dd") != null;
// logs
if (logs.date) {
console.log(jSON.stringify({
"[date] value" : value,
"[date] valide" : valide
}));
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("date", [], function(options) {
options.rules["date"] = options.params;
options.messages["date"] = options.message.replace("''", "'");
});
en
logs.past = true;
// -------------- verleden
$.validator.addMethod("past", function(value, element, param) {
// geldigheid
var valide = value <= new Date().toISOString().substring(0, 10);
// logs
if (logs.past) {
console.log(jSON.stringify({
"[past] value" : value,
"[past] valide" : valide
}));
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("past", [], function(options) {
options.rules["past"] = options.params;
options.messages["past"] = options.message.replace("''", "'");
});
Voordat we de code uitleggen, kijken we eerst naar de logbestanden wanneer we een datum invoeren die later is dan vandaag:
Het eerste wat opvalt, is dat de te valideren datum binnenkomt als een tekenreeks in het formaat [aaaa-mm-jj]. Dit verklaart de volgende regels:
var valide = Globalize.parseDate(value, "yyyy-MM-dd") != null;
De bibliotheek [globalize.js] roept de bovenstaande functie [Globalize.parseDate] aan. De eerste parameter is de datum als tekenreeks en de tweede is de indeling ervan. Het resultaat is een pointer null als de datum ongeldig is, anders de resulterende datum.
De geldigheid van de validator [past] wordt gecontroleerd door de volgende code:
var valide = value <= new Date().toISOString().substring(0, 10);
Hieronder ziet u op een console de evaluatie van de uitdrukking [new Date().toISOString().substring(0, 10)]:
![]() |
De tekenreeks [value] moet alfabetisch vóór de tekenreeks [new Date().toISOString().substring(0, 10)] staan om geldig te zijn.
Merk op dat de gebruikte versie van Chrome de datum weergeeft in het formaat [yyyy-mm-dd]. Voor een browser waar dit niet het geval is, zou de gebruiker expliciet moeten worden geïnstrueerd om dit invoerformaat te gebruiken.
6.3.12. Validator [future]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- vereist, datum, toekomst -->
<tr>
<td class="col1">required, date, future</td>
<td class="col2">
<input type="date" th:field="*{dateInFuture}" th:value="*{dateInFuture}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-date=#{DateInvalide.form01},data-val-future=#{Future.form01.dateInFuture}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="dateInFuture" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('dateInFuture')}" th:errors="*{dateInFuture}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [dateInFuture] van het formulier [Form01]:
@NotNull
@Future
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dateInFuture;
- op regel 5 verschijnt een nieuwe validator [data-val-future];
Deze validator lijkt natuurlijk sterk op de validator [past]. De twee functies die in [client-validation.js] moeten worden toegevoegd, zijn de volgende:
// -------------- toekomst
$.validator.addMethod("future", function(value, element, param) {
var now = new Date().toISOString().substring(0, 10);
return value > now;
});
$.validator.unobtrusive.adapters.add("future", [], function(options) {
options.rules["future"] = options.params;
options.messages["future"] = options.message.replace("''", "'");
});
6.3.13. Validatoren [int] en [max]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks in de weergave [vue-01.xml]:
<!-- verplicht, int, max(100) -->
<tr>
<td class="col1">required, int, max(100)</td>
<td class="col2">
<input type="text" th:field="*{intMax100}" th:value="*{intMax100}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-int=#{typeMismatch},data-val-max=#{Max.form01.intMax100},data-val-max-value=#{form01.intMax100.value}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="intMax100" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('intMax100')}" th:errors="*{intMax100}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [intMax100] van het formulier [Form01]:
@NotNull
@Max(value = 100)
private Integer intMax100;
In regel 5 zijn er twee nieuwe validatoren: [int] en [max]. De laatste heeft één parameter: de maximale waarde. Laten we de code HTML bekijken die door regel 5 wordt gegenereerd:
<!-- verplicht, int, max(100) -->
<tr>
<td class="col1">required, int, max(100)</td>
<td class="col2">
<input type="text" data-val="true" data-val-int="Format invalide" data-val-max-value="100" data-val-required="Le champ est obligatoire" data-val-max="La valeur doit être inférieure ou égale à 100" value="" id="intMax100" name="intMax100" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="intMax100" data-valmsg-replace="true"></span>
</td>
<td class="col4">
</td>
</tr>
Laten we nog eens de betekenis van de verschillende attributen van [data-X] in herinnering brengen:
- [data-val="true"] geeft aan dat er validatoren zijn gekoppeld aan het element HTML;
- [data-val-required] introduceert de validator [required] met zijn bericht;
- [data-val-int] introduceert de validator [int] met zijn bericht;
- [data-val-max] introduceert de validator [max] met zijn bericht;
- [data-val-max-value="100"] introduceert een parameter met de naam [value] voor de validator [max]. [100] is de waarde van deze parameter. Dit is de eerste keer dat we het begrip ‘parameters van een validator’ tegenkomen.
Het bestand [client-validation.js] wordt uitgebreid met de volgende validator [int]:
logs.int = true;
// -------------- int
$.validator.addMethod("int", function(value, element, param) {
// geldigheid
valide = /^\s*[-\+]?\s*\d+\s*$/.test(value);
// logs
if (logs.int) {
console.log(jSON.stringify({
"[int] value" : value,
"[int] valide" : valide,
}));
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("int", [], function(options) {
options.rules["int"] = options.params;
options.messages["int"] = options.message.replace("''", "'");
});
- regel 5: er wordt een reguliere expressie gebruikt om te controleren of de tekenreeks [value] inderdaad een geheel getal vertegenwoordigt. Dit getal kan een getal met teken zijn;
Hier volgen enkele voorbeelden van logbestanden:
De validator [max] wordt als volgt toegevoegd aan [client-validation.js]
// -------------- max te gebruiken in combinatie met [int] of [number]
logs.max = true;
$.validator.addMethod("max", function(value, element, param) {
// logs
if (logs.max) {
console.log(jSON.stringify({
"[max] value" : value,
"[max] param" : param
}));
}
// geldigheid
var val = Globalize.parseFloat(value);
if (isNaN(val)) {
// logs
if (logs.max) {
console.log(jSON.stringify({
"[max] valide" : true
}));
}
// resultaat
return true;
}
var max = Globalize.parseFloat(param.value);
var valide = val <= max;
// logs
if (logs.max) {
console.log(jSON.stringify({
"[max] valide" : valide
}));
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("max", [ "value" ], function(options) {
options.rules["max"] = options.params;
options.messages["max"] = options.message.replace("''", "'");
});
We gaan nu meteen het geval behandelen van de parameter [value] van de validator [max], die wordt geïntroduceerd door het attribuut [data-val-max-value="100"].
- op regel 35 wordt de parameter [value] opgenomen in de tweede parameter van de functie [$.validator.unobtrusive.adapters.add];
- regel 3: het object [param] is niet langer leeg, maar bevat {"value":100};
Om de code van de regels 3-33 te begrijpen, moet men weten dat wanneer er meerdere validators op hetzelfde element HTML staan:
- de volgorde waarin de validators worden uitgevoerd onbekend is;
- de uitvoering van de validators stopt zodra een validator het element ongeldig verklaart. Het is dan de foutmelding van deze laatste die aan het ongeldige element wordt gekoppeld;
Laten we de code eens bekijken:
- regel 12: er wordt gecontroleerd of er een getal is. Als de validator [int] vóór de validator [max] is uitgevoerd, is dit noodzakelijkerwijs het geval, aangezien een ongeldige waarde de uitvoering van de validators stopt;
- regels 13-22: als er geen getal is, betekent dit dat de validator [int] nog niet is uitgevoerd. Vervolgens wordt aangegeven dat de geteste waarde geldig is, zodat de validator [int] zijn werk kan doen en het element ongeldig kan verklaren met zijn eigen foutmelding;
- regels 23-24: berekent de geldigheid van [value];
Hier volgen enkele logbestanden:
Ingevoerde waarde | logs |
| |
| |
|
6.3.14. Validator [min]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- verplicht, int, min(10) -->
<tr>
<td class="col1">required, int, min(10)</td>
<td class="col2">
<input type="text" th:field="*{intMin10}" th:value="*{intMin10}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-int=#{typeMismatch},data-val-min=#{Min.form01.intMin10},data-val-min-value=#{form01.intMin10.value}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="intMin10" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('intMin10')}" th:errors="*{intMin10}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [intMin10] van het formulier [Form01]:
@NotNull
@Min(value = 10)
private Integer intMin10;
Regel 5 voegt een nieuwe validator [min] [data-val-int=#{typeMismatch}] toe met een parameter [value] [data-val-min-value=#{form01.intMin10.value}"]. Dit is een vergelijkbaar geval als de validator [max]. We voegen in [client-validation.js] de volgende code toe:
logs.min = true;
//-------------- min moet worden gebruikt in combinatie met [int] of [number]
$.validator.addMethod("min", function(value, element, param) {
// logs
if (logs.min) {
console.log(jSON.stringify({
"[min] value" : value,
"[min] param" : param
}));
}
// geldigheid
var val = Globalize.parseFloat(value);
if (isNaN(val)) {
// logs
if (logs.min) {
console.log(jSON.stringify({
"[min] valide" : true
}));
}
// resultaat
return true;
}
var min = Globalize.parseFloat(param.value);
var valide = val >= min;
// logs
if (logs.min) {
console.log(jSON.stringify({
"[min] valide" : valide
}));
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("min", [ "value" ], function(options) {
options.rules["min"] = options.params;
options.messages["min"] = options.message.replace("''", "'");
});
Hier volgen enkele uitvoeringslogs:
Ingevoerde waarde | logs |
| |
| |
|
6.3.15. Validator [regex]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- vereist, regex -->
<tr>
<td class="col1">required, regex</td>
<td class="col2">
<input type="text" th:field="*{strBetween4and6}" th:value="*{strBetween4and6}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-regex=#{Size.form01.strBetween4and6}, data-val-regex-pattern=#{form01.strBetween4and6.pattern}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="strBetween4and6" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('strBetween4and6')}" th:errors="*{strBetween4and6}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [strBetween4and6] van het formulier [Form01]:
@NotNull
@Size(min = 4, max = 6)
private String strBetween4and6;
Regel 5 genereert het volgende HTML:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" data-val-regex="La chaîne doit avoir entre 4 et 6 caractères" data-val-regex-pattern="^.{4,6}$" value="" id="strBetween4and6" name="strBetween4and6" />
Deze tag introduceert de validator [regex] [data-val-regex="La chaîne doit avoir entre 4 et 6 caractères"] met de bijbehorende parameter [pattern] [data-val-regex-pattern="^.{4,6}$"]. De parameter [pattern] is de reguliere expressie waaraan de te valideren waarde moet voldoen. Hier controleert de reguliere uitdrukking of de tekenreeks uit 4 tot en met 6 willekeurige tekens bestaat. De validator [regex] is vooraf gedefinieerd in de validatiebibliotheek MS. Er hoeft dus niets te worden toegevoegd aan het bestand [client-validation.js].
6.3.16. Validator [email]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- verplicht, e-mail -->
<tr>
<td class="col1">required, email</td>
<td class="col2">
<input type="text" th:field="*{email}" th:value="*{email}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-email=#{Email.form01.email}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="email" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [email] van het formulier [Form01]:
@NotNull
@Email
@NotBlank
private String email;
Regel 5 genereert de volgende regel HTML:
<input type="text" data-val="true" data-val-required="Le champ est obligatoire" data-val-email="Adresse mail invalide" value="" id="email" name="email" />
Deze tag introduceert de validator [email] [data-val-email="Adresse mail invalide"]. De validator [email] is vooraf gedefinieerd in de validatiebibliotheek MS. Er hoeft dus niets te worden toegevoegd aan het bestand [client-validation.js].
6.3.17. Validator [range]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- verplicht, int, bereik (10,14) -->
<tr>
<td class="col1">required, int, range (10,14)</td>
<td class="col2">
<input type="text" th:field="*{int1014}" th:value="*{int1014}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-int=#{typeMismatch}, data-val-range=#{Range.form01.int1014},data-val-range-max=#{form01.int1014.max},data-val-range-min=#{form01.int1014.min}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="int1014" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('int1014')}" th:errors="*{int1014}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [int1014] van het formulier [Form01]:
@Range(min = 10, max = 14)
@NotNull
private Integer int1014;
Regel 5 genereert de volgende regel HTML:
<input type="text" data-val="true" data-val-range-max="14" data-val-range="La valeur doit être dans l''intervalle [10,14]" data-val-int="Format invalide" data-val-required="Le champ est obligatoire" data-val-range-min="10" value="" id="int1014" name="int1014" />
Deze tag introduceert een nieuwe validator [range] [data-val-range="La valeur doit être dans l''intervalle [10,14]"] met twee parameters: [min] [data-val-range-min="10"] en [max] [data-val-range-max="14"].
In het bestand [client-validation.js] definiëren we de validator [range] als volgt:
// -------------- bereik te gebruiken in combinatie met [int] of [number]
logs.range=true
$.validator.addMethod("range", function(value, element, param) {
// logs
if (logs.range) {
console.log(jSON.stringify({
"[range] value" : value,
"[range] param" : param
}));
}
// geldigheid
var val = Globalize.parseFloat(value);
if (isNaN(val)) {
// logs
if (logs.min) {
console.log(jSON.stringify({
"[range] valide" : true
}));
}
// voltooid
return true;
}
var min = Globalize.parseFloat(param.min);
var max = Globalize.parseFloat(param.max);
var valide = val >= min && val <= max;
// logs
if (logs.range) {
console.log(jSON.stringify({
"[range] valide" : valide
}));
}
// voltooid
return valide;
});
$.validator.unobtrusive.adapters.add("range", [ "min", "max" ], function(options) {
options.rules["range"] = options.params;
options.messages["range"] = options.message.replace("''", "'");
});
Deze lijkt sterk op de validators [min] en [max] die we al hebben besproken.
Hier volgen enkele voorbeelden van logbestanden:
Ingevoerde waarde | logboeken |
| |
| |
|
6.3.18. Validator [number]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks uit de weergave [vue-01.xml]:
<!-- double1: vereist, getal, bereik (2,3; 3,4) -->
<tr>
<td class="col1">double1 : required, number, range (2.3,3.4)</td>
<td class="col2">
<input type="text" th:field="*{double1}" th:value="*{double1}" data-val="true"
th:attr="data-val-required=#{NotNull},data-val-number=#{typeMismatch},data-val-range=#{Range.form01.double1},data-val-range-max=#{form01.double1.max},data-val-range-min=#{form01.double1.min}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="double1" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('double1')}" th:errors="*{double1}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [double1] van het formulier [Form01]:
@NotNull
@DecimalMax(value = "3.4")
@DecimalMin(value = "2.3")
private Double double1;
Regel 5 genereert de volgende regel HTML:
<input type="text" data-val="true" data-val-number="Format invalide" data-val-range-max="3.4" data-val-range="La valeur doit être dans l'intervalle [2,3-3,4]" data-val-required="Le champ est obligatoire" data-val-range-min="2.3" value="" id="double1" name="double1" />
De tag voegt een nieuwe validator [number] toe met het attribuut [data-val-number="Format invalide"]. Deze validator is als volgt gedefinieerd in het bestand [client-validation.js]:
// -------------- getal
logs.number = true;
$.validator.addMethod("number", function(value, element, param) {
var valide = !isNaN(Globalize.parseFloat(value));
// logs
if (logs.number) {
console.log(jSON.stringify({
"[number] value" : value,
"[number] valide" : valide
}));
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("number", [], function(options) {
options.rules["number"] = options.params;
options.messages["number"] = options.message.replace("''", "'");
});
Hier volgen enkele voorbeelden van logbestanden:
Ingevoerde waarde | logboeken |
Het is bekend dat reële getallen cultuurgebonden zijn. Hierboven bevinden we ons in de notatie [fr-FR]. Wanneer we [2.5] (Angelsaksische notatie) invoeren, wordt het getal geaccepteerd. Dit komt door [Globalize.parseFloat], dat beide notaties accepteert:
Laten we overschakelen naar het Engels en de waarden [+2,5] en [+2.5] invoeren. De logbestanden zien er als volgt uit:
Ingevoerde waarde | logs |
Er is een probleem met [2,5]. Het is als een geldige waarde aangemerkt, terwijl het eigenlijk [2.5] moet zijn. Dit komt door [Globalize.parseFloat]:
Hierboven negeert [Globalize.parseFloat] de komma en beschouwt het getal als 25. In de cultuur van [en-US] kan een reëel getal een decimaalteken en komma's bevatten, die soms worden gebruikt om de duizendtallen te scheiden.
Dit kan als volgt worden verbeterd:
// -------------- getal
logs.number = true;
$.validator.addMethod("number", function(value, element, param) {
// we beheren uitsluitend de teelten [fr-FR] en [en-US]
var pattern_fr_FR = /^\s*[-+]?[0-9]*\,?[0-9]+\s*$/;
var pattern_en_US = /^\s*[-+]?[0-9]*\.?[0-9]+\s*$/;
var culture = Globalize.culture().name;
// geldigheidstest
var valide;
if (culture === "fr-FR") {
valide = pattern_fr_FR.test(value);
} else if (culture === "en-US") {
valide = pattern_en_US.test(value);
} else {
valide = !isNaN(Globalize.parseFloat(value));
}
// logboeken
if (logs.number) {
console.log(jSON.stringify({
"[number] value" : value,
"[number] culture" : culture,
"[number] valide" : valide
}));
}
// resultaat
return valide;
});
- regel 5: de reguliere expressie voor een reëel getal in de cultuur [fr-FR];
- regel 6: de reguliere expressie voor een reëel getal in de QZXW2HTML-cultuur P002797ZQX;
- regel 7: de naam van de huidige cultuur. In ons voorbeeld is dit een van de twee bovengenoemde culturen;
- regels 9-16: de geldigheidstest van de ingevoerde waarde;
- regel 15: er is rekening gehouden met het geval waarin de cultuur noch [fr-FR], noch [en-US] is;
De logbestanden geven nu het volgende weer:
Cultuur [fr-FR]
Ingevoerde waarde | logbestanden |
| |
| |
| |
|
Cultuur [en-US]
Ingevoerde waarde | logs |
| |
| |
|
6.3.19. Validator [custom3]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- double3: vereist, getal, custom3 -->
<tr>
<td class="col1">double3 : required, number, custom3</td>
<td class="col2">
<input type="text" th:field="*{double3}" th:value="*{double3}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-number=#{typeMismatch},data-val-custom3=${custom3.message},data-val-custom3-field=${custom3.otherFieldName},data-val-custom3-max=${custom3.max},data-val-custom3-min=${custom3.min}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="double3" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('double3')}" th:errors="*{double3}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [double3] van het formulier [Form01]:
@NotNull
private Double double3;
We willen hier een validator onderzoeken die niet langer een ingevoerde waarde valideert, maar een relatie tussen twee ingevoerde waarden. In dit geval willen we dat [double1+double3] binnen het interval van [10,13] valt.
Regel 5 genereert de volgende regel HTML:
<input type="text" data-val="true" data-val-custom3-min="10.0" data-val-number="Invalid format"
data-val-custom3="[double3+double1] must be in [10,13]" data-val-custom3-max="13.0" data-val-custom3-field="double1" data-val-required="Field is required" value="" id="double3" name="double3" />
Deze regel introduceert de nieuwe validator [custom3], gedefinieerd door het attribuut [data-val-custom3="[double3+double1] must be in [10,13]"]. Deze validator heeft de volgende parameters:
- [field], gedefinieerd door het attribuut [data-val-custom3-field="double1"]. Deze parameter geeft het veld aan waarvan de waarde wordt gebruikt bij de berekening van de geldigheid van [double3];
- [min] wordt gedefinieerd door het attribuut [data-val-custom3-min="10.0"]. Deze parameter is de minimumwaarde van het interval [min, max] waarin [double1+double3] moet liggen;
- [max] wordt gedefinieerd door het attribuut [data-val-custom3-max="13.0"]. Deze parameter is de maximumwaarde van het interval [min, max] waarin [double1+double3] moet liggen;
Deze validator wordt als volgt beheerd in [client-validation.js]:
// -------------- custom3 gebruikt in combinatie met [number]
logs.custom3 = true;
$.validator.addMethod("custom3", function(value1, element, param) {
// tweede waarde
var value2 = $("#" + param.field).val();
// logs
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] value1" : value1,
"[custom3] param" : param,
"[custom3] value2" : value2
}))
}
// eerste waarde
var valeur1 = Globalize.parseFloat(value1);
if (isNaN(valeur1)) {
// we laten de validator [number] het werk doen
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] valide" : true
}))
}
return true;
}
// tweede waarde
var valeur2 = Globalize.parseFloat(value2);
if (isNaN(valeur2)) {
// de geldigheidscontrole kan niet worden uitgevoerd
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] valide" : false
}))
}
return false;
}
// geldigheidsberekening
var min = Globalize.parseFloat(param.min);
var max = Globalize.parseFloat(param.max);
var somme = valeur1 + valeur2;
var valide = somme >= min && somme <= max;
// logbestanden
if (logs.custom3) {
console.log(jSON.stringify({
"[custom3] valide" : valide
}))
}
// resultaat
return valide;
});
$.validator.unobtrusive.adapters.add("custom3", [ "field", "max", "min" ], function(options) {
options.rules["custom3"] = options.params;
options.messages["custom3"] = options.message.replace("''", "'");
});
Hier volgen enkele voorbeelden van logbestanden:
Ingevoerde waarden [double1,double3] | logbestanden |
| |
| |
| |
|
6.3.20. Validator [url]
![]() |
De regel [1] wordt gegenereerd door de volgende reeks van de weergave [vue-01.xml]:
<!-- vereist, url -->
<tr>
<td class="col1">required, url</td>
<td class="col2">
<input type="text" th:field="*{url}" th:value="*{url}" data-val="true" th:attr="data-val-required=#{NotNull},data-val-url=#{URL.form01.url}" />
</td>
<td class="col3">
<span class="field-validation-valid" data-valmsg-for="url" data-valmsg-replace="true"></span>
</td>
<td class="col4">
<span th:if="${#fields.hasErrors('url')}" th:errors="*{url}" class="error">Donnée erronée</span>
</td>
</tr>
Deze regels hebben betrekking op het veld [url] van het formulier [Form01]:
@URL
@NotBlank
private String url;
Regel 5 genereert de volgende regel HTML:
<input type="text" data-val="true" data-val-url="Invalid URL" data-val-required="Field is required" value="" id="url" name="url" />
Deze voegt de validator [url] toe met het attribuut [data-val-url]. Deze validator is vooraf gedefinieerd in de validatiebibliotheek jQuery. Er hoeft niets te worden toegevoegd aan [client-validation.js].
6.3.21. Client-side validatie in- en uitschakelen
Zolang de validatie aan de clientzijde actief is, wordt de validatie aan de serverzijde nooit zichtbaar, omdat de verzonden waarden pas bij de server aankomen als ze aan de clientzijde als geldig zijn aangemerkt. Om de validatie aan de serverzijde te laten werken, moet de validatie aan de clientzijde worden uitgeschakeld. De weergave [vue-01.xml] biedt twee links om deze in- en uitschakeling te beheren:
<a id="clientValidationTrue" href="javascript:setClientValidation(true)">
<span style="margin-left:30px" th:text="#{client.validation.true}"></span>
</a>
<a id="clientValidationFalse" href="javascript:setClientValidation(false)">
<span style="margin-left:30px" th:text="#{client.validation.false}"></span>
</a>
Deze twee links zijn niet tegelijkertijd zichtbaar:
![]() | ![]() |
De vertaling HTML van deze links is als volgt:
<a id="clientValidationTrue" href="javascript:setClientValidation(true)">
<span style="margin-left:30px">Activer la validation client</span>
</a>
<a id="clientValidationFalse" href="javascript:setClientValidation(false)">
<span style="margin-left:30px">Inhiber la validation client</span>
</a>
Het script jS [setClientValidation] is gedefinieerd in het bestand [local.js] (zie hierboven). In de functie [$(document).ready] van dit bestand worden de validatielinks gebruikt:
// document gereed
$(document).ready(function() {
// globale verwijzingen
...
activateValidationTrue = $("#clientValidationTrue");
activateValidationFalse = $("#clientValidationFalse");
clientValidation = $("#clientValidation");
...
// validatielinks
// clientValidation is een verborgen veld dat door de server wordt ingesteld
var validate = clientValidation.val();
setClientValidation2(validate === "true");
});
- regel 5: een verwijzing naar de koppeling voor het activeren van de validatie aan de clientzijde;
- regel 6: een verwijzing naar de link voor het deactiveren van de validatie aan de clientzijde;
- regel 7: een verwijzing naar een verborgen veld in het formulier dat de laatste status van de activering opslaat in de vorm van een booleaanse waarde [true : validation client activée, false : validation client désactivée]. Dit veld bevindt zich in de weergave [vue-01.xml] in de volgende vorm:
<input type="hidden" th:field="*{clientValidation}" th:value="*{clientValidation}" value="true" />
en komt overeen met het veld [clientValidation] van het formulier [Form01]:
// validatie door de client
private boolean clientValidation = true;
- regel 11: de waarde van het verborgen veld wordt opgehaald;
- regel 12: de volgende functie [setClientValidation2] wordt aangeroepen:
function setClientValidation2(activate) {
// links
if (activate) {
// clientvalidatie is actief
activateValidationTrue.hide();
activateValidationFalse.show();
// de validatoren van het formulier worden geparseerd
$.validator.unobtrusive.parse(formulaire);
} else {
// clientvalidatie is uitgeschakeld
activateValidationFalse.hide();
activateValidationTrue.show();
// de validatievelden van het formulier worden uitgeschakeld
formulaire.data('validator', null);
}
}
- regel 1: de parameter [activate] is gelijk aan [true] als de validatie aan de clientzijde moet worden geactiveerd, anders is deze false;
- regels 5-6: de link voor deactivering wordt weergegeven, de link voor activering wordt verborgen;
- regel 8: om de validatie aan de clientzijde te laten werken, moet het document worden geparseerd (geanalyseerd) op zoek naar validatoren [data-val-X]. De parameter van de functie [$.validator.unobtrusive.parse] is de ID jS van het te parseren formulier;
- regels 11-12: de activeringslink wordt weergegeven, de deactiveringslink wordt verborgen;
- regel 14: de validatoren van het formulier zijn uitgeschakeld. Vanaf nu is het alsof er geen validatoren jS in het formulier staan;
Waarvoor dient deze functie [setClientValidation2]? Deze functie dient om de POST te beheren. Aangezien het veld [clientValidation] een verborgen veld is, wordt het verzonden en komt het terug met het formulier dat door de server wordt teruggestuurd. De waarde ervan wordt vervolgens gebruikt om de validatie aan de clientzijde te herstellen zoals deze was vóór de POST. Er is namelijk geen jS-geheugen tussen de verzoeken. De server moet dus in de nieuwe weergave de informatie doorgeven waarmee de client-side validatie van deze weergave kan worden geïnitialiseerd. Dit gebeurt gewoonlijk in de functie [$(document).ready].
Laten we teruggaan naar de functie [setClientValidation], die de klik op de links voor het in- en uitschakelen van de validatie aan de clientzijde afhandelt:
// validatie aan de clientzijde
function setClientValidation(activate) {
// het in- en uitschakelen van de clientvalidatie wordt beheerd
setClientValidation2(activate);
// de keuze van de gebruiker wordt opgeslagen in het verborgen veld
clientValidation.val(activate ? "true" : "false");
// aanvullende aanpassingen
if (activate) {
// de validatie aan de clientzijde is actief
// alle foutmeldingen van de server worden gewist
clearServerErrors();
// het formulier wordt gevalideerd
formulaire.validate().form();
} else {
// de clientvalidatie is uitgeschakeld
// alle foutmeldingen van de client worden gewist
clearClientErrors();
}
}
- regel 4: we gebruiken de functie [setClientValidation2] die we zojuist hebben bekeken;
- regel 6: de keuze van de gebruiker wordt opgeslagen in het verborgen veld om deze op te halen bij de terugkeer van de volgende POST;
- regel 11: als de validatie aan de clientzijde actief is, worden de foutmeldingen uit de kolom [serveur] van de weergave gewist. We hebben de functie [clearServerErrors] beschreven in paragraaf 6.3.7;
- regel 13: de validatoren jS worden uitgevoerd om eventuele foutmeldingen weer te geven in de kolom [client] van de weergave;
- regel 17: als de clientvalidatie is uitgeschakeld, worden de foutmeldingen uit kolom [client] van de weergave verwijderd. Laten we in de ontwikkelingsconsole van Chrome de code HTML van een foutief element bekijken:
<td class="col2">
<input type="text" data-val="true" data-val-int="Format invalide" data-val-max-value="100" data-val-required="Le champ est obligatoire" data-val-max="La valeur doit être inférieure ou égale à 100" value="" id="intMax100" name="intMax100" aria-required="true" class="input-validation-error" aria-describedby="intMax100-error">
</td>
<td class="col3">
<span class="field-validation-error" data-valmsg-for="intMax100" data-valmsg-replace="true">
<span id="intMax100-error" class="">Le champ est obligatoire</span>
</span>
</td>
- op regel 2 zien we dat het foutieve element in kolom 2 van de tabel de stijl [class="input-validation-error"] heeft;
- op regel 5 zien we dat in kolom 3 van de tabel de foutmelding de stijl [class="field-validation-error"] heeft;
Dit geldt voor alle foutieve elementen. Deze twee gegevens worden gebruikt in de volgende functie [clearClientErrors]:
// clientfouten wissen
function clearClientErrors() {
// de foutmeldingen van de client worden gewist
$(".field-validation-error").each(function(index) {
$(this).text("");
});
// de klasse CSS van de foutieve invoer wordt gewijzigd
$(".input-validation-error").each(function(index) {
$(this).removeClass("input-validation-error");
});
}
- regels 4-6: we zoeken alle elementen van DOM met de klasse [field-validation-error] en wissen de tekst die ze weergeven. Zo worden de foutmeldingen gewist;
- regels 8-10: alle elementen van DOM met de klasse [input-validation-error] worden gezocht en deze klasse wordt bij hen verwijderd. Zo krijgt het foutieve element dat rood was gekleurd zijn oorspronkelijke stijl terug;


















































