Validierung komplexer Reaktionsformen. Teil 1

Zuerst müssen Sie die React-Validation-Boo- Komponente installieren. Ich gehe davon aus, dass Sie mit React vertraut sind und wissen, wie man sie konfiguriert.

npm install reagiere-validierung-boo

Um nicht viel zu reden, werde ich sofort ein kleines Codebeispiel geben.

import React, {Component} from 'react'; import {connect, Form, Input, logger} from 'react-validation-boo'; class MyForm extends Component { sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; render() { return <Form connect={this.props.vBoo.connect}> <div> <Input type="text" name="name" /> {this.getError('name')} </div> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: () => ( [ ['name', 'required'], ] ), middleware: logger })(MyForm); 


Lassen Sie uns diesen Code analysieren.

Beginnen wir mit der Verbindungsfunktion , wir übergeben unsere Validierungsregeln und andere zusätzliche Parameter an sie. Durch Aufrufen dieser Methode erhalten wir eine neue Funktion, in der wir unsere Komponente ( MyForm ) übergeben, damit sie die erforderlichen Methoden für die Arbeit mit der Formularvalidierung in Requisiten erhält .

In der Renderfunktion unserer Komponente geben wir die Formularkomponente zurück , die wir mit den Validierungsregeln verbinden. Connect = {this.props.connect} . Dies ist ein notwendiger Entwurf, damit Form weiß, wie verschachtelte Komponenten validiert werden.
<Input type = "text" name = "name" /> Das Eingabefeld, das wir überprüfen werden, hat die Überprüfungsregeln übergeben, um eine Verbindung in der Regeleigenschaft herzustellen. In unserem Fall sollte dieser Name nicht leer sein ( erforderlich ).

Wir haben auch Middleware: Logger übergeben , um eine Verbindung herzustellen , um zu sehen, wie die Validierung in der Konsole funktioniert.

In den Requisiten unserer Komponente haben wir eine Reihe von Funktionen:

  1. vBoo.isValid () - gibt true zurück , wenn alle Eingabekomponenten validiert wurden
  2. vBoo.hasError (name) - gibt true zurück , wenn die Komponente mit der Eigenschaft name ungültig ist
  3. vBoo.getError (Name) - Gibt für eine Komponente mit der Eigenschaft name den Fehlertext zurück

Jetzt werden wir es schrittweise komplizieren. Zuerst übergeben wir die Sprache für die Verbindung , damit wir die Validierungsregeln je nach Sprache ändern und zusätzliche Felder und Validierungsregeln hinzufügen können.

 import React, {Component} from 'react'; import {connect, Form, Input, InputCheckbox} from 'react-validation-boo'; class MyForm extends Component { sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; render() { return <Form connect={this.props.vBoo.connect}> <div> <label>{this.props.vBoo.getLabel('name')}:</label> <Input type="text" name="name" /> {this.getError('name')} </div> <div> <label>{this.props.vBoo.getLabel('email')}:</label> <Input type="text" name="email" value="default@mail.ru" /> {this.getError('email')} </div> <div> <label>{this.props.vBoo.getLabel('remember')}:</label> <InputCheckbox name="remember" value="yes" /> {this.getError('remember')} </div> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: (lang) => { let rules = [ [ ['name', 'email'], 'required', { error: '%name%    ' } ], ['email', 'email'] ]; rules.push(['remember', lang === 'ru' ? 'required': 'valid']); return rules; }, labels: (lang) => ({ name: '', email: ' ', remember: '' }), lang: 'ru' })(MyForm); 

In diesem Beispiel muss das Kontrollkästchen Merken in Russisch erforderlich installiert sein, in anderen ist es jedoch immer gültig.

Wir haben auch die Funktionsbezeichnungen (lang) zum Verbinden übergeben , die den Namen der Felder in lesbarer Form zurückgeben.

In den Requisiten Ihrer Komponente gibt es eine getLabel- Funktion (Name) , die den an die Labels- Funktion übergebenen Wert zurückgibt. Wenn kein solcher Wert vorhanden ist, wird der Name zurückgegeben .

VBoo-Kernkomponenten


