Nette Documentation Preview

syntax
Validierung von Formularen
**************************


Erforderliche Steuerelemente .[#toc-required-controls]
======================================================

Steuerelemente werden mit der Methode `setRequired()` als erforderlich markiert, deren Argument der Text der [Fehlermeldung |#Error Messages] ist, die angezeigt wird, wenn der Benutzer sie nicht ausfüllt. Wenn kein Argument angegeben wird, wird die Standard-Fehlermeldung verwendet.

```php
$form->addText('name', 'Name:')
	->setRequired('Please fill your name.');
```


Regeln .[#toc-rules]
====================

Mit der Methode `addRule()` fügen wir den Steuerelementen Validierungsregeln hinzu. Der erste Parameter ist die Regel, der zweite die [Fehlermeldung |#Error Messages] und der dritte das Argument für die Überprüfungsregel.

```php
$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password must be at least %d characters', 8);
```

**Validierungsregeln werden nur dann überprüft, wenn der Benutzer das Element ausgefüllt hat.**

Nette verfügt über eine Reihe von vordefinierten Regeln, deren Namen Konstanten der Klasse `Nette\Forms\Form` sind. Wir können diese Regeln auf alle Elemente anwenden:

| Konstante | Beschreibung | Argumente
|-------
| `Required` | alias von `setRequired()` | -
| `Filled` | alias von `setRequired()` | -
| `Blank` | darf nicht gefüllt werden | -
| `Equal` | Wert ist gleich dem Parameter | `mixed`
| `NotEqual` | Wert ist nicht gleich Parameter | `mixed`
| `IsIn` | Wert ist gleich einem Element im Array | `array`
| `IsNotIn` | Wert ist nicht gleich einem Element im Array | `array`
| `Valid` | Eingabe besteht Validierung (für [Bedingungen |#conditions]) | -


Texteingaben
------------

Für die Elemente `addText()`, `addPassword()`, `addTextArea()`, `addEmail()`, `addInteger()`, `addFloat()` können auch einige der folgenden Regeln angewendet werden:

| `MinLength` | minimale Stringlänge | `int`
| `MaxLength` | maximale Länge der Zeichenkette | `int`
| `Length` | Länge im Bereich oder exakte Länge | Paar `[int, int]` oder `int`
| `Email` | gültige E-Mail Adresse | -
| `URL` | gültige URL | -
| `Pattern` | entspricht regulärem Muster | `string`
| `PatternInsensitive` | wie `Pattern`, aber Groß-/Kleinschreibung wird nicht berücksichtigt | `string`
| `Integer` | ganze Zahl | -
| `Numeric` | Alias von `Integer` | -
| `Float` | Ganzzahl oder Fließkommazahl | -
| `Min` | Minimum des Integer-Wertes | `int\|float`
| `Max` | Maximum des ganzzahligen Wertes | `int\|float`
| `Range` | Wert im Bereich | Paar `[int\|float, int\|float]`

Die Regeln `Integer`, `Numeric` und `Float` konvertieren den Wert automatisch in Ganzzahl (bzw. Gleitkommazahl). Außerdem akzeptiert die Regel `URL` auch eine Adresse ohne Schema (z. B. `nette.org`) und vervollständigt das Schema (`https://nette.org`).
Die Ausdrücke in `Pattern` und `PatternInsensitive` müssen für den gesamten Wert gültig sein, d. h. so, als ob er in die Zeichen `^` and `$` eingeschlossen wäre.


Anzahl der Artikel .[#toc-number-of-items]
------------------------------------------

Für die Elemente `addMultiUpload()`, `addCheckboxList()`, `addMultiSelect()` können Sie auch die folgenden Regeln verwenden, um die Anzahl der ausgewählten Elemente oder hochgeladenen Dateien zu begrenzen:

| `MinLength` | Mindestanzahl | `int`
| `MaxLength` | maximale Anzahl | `int`
| `Length` | Anzahl im Bereich oder genaue Anzahl | Paare `[int, int]` oder `int`


Datei hochladen
---------------

Für die Steuerelemente `addUpload()`, `addMultiUpload()` können auch die folgenden Regeln verwendet werden:

| `MaxFileSize` | Maximale Dateigröße in Bytes | `int`
| `MimeType` | MIME-Typ, akzeptiert Wildcards (`'video/*'`) | `string\|string[]`
| `Image` | hochgeladene Datei ist JPEG, PNG, GIF, WebP | -
| `Pattern` | Dateiname entspricht regulärem Ausdruck | `string`
| `PatternInsensitive` | wie `Pattern`, aber Groß-/Kleinschreibung wird nicht berücksichtigt | `string`

Für `MimeType` und `Image` ist die PHP-Erweiterung `fileinfo` erforderlich. Ob eine Datei oder ein Bild dem erforderlichen Typ entspricht, wird anhand ihrer Signatur erkannt. Die Integrität der gesamten Datei wird nicht geprüft. Sie können herausfinden, ob ein Bild nicht beschädigt ist, indem Sie beispielsweise versuchen, [es zu laden |http:request#toImage].


Fehlermeldungen .[#toc-error-messages]
======================================

Alle vordefinierten Regeln außer `Pattern` und `PatternInsensitive` haben eine Standard-Fehlermeldung, so dass sie weggelassen werden können. Wenn Sie jedoch alle benutzerdefinierten Meldungen übergeben und formulieren, wird das Formular benutzerfreundlicher.

Sie können die Standardmeldungen in [forms:configuration] ändern, indem Sie die Texte im Array `Nette\Forms\Validator::$messages` ändern oder den [Übersetzer |rendering#translating] verwenden.

Die folgenden Platzhalter können im Text der Fehlermeldungen verwendet werden:

| `%d` | ersetzt schrittweise die Regeln nach den Argumenten
| `%n$d` | ersetzt durch das n-te Regelargument
| `%label` | ersetzt durch Feldbezeichnung (ohne Doppelpunkt)
| `%name` | ersetzt durch den Feldnamen (z.B. `name`)
| `%value` | ersetzt durch den vom Benutzer eingegebenen Wert

```php
$form->addText('name', 'Name:')
	->setRequired('Please fill in %label');

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'at least %d and no more than %d', [5, 10]);

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'no more than %2$d and at least %1$d', [5, 10]);
```


Bedingungen .[#toc-conditions]
==============================

Neben den Validierungsregeln können auch Bedingungen festgelegt werden. Sie werden ähnlich wie Regeln gesetzt, jedoch verwenden wir `addRule()` anstelle von `addCondition()` und lassen sie natürlich ohne Fehlermeldung stehen (die Bedingung fragt nur):

```php
$form->addPassword('password', 'Passwort:')
	// wenn das Passwort nicht länger als 8 Zeichen ist ...
	->addCondition($form::MaxLength, 8)
		// ... dann muss es eine Zahl enthalten
		->addRule($form::Pattern, 'Muss Zahl enthalten', '.*[0-9].*');
```

Die Bedingung kann mit einem anderen Element als dem aktuellen verknüpft werden, indem `addConditionOn()` verwendet wird. Der erste Parameter ist ein Verweis auf das Feld. Im folgenden Fall ist die E-Mail nur erforderlich, wenn das Kontrollkästchen aktiviert ist (d. h. sein Wert ist `true`):

```php
$form->addCheckbox('newsletters', 'Newsletter versenden');

$form->addEmail('email', 'Email:')
	// wenn das Kontrollkästchen aktiviert ist ...
	->addConditionOn($form['newsletters'], $form::Equal, true)
		// ... erfordern E-Mail
		->setRequired('Füllen Sie Ihre E-Mail-Adresse aus');
```

Bedingungen können mit den Methoden `elseCondition()` und `endCondition()` zu komplexen Strukturen gruppiert werden.

```php
$form->addText(/* ... */)
	->addCondition(/* ... */) // wenn die erste Bedingung erfüllt ist
		->addConditionOn(/* ... */) // und die zweite Bedingung auch für ein anderes Element
			->addRule(/* ... */) // erfordert diese Regel
		->elseCondition() // wenn die zweite Bedingung nicht erfüllt ist
			->addRule(/* ... */) // erfordert diese Regeln
			->addRule(/* ... */)
		->endCondition() // wir kehren zur ersten Bedingung zurück
		->addRule(/* ... */);
```

In Nette ist es sehr einfach, auf die Erfüllung oder Nichterfüllung einer Bedingung auf der JavaScript-Seite mit der Methode `toggle()` zu reagieren, siehe [Dynamisches JavaScript |#Dynamic JavaScript].


Referenzen zwischen Controls .[#toc-references-between-controls]
================================================================

Das Regel- oder Bedingungsargument kann ein Verweis auf ein anderes Element sein. Sie können zum Beispiel dynamisch überprüfen, ob `text` so viele Zeichen hat wie der Wert des Feldes `length` beträgt:

```php
$form->addInteger('length');
$form->addText('text')
	->addRule($form::Length, null, $form['length']);
```


Benutzerdefinierte Regeln und Bedingungen .[#toc-custom-rules-and-conditions]
=============================================================================

Manchmal kommen wir in eine Situation, in der die eingebauten Validierungsregeln in Nette nicht ausreichen und wir die Daten des Benutzers auf unsere eigene Weise validieren müssen. In Nette ist das sehr einfach!

Sie können einen beliebigen Callback als ersten Parameter an die Methoden `addRule()` oder `addCondition()` übergeben. Der Callback akzeptiert das Element selbst als ersten Parameter und gibt einen booleschen Wert zurück, der angibt, ob die Validierung erfolgreich war. Beim Hinzufügen einer Regel mit `addRule()` können zusätzliche Argumente übergeben werden, die dann als zweiter Parameter übergeben werden.

Der benutzerdefinierte Satz von Validatoren kann somit als Klasse mit statischen Methoden erstellt werden:

```php
class MyValidators
{
	// prüft, ob der Wert durch das Argument teilbar ist
	public static function validateDivisibility(BaseControl $input, $arg): bool
	{
		return $input->getValue() % $arg === 0;
	}

	public static function validateEmailDomain(BaseControl $input, $domain)
	{
		// zusätzliche Prüfer
	}
}
```

Die Verwendung ist dann sehr einfach:

```php
$form->addInteger('num')
	->addRule(
		[MyValidators::class, 'validateDivisibility'],
		'The value must be a multiple of %d',
		8,
	);
```

Benutzerdefinierte Validierungsregeln können auch zu JavaScript hinzugefügt werden. Die einzige Bedingung ist, dass die Regel eine statische Methode sein muss. Ihr Name für den JavaScript-Validator wird durch Verkettung des Klassennamens ohne Backslashes `\`, the underscore `_` und des Methodennamens gebildet. Schreiben Sie zum Beispiel `App\MyValidators::validateDivisibility` als `AppMyValidators_validateDivisibility` und fügen Sie es dem Objekt `Nette.validators` hinzu:

```js
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
	return val % args === 0;
};
```


Ereignis onValidate .[#toc-event-onvalidate]
============================================

Nach dem Absenden des Formulars wird die Validierung durchgeführt, indem die einzelnen von `addRule()` hinzugefügten Regeln überprüft und dann das [Ereignis |nette:glossary#Events] `onValidate` aufgerufen wird. Dessen Handler kann für zusätzliche Validierungen verwendet werden, in der Regel um die korrekte Kombination von Werten in mehreren Formularelementen zu überprüfen.

Wenn ein Fehler festgestellt wird, wird er mit der Methode `addError()` an das Formular weitergegeben. Diese kann entweder für ein bestimmtes Element oder direkt für das Formular aufgerufen werden.

```php
protected function createComponentSignInForm(): Form
{
	$form = new Form;
	// ...
	$form->onValidate[] = [$this, 'validateSignInForm'];
	return $form;
}

public function validateSignInForm(Form $form, \stdClass $data): void
{
	if ($data->foo > 1 && $data->bar > 5) {
		$form->addError('Diese Kombination ist nicht möglich.');
	}
}
```


Verarbeitung von Fehlern .[#toc-processing-errors]
==================================================

In vielen Fällen entdecken wir einen Fehler, wenn wir ein gültiges Formular verarbeiten, z. B. wenn wir einen neuen Eintrag in die Datenbank schreiben und auf einen doppelten Schlüssel stoßen. In diesem Fall geben wir den Fehler mit der Methode `addError()` an das Formular zurück. Diese Methode kann entweder für ein bestimmtes Element oder direkt für das Formular aufgerufen werden:

```php
try {
	$data = $form->getValues();
	$this->user->login($data->username, $data->password);
	$this->redirect('Home:');

} catch (Nette\Security\AuthenticationException $e) {
	if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
		$form->addError('Invalid password.');
	}
}
```

Wenn möglich, empfehlen wir, den Fehler direkt zum Formularelement hinzuzufügen, da er bei Verwendung des Standard-Renderers daneben angezeigt wird.

```php
$form['date']->addError('Sorry, this date is already taken.');
```

Sie können `addError()` wiederholt aufrufen, um mehrere Fehlermeldungen an ein Formular oder Element zu übergeben. Sie erhalten sie mit `getErrors()`.

Beachten Sie, dass `$form->getErrors()` eine Zusammenfassung aller Fehlermeldungen zurückgibt, auch derjenigen, die direkt an einzelne Elemente übergeben wurden, nicht nur direkt an das Formular. Fehlermeldungen, die nur an das Formular übergeben werden, werden über `$form->getOwnErrors()` abgerufen.


Ändern von Eingabewerten .[#toc-modifying-input-values]
=======================================================

Mit der Methode `addFilter()` können wir den vom Benutzer eingegebenen Wert ändern. In diesem Beispiel werden wir Leerzeichen in der Postleitzahl tolerieren und entfernen:

```php
$form->addText('zip', 'Postleitzahl:')
	->addFilter(function ($value) {
		return str_replace(' ', '', $value); // Leerzeichen aus der Postleitzahl entfernen
	})
	->addRule($form::Pattern, 'Die Postleitzahl ist nicht fünfstellig', '\d{5}');
```

Der Filter ist zwischen den Validierungsregeln und -bedingungen eingefügt und hängt daher von der Reihenfolge der Methoden ab, d. h. der Filter und die Regel werden in der gleichen Reihenfolge aufgerufen wie die Methoden `addFilter()` und `addRule()`.


JavaScript-Überprüfung .[#toc-javascript-validation]
====================================================

Die Sprache der Validierungsregeln und -bedingungen ist mächtig. Auch wenn alle Konstruktionen sowohl server- als auch clientseitig funktionieren, in JavaScript. Die Regeln werden in HTML-Attributen `data-nette-rules` als JSON übertragen.
Die Validierung selbst wird von einem anderen Skript durchgeführt, das alle `submit` Ereignisse des Formulars abfängt, über alle Eingaben iteriert und entsprechende Validierungen durchführt.

Dieses Skript ist `netteForms.js`, das von mehreren möglichen Quellen erhältlich ist:

Sie können das Skript direkt in die HTML-Seite aus dem CDN einbetten:

```latte
<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>
```

Oder kopieren Sie es lokal in den öffentlichen Ordner des Projekts (z. B. von `vendor/nette/forms/src/assets/netteForms.min.js`):

```latte
<script src="/path/to/netteForms.min.js"></script>
```

Oder über [npm |https://www.npmjs.com/package/nette-forms] installieren:

```shell
npm install nette-forms
```

Und dann laden und ausführen:

```js
import netteForms from 'nette-forms';
netteForms.initOnLoad();
```

Alternativ können Sie es auch direkt aus dem Ordner `vendor` laden:

```js
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
```


Dynamisches JavaScript .[#toc-dynamic-javascript]
=================================================

Sie möchten die Adressfelder nur dann anzeigen, wenn der Benutzer die Ware per Post verschicken möchte? Das ist kein Problem. Der Schlüssel ist ein Paar von Methoden `addCondition()` & `toggle()`:

```php
$form->addCheckbox('send_it')
	->addCondition($form::Equal, true)
		->toggle('#address-container');
```

Dieser Code besagt, dass das HTML-Element `#address-container` sichtbar wird, wenn die Bedingung erfüllt ist, d. h. wenn das Kontrollkästchen markiert ist. Und vice versa. Wir platzieren also die Formularelemente mit der Adresse des Empfängers in einem Container mit dieser ID, und wenn das Ankreuzfeld angeklickt wird, werden sie ein- oder ausgeblendet. Dies wird durch das Skript `netteForms.js` gesteuert.

Jeder Selektor kann als Argument an die Methode `toggle()` übergeben werden. Aus historischen Gründen wird eine alphanumerische Zeichenkette ohne andere Sonderzeichen als Element-ID behandelt, so als ob ihr das `#` character. The second optional parameter allows us to reverse the behavior, i.e. if we used `toggle('#address-container', false)` vorangestellt wäre. Das Element würde nur angezeigt werden, wenn das Kontrollkästchen nicht angekreuzt ist.

Die Standardimplementierung von JavaScript ändert die Eigenschaft `hidden` für Elemente. Wir können das Verhalten jedoch leicht ändern, indem wir beispielsweise eine Animation hinzufügen. Überschreiben Sie einfach die Methode `Nette.toggle` in JavaScript mit einer benutzerdefinierten Lösung:

```js
Nette.toggle = (selector, visible, srcElement, event) => {
	document.querySelectorAll(selector).forEach((el) => {
		// hide or show 'el' according to the value of 'visible'
	});
};
```


Deaktivieren der Validierung .[#toc-disabling-validation]
=========================================================

In bestimmten Fällen müssen Sie die Gültigkeitsprüfung deaktivieren. Wenn eine Submit-Schaltfläche nach dem Absenden keine Validierung durchführen soll (z. B. *Abbrechen* oder *Vorschau*), können Sie die Validierung durch den Aufruf von `$submit->setValidationScope([])` deaktivieren. Sie können das Formular auch teilweise validieren, indem Sie Elemente angeben, die validiert werden sollen.

```php
$form->addText('name')
	->setRequired();

$details = $form->addContainer('details');
$details->addInteger('age')
	->setRequired('age');
$details->addInteger('age2')
	->setRequired('age2');

$form->addSubmit('send1'); // Validiert das gesamte Formular
$form->addSubmit('send2')
	->setValidationScope([]); // Überprüft nichts
$form->addSubmit('send3')
	->setValidationScope([$form['name']]); // Prüft nur das Feld 'name'
$form->addSubmit('send4')
	->setValidationScope([$form['details']['age']]); // Validiert nur das Feld 'age'
$form->addSubmit('send5')
	->setValidationScope([$form['details']]); // Validiert den 'details'-Container
```

[Das Ereignis onValidate |#Event onValidate] auf dem Formular wird immer aufgerufen und wird von `setValidationScope` nicht beeinflusst. `onValidate` Ereignis auf dem Container wird nur aufgerufen, wenn dieser Container für eine Teilvalidierung angegeben ist.

Validierung von Formularen

Erforderliche Steuerelemente

Steuerelemente werden mit der Methode setRequired() als erforderlich markiert, deren Argument der Text der Fehlermeldung ist, die angezeigt wird, wenn der Benutzer sie nicht ausfüllt. Wenn kein Argument angegeben wird, wird die Standard-Fehlermeldung verwendet.

$form->addText('name', 'Name:')
	->setRequired('Please fill your name.');

Regeln

Mit der Methode addRule() fügen wir den Steuerelementen Validierungsregeln hinzu. Der erste Parameter ist die Regel, der zweite die Fehlermeldung und der dritte das Argument für die Überprüfungsregel.

$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password must be at least %d characters', 8);

Validierungsregeln werden nur dann überprüft, wenn der Benutzer das Element ausgefüllt hat.

Nette verfügt über eine Reihe von vordefinierten Regeln, deren Namen Konstanten der Klasse Nette\Forms\Form sind. Wir können diese Regeln auf alle Elemente anwenden:

Konstante Beschreibung Argumente
Required alias von setRequired()
Filled alias von setRequired()
Blank darf nicht gefüllt werden
Equal Wert ist gleich dem Parameter mixed
NotEqual Wert ist nicht gleich Parameter mixed
IsIn Wert ist gleich einem Element im Array array
IsNotIn Wert ist nicht gleich einem Element im Array array
Valid Eingabe besteht Validierung (für Bedingungen)

Texteingaben

Für die Elemente addText(), addPassword(), addTextArea(), addEmail(), addInteger(), addFloat() können auch einige der folgenden Regeln angewendet werden:

MinLength minimale Stringlänge int
MaxLength maximale Länge der Zeichenkette int
Length Länge im Bereich oder exakte Länge Paar [int, int] oder int
Email gültige E-Mail Adresse
URL gültige URL
Pattern entspricht regulärem Muster string
PatternInsensitive wie Pattern, aber Groß-/Kleinschreibung wird nicht berücksichtigt string
Integer ganze Zahl
Numeric Alias von Integer
Float Ganzzahl oder Fließkommazahl
Min Minimum des Integer-Wertes int|float
Max Maximum des ganzzahligen Wertes int|float
Range Wert im Bereich Paar [int|float, int|float]

Die Regeln Integer, Numeric und Float konvertieren den Wert automatisch in Ganzzahl (bzw. Gleitkommazahl). Außerdem akzeptiert die Regel URL auch eine Adresse ohne Schema (z. B. nette.org) und vervollständigt das Schema (https://nette.org). Die Ausdrücke in Pattern und PatternInsensitive müssen für den gesamten Wert gültig sein, d. h. so, als ob er in die Zeichen ^ and $ eingeschlossen wäre.

Anzahl der Artikel

Für die Elemente addMultiUpload(), addCheckboxList(), addMultiSelect() können Sie auch die folgenden Regeln verwenden, um die Anzahl der ausgewählten Elemente oder hochgeladenen Dateien zu begrenzen:

MinLength Mindestanzahl int
MaxLength maximale Anzahl int
Length Anzahl im Bereich oder genaue Anzahl Paare [int, int] oder int

Datei hochladen

Für die Steuerelemente addUpload(), addMultiUpload() können auch die folgenden Regeln verwendet werden:

MaxFileSize Maximale Dateigröße in Bytes int
MimeType MIME-Typ, akzeptiert Wildcards ('video/*') string|string[]
Image hochgeladene Datei ist JPEG, PNG, GIF, WebP
Pattern Dateiname entspricht regulärem Ausdruck string
PatternInsensitive wie Pattern, aber Groß-/Kleinschreibung wird nicht berücksichtigt string

Für MimeType und Image ist die PHP-Erweiterung fileinfo erforderlich. Ob eine Datei oder ein Bild dem erforderlichen Typ entspricht, wird anhand ihrer Signatur erkannt. Die Integrität der gesamten Datei wird nicht geprüft. Sie können herausfinden, ob ein Bild nicht beschädigt ist, indem Sie beispielsweise versuchen, es zu laden.

Fehlermeldungen

Alle vordefinierten Regeln außer Pattern und PatternInsensitive haben eine Standard-Fehlermeldung, so dass sie weggelassen werden können. Wenn Sie jedoch alle benutzerdefinierten Meldungen übergeben und formulieren, wird das Formular benutzerfreundlicher.

Sie können die Standardmeldungen in configuration ändern, indem Sie die Texte im Array Nette\Forms\Validator::$messages ändern oder den Übersetzer verwenden.

Die folgenden Platzhalter können im Text der Fehlermeldungen verwendet werden:

%d ersetzt schrittweise die Regeln nach den Argumenten
%n$d ersetzt durch das n-te Regelargument
%label ersetzt durch Feldbezeichnung (ohne Doppelpunkt)
%name ersetzt durch den Feldnamen (z.B. name)
%value ersetzt durch den vom Benutzer eingegebenen Wert
$form->addText('name', 'Name:')
	->setRequired('Please fill in %label');

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'at least %d and no more than %d', [5, 10]);

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'no more than %2$d and at least %1$d', [5, 10]);

Bedingungen

Neben den Validierungsregeln können auch Bedingungen festgelegt werden. Sie werden ähnlich wie Regeln gesetzt, jedoch verwenden wir addRule() anstelle von addCondition() und lassen sie natürlich ohne Fehlermeldung stehen (die Bedingung fragt nur):

$form->addPassword('password', 'Passwort:')
	// wenn das Passwort nicht länger als 8 Zeichen ist ...
	->addCondition($form::MaxLength, 8)
		// ... dann muss es eine Zahl enthalten
		->addRule($form::Pattern, 'Muss Zahl enthalten', '.*[0-9].*');

Die Bedingung kann mit einem anderen Element als dem aktuellen verknüpft werden, indem addConditionOn() verwendet wird. Der erste Parameter ist ein Verweis auf das Feld. Im folgenden Fall ist die E-Mail nur erforderlich, wenn das Kontrollkästchen aktiviert ist (d. h. sein Wert ist true):

$form->addCheckbox('newsletters', 'Newsletter versenden');

$form->addEmail('email', 'Email:')
	// wenn das Kontrollkästchen aktiviert ist ...
	->addConditionOn($form['newsletters'], $form::Equal, true)
		// ... erfordern E-Mail
		->setRequired('Füllen Sie Ihre E-Mail-Adresse aus');

Bedingungen können mit den Methoden elseCondition() und endCondition() zu komplexen Strukturen gruppiert werden.

$form->addText(/* ... */)
	->addCondition(/* ... */) // wenn die erste Bedingung erfüllt ist
		->addConditionOn(/* ... */) // und die zweite Bedingung auch für ein anderes Element
			->addRule(/* ... */) // erfordert diese Regel
		->elseCondition() // wenn die zweite Bedingung nicht erfüllt ist
			->addRule(/* ... */) // erfordert diese Regeln
			->addRule(/* ... */)
		->endCondition() // wir kehren zur ersten Bedingung zurück
		->addRule(/* ... */);

In Nette ist es sehr einfach, auf die Erfüllung oder Nichterfüllung einer Bedingung auf der JavaScript-Seite mit der Methode toggle() zu reagieren, siehe Dynamisches JavaScript.

Referenzen zwischen Controls

Das Regel- oder Bedingungsargument kann ein Verweis auf ein anderes Element sein. Sie können zum Beispiel dynamisch überprüfen, ob text so viele Zeichen hat wie der Wert des Feldes length beträgt:

$form->addInteger('length');
$form->addText('text')
	->addRule($form::Length, null, $form['length']);

Benutzerdefinierte Regeln und Bedingungen

Manchmal kommen wir in eine Situation, in der die eingebauten Validierungsregeln in Nette nicht ausreichen und wir die Daten des Benutzers auf unsere eigene Weise validieren müssen. In Nette ist das sehr einfach!

Sie können einen beliebigen Callback als ersten Parameter an die Methoden addRule() oder addCondition() übergeben. Der Callback akzeptiert das Element selbst als ersten Parameter und gibt einen booleschen Wert zurück, der angibt, ob die Validierung erfolgreich war. Beim Hinzufügen einer Regel mit addRule() können zusätzliche Argumente übergeben werden, die dann als zweiter Parameter übergeben werden.

Der benutzerdefinierte Satz von Validatoren kann somit als Klasse mit statischen Methoden erstellt werden:

class MyValidators
{
	// prüft, ob der Wert durch das Argument teilbar ist
	public static function validateDivisibility(BaseControl $input, $arg): bool
	{
		return $input->getValue() % $arg === 0;
	}

	public static function validateEmailDomain(BaseControl $input, $domain)
	{
		// zusätzliche Prüfer
	}
}

Die Verwendung ist dann sehr einfach:

$form->addInteger('num')
	->addRule(
		[MyValidators::class, 'validateDivisibility'],
		'The value must be a multiple of %d',
		8,
	);

Benutzerdefinierte Validierungsregeln können auch zu JavaScript hinzugefügt werden. Die einzige Bedingung ist, dass die Regel eine statische Methode sein muss. Ihr Name für den JavaScript-Validator wird durch Verkettung des Klassennamens ohne Backslashes \, the underscore _ und des Methodennamens gebildet. Schreiben Sie zum Beispiel App\MyValidators::validateDivisibility als AppMyValidators_validateDivisibility und fügen Sie es dem Objekt Nette.validators hinzu:

Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
	return val % args === 0;
};

Ereignis onValidate

Nach dem Absenden des Formulars wird die Validierung durchgeführt, indem die einzelnen von addRule() hinzugefügten Regeln überprüft und dann das Ereignis onValidate aufgerufen wird. Dessen Handler kann für zusätzliche Validierungen verwendet werden, in der Regel um die korrekte Kombination von Werten in mehreren Formularelementen zu überprüfen.

Wenn ein Fehler festgestellt wird, wird er mit der Methode addError() an das Formular weitergegeben. Diese kann entweder für ein bestimmtes Element oder direkt für das Formular aufgerufen werden.

protected function createComponentSignInForm(): Form
{
	$form = new Form;
	// ...
	$form->onValidate[] = [$this, 'validateSignInForm'];
	return $form;
}

public function validateSignInForm(Form $form, \stdClass $data): void
{
	if ($data->foo > 1 && $data->bar > 5) {
		$form->addError('Diese Kombination ist nicht möglich.');
	}
}

Verarbeitung von Fehlern

In vielen Fällen entdecken wir einen Fehler, wenn wir ein gültiges Formular verarbeiten, z. B. wenn wir einen neuen Eintrag in die Datenbank schreiben und auf einen doppelten Schlüssel stoßen. In diesem Fall geben wir den Fehler mit der Methode addError() an das Formular zurück. Diese Methode kann entweder für ein bestimmtes Element oder direkt für das Formular aufgerufen werden:

try {
	$data = $form->getValues();
	$this->user->login($data->username, $data->password);
	$this->redirect('Home:');

} catch (Nette\Security\AuthenticationException $e) {
	if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
		$form->addError('Invalid password.');
	}
}

Wenn möglich, empfehlen wir, den Fehler direkt zum Formularelement hinzuzufügen, da er bei Verwendung des Standard-Renderers daneben angezeigt wird.

$form['date']->addError('Sorry, this date is already taken.');

Sie können addError() wiederholt aufrufen, um mehrere Fehlermeldungen an ein Formular oder Element zu übergeben. Sie erhalten sie mit getErrors().

Beachten Sie, dass $form->getErrors() eine Zusammenfassung aller Fehlermeldungen zurückgibt, auch derjenigen, die direkt an einzelne Elemente übergeben wurden, nicht nur direkt an das Formular. Fehlermeldungen, die nur an das Formular übergeben werden, werden über $form->getOwnErrors() abgerufen.

Ändern von Eingabewerten

Mit der Methode addFilter() können wir den vom Benutzer eingegebenen Wert ändern. In diesem Beispiel werden wir Leerzeichen in der Postleitzahl tolerieren und entfernen:

$form->addText('zip', 'Postleitzahl:')
	->addFilter(function ($value) {
		return str_replace(' ', '', $value); // Leerzeichen aus der Postleitzahl entfernen
	})
	->addRule($form::Pattern, 'Die Postleitzahl ist nicht fünfstellig', '\d{5}');

Der Filter ist zwischen den Validierungsregeln und -bedingungen eingefügt und hängt daher von der Reihenfolge der Methoden ab, d. h. der Filter und die Regel werden in der gleichen Reihenfolge aufgerufen wie die Methoden addFilter() und addRule().

JavaScript-Überprüfung

Die Sprache der Validierungsregeln und -bedingungen ist mächtig. Auch wenn alle Konstruktionen sowohl server- als auch clientseitig funktionieren, in JavaScript. Die Regeln werden in HTML-Attributen data-nette-rules als JSON übertragen. Die Validierung selbst wird von einem anderen Skript durchgeführt, das alle submit Ereignisse des Formulars abfängt, über alle Eingaben iteriert und entsprechende Validierungen durchführt.

Dieses Skript ist netteForms.js, das von mehreren möglichen Quellen erhältlich ist:

Sie können das Skript direkt in die HTML-Seite aus dem CDN einbetten:

<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>

Oder kopieren Sie es lokal in den öffentlichen Ordner des Projekts (z. B. von vendor/nette/forms/src/assets/netteForms.min.js):

<script src="/path/to/netteForms.min.js"></script>

Oder über npm installieren:

npm install nette-forms

Und dann laden und ausführen:

import netteForms from 'nette-forms';
netteForms.initOnLoad();

Alternativ können Sie es auch direkt aus dem Ordner vendor laden:

import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();

Dynamisches JavaScript

Sie möchten die Adressfelder nur dann anzeigen, wenn der Benutzer die Ware per Post verschicken möchte? Das ist kein Problem. Der Schlüssel ist ein Paar von Methoden addCondition() & toggle():

$form->addCheckbox('send_it')
	->addCondition($form::Equal, true)
		->toggle('#address-container');

Dieser Code besagt, dass das HTML-Element #address-container sichtbar wird, wenn die Bedingung erfüllt ist, d. h. wenn das Kontrollkästchen markiert ist. Und vice versa. Wir platzieren also die Formularelemente mit der Adresse des Empfängers in einem Container mit dieser ID, und wenn das Ankreuzfeld angeklickt wird, werden sie ein- oder ausgeblendet. Dies wird durch das Skript netteForms.js gesteuert.

Jeder Selektor kann als Argument an die Methode toggle() übergeben werden. Aus historischen Gründen wird eine alphanumerische Zeichenkette ohne andere Sonderzeichen als Element-ID behandelt, so als ob ihr das # character. The second optional parameter allows us to reverse the behavior, i.e. if we used toggle('#address-container', false) vorangestellt wäre. Das Element würde nur angezeigt werden, wenn das Kontrollkästchen nicht angekreuzt ist.

Die Standardimplementierung von JavaScript ändert die Eigenschaft hidden für Elemente. Wir können das Verhalten jedoch leicht ändern, indem wir beispielsweise eine Animation hinzufügen. Überschreiben Sie einfach die Methode Nette.toggle in JavaScript mit einer benutzerdefinierten Lösung:

Nette.toggle = (selector, visible, srcElement, event) => {
	document.querySelectorAll(selector).forEach((el) => {
		// hide or show 'el' according to the value of 'visible'
	});
};

Deaktivieren der Validierung

In bestimmten Fällen müssen Sie die Gültigkeitsprüfung deaktivieren. Wenn eine Submit-Schaltfläche nach dem Absenden keine Validierung durchführen soll (z. B. Abbrechen oder Vorschau), können Sie die Validierung durch den Aufruf von $submit->setValidationScope([]) deaktivieren. Sie können das Formular auch teilweise validieren, indem Sie Elemente angeben, die validiert werden sollen.

$form->addText('name')
	->setRequired();

$details = $form->addContainer('details');
$details->addInteger('age')
	->setRequired('age');
$details->addInteger('age2')
	->setRequired('age2');

$form->addSubmit('send1'); // Validiert das gesamte Formular
$form->addSubmit('send2')
	->setValidationScope([]); // Überprüft nichts
$form->addSubmit('send3')
	->setValidationScope([$form['name']]); // Prüft nur das Feld 'name'
$form->addSubmit('send4')
	->setValidationScope([$form['details']['age']]); // Validiert nur das Feld 'age'
$form->addSubmit('send5')
	->setValidationScope([$form['details']]); // Validiert den 'details'-Container

Das Ereignis onValidate auf dem Formular wird immer aufgerufen und wird von setValidationScope nicht beeinflusst. onValidate Ereignis auf dem Container wird nur aufgerufen, wenn dieser Container für eine Teilvalidierung angegeben ist.