Form , Input , InputRadio , InputCheckbox , Select , Textarea .

 import React, {Component} from 'react'; import {connect, Form, Input, Select, InputRadio, InputCheckbox, Textarea} from 'react-validation-boo'; class MyForm extends Component { sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; render() { return <Form connect={this.props.vBoo.connect}> <div> <label>{this.props.vBoo.getLabel('name')}:</label> <Input type="text" name="name" /> {this.getError('name')} </div> <div> <label>{this.props.vBoo.getLabel('email')}:</label> <Input type="text" name="email" value="default@mail.ru" /> {this.getError('email')} </div> <div> <label>{this.props.vBoo.getLabel('gender')}:</label> <Select name="gender"> <option disabled> </option> <option value="1"></option> <option value="2"></option> </Select> {this.getError('gender')} </div> <div> <div>{this.props.vBoo.getLabel('familyStatus')}:</div> <div> <InputRadio name="familyStatus" value="1" checked /> <label></label> </div> <div> <InputRadio name="familyStatus" value="2" /> <label></label> </div> <div> <InputRadio name="familyStatus" value="3" /> <label></label> </div> {this.getError('familyStatus')} </div> <div> <label>{this.props.vBoo.getLabel('comment')}:</label> <Textarea name="comment"></Textarea> {this.getError('comment')} </div> <div> <label>{this.props.vBoo.getLabel('remember')}:</label> <InputCheckbox name="remember" value="yes" /> {this.getError('remember')} </div> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: () => ([ [ ['name', 'email'], 'required', { error: '%name%    ' } ], ['email', 'email'], [['gender', 'familyStatus', 'comment', 'remember'], 'valid'] ]), labels: () => ({ name: '', email: ' ', gender: '', familyStatus: ' ', comment: '', remember: '' }), lang: 'ru' })(MyForm); 

Validierungsregeln


Schauen wir uns an, wie wir unsere eigenen Validierungsregeln schreiben.
Um eine Regel zu schreiben, müssen Sie eine Klasse erstellen, die von der Validator- Klasse geerbt wird.

 import {validator} from 'react-validation-boo'; class myValidator extends validator { /** * name -  ,   label    * value -    * params -     3-    (rules) */ validate(name, value, params) { let lang = this.getLang(); let pattern = /^\d+$/; if(!pattern.test(value)) { let error = params.error || '   %name%   %value%'; error = error.replace('%name%', name); error = error.replace('%value%', value); this.addError(error); } } } export default myValidator; 

Verbinden Sie nun unseren Validator mit dem Formular.
 import myValidator from 'path/myValidator'; // ... export default connect({ rules: () => ([ [ 'name', 'required', { error: '%name%    ' } ], [ 'name', 'myValidator', { error: '   params.error' } ] ]), labels: () => ({ name: '' }), validators: { myValidator }, lang: 'ru' })(MyForm); 

Um nicht jedes Mal alle Ihre Validierungsregeln zu registrieren, erstellen Sie eine separate Datei, in der sie registriert werden, und verbinden Sie die Validatoren: "Importieren" der Dateivalidierung " . Und wenn es spezielle Regeln für dieses Formular gibt, dann Validatoren: Object.assign ({}, `Import 'File-Validation``, {...})

Szenarien


Betrachten Sie die Fälle, in denen wir die Validierungsregeln abhängig von den im Formular ausgeführten Aktionen ändern müssen.

Standardmäßig haben wir ein Skript namens default . In den Regeln können wir angeben, unter welchem ​​Szenario diese Validierung durchgeführt werden soll.

Wenn kein Skript angegeben ist, wird die Validierung für alle Szenarien durchgeführt.

 rules = () => ([ [ 'name', 'required', { error: '%name%    ' } ], [ 'name', 'myValidator', { scenario: ['default', 'scenario1'] } ], [ 'email', 'email', { scenario: 'scenario1' } ] ]) 

Die Funktion wird über die Requisiteneigenschaft unserer Komponente übergeben:

  1. vBoo.setScenario (Szenario) - Legt das Szenarioskript fest. Es kann entweder eine Zeichenfolge oder ein Array sein, wenn mehrere Skripte gleichzeitig aktiv sind
  2. vBoo.getScenario () - Gibt das aktuelle Skript oder Array von Skripten zurück
  3. vBoo.hasScenario (Name) - ob dieses Skript jetzt installiert ist, Name Zeichenfolge

Fügen wir in unserem Formular ein Szenarioobjekt hinzu , in dem alle möglichen Skripte gespeichert werden. Richtig , das Skript ist aktiv, falsch ist nicht.

Sowie Funktionen addScenaries und deleteScenaries , mit denen Skripte hinzugefügt und entfernt werden.

Wenn wir "Zusammenleben" oder "Ehe" ausgewählt haben, fügen wir ein Kommentarfeld hinzu, und dieses Feld sollte natürlich nur in diesem Fall, dem Szenario-verheirateten Szenario , validiert werden .

Wenn das Kontrollkästchen "Erweitert" aktiviert ist, fügen wir zusätzliche Felder hinzu, die erforderlich sind, das Skript " Szenario-Addition ".

 import React, {Component} from 'react'; import {connect, Form, Input, Select, InputRadio, InputCheckbox, Textarea} from 'react-validation-boo'; class MyForm extends Component { constructor() { super(); this.scenaries = { 'scenario-married': false, 'scenario-addition': false } } changeScenaries(addScenaries = [], deleteScenaries = []) { addScenaries.forEach(item => this.scenaries[item] = true); deleteScenaries.forEach(item => this.scenaries[item] = false); let scenario = Object.keys(this.scenaries) .reduce((result, item) => this.scenaries[item]? result.concat(item): result, []); this.props.vBoo.setScenario(scenario); } addScenaries = (m = []) => this.changeScenaries(m, []); deleteScenaries = (m = []) => this.changeScenaries([], m); sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; changeFamilyStatus = (event) => { let val = event.target.value; if(val !== '1') { this.addScenaries(['scenario-married']) } else { this.deleteScenaries(['scenario-married']); } }; changeAddition = (event) => { let check = event.target.checked; if(check) { this.addScenaries(['scenario-addition']) } else { this.deleteScenaries(['scenario-addition']); } }; getCommentContent() { if(this.props.vBoo.hasScenario('scenario-married')) { return ( <div key="comment-content"> <label>{this.props.vBoo.getLabel('comment')}:</label> <Textarea name="comment"></Textarea> {this.getError('comment')} </div> ); } return ''; } getAdditionContent() { if(this.props.vBoo.hasScenario('scenario-addition')) { return ( <div key="addition-content"> <label>{this.props.vBoo.getLabel('place')}:</label> <Input type="text" name="place" /> {this.getError('place')} </div> ); } return ''; } render() { return <Form connect={this.props.vBoo.connect}> <div> <label>{this.props.vBoo.getLabel('name')}:</label> <Input type="text" name="name" /> {this.getError('name')} </div> <div> <label>{this.props.vBoo.getLabel('email')}:</label> <Input type="text" name="email" value="default@mail.ru" /> {this.getError('email')} </div> <div> <label>{this.props.vBoo.getLabel('gender')}:</label> <Select name="gender"> <option disabled> </option> <option value="1"></option> <option value="2"></option> </Select> {this.getError('gender')} </div> <div> <div>{this.props.vBoo.getLabel('familyStatus')}:</div> <div> <InputRadio name="familyStatus" value="1" checked onChange={this.changeFamilyStatus} /> <label></label> </div> <div> <InputRadio name="familyStatus" value="2" onChange={this.changeFamilyStatus} /> <label></label> </div> <div> <InputRadio name="familyStatus" value="3" onChange={this.changeFamilyStatus} /> <label></label> </div> {this.getError('familyStatus')} </div> {this.getCommentContent()} <div> <label>{this.props.vBoo.getLabel('addition')}:</label> <InputCheckbox name="addition" value="yes" onChange={this.changeAddition} /> {this.getError('addition')} </div> {this.getAdditionContent()} <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: () => ([ [ ['name', 'gender', 'familyStatus', 'email'], 'required', { error: '%name%    ' } ], ['email', 'email'], [ 'comment', 'required', { scenario: 'scenario-married' } ], ['addition', 'valid'], [ 'place', 'required', { scenario: 'scenario-addition' } ], ]), labels: () => ({ name: '', email: ' ', gender: '', familyStatus: ' ', comment: '', addition: '', place: '' }), lang: 'ru' })(MyForm); 

Um den Artikel nicht sehr groß zu machen, werde ich mit dem nächsten fortfahren, in dem ich schreibe, wie ich meine Komponenten (z. B. einen Kalender oder eine Eingabesuche) erstelle und validiere, wie ich sie mit Redux verknüpfe und mehr.

Source: https://habr.com/ru/post/de430312/


All Articles