Neues Validierungspaket für React on Mobx @ quantumart / mobx-form-validation-kit

Guten Tag.
Heute möchte ich über ein neues Paket für asynchrone Validierungen in Projekten sprechen, die auf React , Mobx basieren und in Typescript geschrieben sind .
Die moderne Frontend-Entwicklung erfordert viel Logik beim Ausfüllen von Seiten mit Dokumenten, Fragebögen und Dokumenten für einen Kredit, Zahlungsaufträgen und Registrierungsseiten auf der Website. Die logische Hauptlast liegt bei den Validierungsprüfungen. Angular- Entwickler haben über diesen Punkt nachgedacht und bieten Entwicklern an, den integrierten FormControl- Mechanismus für diese Zwecke zu verwenden, der zwar eine Reihe von Nachteilen aufweist, aber immer noch besser ist als das völlige Fehlen einer solchen Lösung für React . Die Situation wird durch die Tatsache kompliziert, dass der aktuelle Trend der React- Entwicklung die Verwendung von Mobx zur Organisation der Geschäftslogik beinhaltet.
Angesichts dieser Probleme haben wir alle gelöst, indem wir ein Paket geschrieben haben: @ quantumart / mobx-form-validation-kit

Paketvorteile:
  • Ganz auf TypeScript
  • Kompatibel mit Mobx (Version 4, die IE10 unterstützt, jedermanns Favorit)
  • Entwickelt für die Arbeit in React (kann in Projekten ohne React verwendet werden)
  • Entwickelt für die asynchrone Validierung
  • Einfach in ein bestehendes Projekt einzubetten.

Anleitung zum Arbeiten mit der Verpackung unter dem Schnitt.


Zu Beginn werden wir die Funktionalität des @ quantumart / mobx-Formularvalidierungs-Kit- Pakets beschreiben. Am Ende des Artikels werden wir eine voll funktionsfähige Seite mit einem Beispiel für das Registrierungsformular auf der Website schreiben.

Formcontrol


Mit @ quantumart / mobx-form-validation-kit können Sie eine Ebene zwischen den Quelldaten und dem anzuzeigenden Formular erstellen. Auf diese Weise können Sie sie validieren und gegebenenfalls die Daten ändern, bevor sie zum ursprünglichen Objekt gelangen.

Die @ quantumart / mobx-Formularvalidierungskit- Bibliothek enthält drei Hauptklassen (Validierungskomponenten) zum Verwalten des Formulars:
  • FormGroup - Ermöglicht das Kombinieren von Validierungskomponenten. Die Klasse ist typisiert und ermöglicht es Ihnen, die Schnittstelle mit der Liste der Felder als generischen Parameter neu zu erstellen. Alle sind standardmäßig registriert. Es wird dringend empfohlen, sie nicht ohne Eingabe zu verwenden, es besteht jedoch die Möglichkeit.
  • FormControl - wird verwendet, um ein bestimmtes Feld zu validieren, die am häufigsten verwendete Klasse. Die Klasse ist typisiert und verwendet als generischen Parameter den Typ der Variablen, die gespeichert werden soll. Standardmäßig ist string registriert, weil Die Standardeinstellung ist Zeichenfolge als privateste Option für Formulare.
  • FormArray - Ermöglicht das Erstellen und Verwalten eines Arrays von Validierungskomponenten.

Darüber hinaus gibt es grundlegende abstrakte Klassen
  • AbstractControl - die Basisklasse für alle aufgelisteten Validierungsklassen, nicht typisiert.
  • FormAbstractControl - Basisklasse für FormGroup und FormArray , nicht eingegeben.
  • FormAbstractGroup - keine typisierte Basisklasse für FormControl, enthält einen Link zum HTML-Element, das gerendert wird.

Die beste Vorgehensweise zum Erstellen eines Validierungsformulars ist die folgende Idee.
Auf dem Formular wird ein Objekt vom Typ 1 FormGroup erstellt, in dem die Felder bereits aufgeführt sind
this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ), surname: new FormControl( this.userInfo.surname, [], v => (this.userInfo.surname = v) ) // … }); 

FormGroup unterstützt das Verschachteln, d.h.
 this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ), surname: new FormControl( this.userInfo.surname, [], v => (this.userInfo.surname = v) ) passport: new FormGroup<IPassport >({ number: new FormControl( this.userInfo.passport.number, [], v => (this.userInfo.passport.number = v) ), // … }) // … }); 

Sie können FormArray hinzufügen, dem wiederum der Typ FormControl und / oder die gesamte FormGroup übergeben werden können , um Objekte beliebiger Komplexität und Struktur zu erstellen.
  • FormArray <FormControl>
    FormArray <FormGroup>

    FormControl selbst übernimmt die folgenden Parameter in den Konstruktor
    • value : TEntity ist der eingegebene Anfangswert.
    • Validatoren : ValidatorFunctionFormControlHandler [] - eine Reihe von Validatoren.
    • callbackValidValue : UpdateValidValueHandler | null - Rückruffunktion, an die der letzte gültige Wert übergeben wird. Es wird jedes Mal aufgerufen, wenn sich ein Wert in FormControl ändert und dieser Wert die beschriebenen Überprüfungen besteht.
    • aktivieren : (() => boolean) | null - Die Funktion aktiviert / deaktiviert Validierungen nach Bedingung (immer standardmäßig aktiviert). Beispielsweise muss die Gültigkeit des Enddatums des Dienstes nicht aktiviert werden, wenn das Kontrollkästchen "Unbegrenzt" nicht aktiviert ist. Wenn Sie hier einfach eine Funktion eingeben, die den Status des beobachtbaren Felds aktiviert, das für das Kontrollkästchen "Unbegrenzt" verantwortlich ist, können Sie automatisch alle mit dem Feld verknüpften Überprüfungen zum Überprüfen des Datums deaktivieren und diese Logik nicht in jeder der Datumsfeldüberprüfungen registrieren.
    • zusätzliche Daten: TAdditionalData | null - Mit einem Block mit zusätzlichen Informationen können Sie einem bestimmten FormControl zusätzliche Informationen hinzufügen und diese später beispielsweise zur Visualisierung verwenden. Dies ist praktisch, wenn es Builder für FormControl gibt, in denen Sie bestimmte Informationen analysieren müssen und diese Informationen nicht zur Visualisierung über ein komplexes Datenpaket an die Steuerelemente weitergeben müssen. Obwohl ich kein genaues und unbestreitbares Anwendungsszenario angeben kann, ist es besser, eine solche Gelegenheit zu haben, als ohne sie zu leiden.

    Angular FormControl hat eine Einschränkung: Es ist nicht erforderlich, Objekte in verschiedenen Formularen wiederzuverwenden. Das heißt, Sie können einen FormGroup- Builder erstellen und auf jeder Seite ein eigenes Objekt erstellen. Die Verwendung eines Objekts pro Seitenbündel ist jedoch eine schlechte Praxis.
    Darüber hinaus wird FormControl mit einem einzelnen Wert initialisiert. Wenn dieser Wert geändert wird, wird der neue Wert nicht in FormControl übernommen . Dies geschieht absichtlich, weil, wie die Praxis gezeigt hat, aus irgendeinem Grund jeder hartnäckig versucht, das ursprüngliche Objekt zunächst unter Umgehung von Validierungen zu bearbeiten, und nicht den Wert in FormControl . Weisen Sie dem Wertefeld des FormControl einfach einen neuen Wert zu, um das ursprüngliche Objekt zu ändern.
    FormGroup akzeptiert die folgenden Parameter im Konstruktor:
    • Steuerelemente : TControls - ein von AbstractControls geerbtes Objekt. Erstellen Sie einfach eine von AbstractControls geerbte Schnittstelle, in der Sie Felder vom Typ FormGroup , FormControl , FormArray auflisten . Sie können den Typ natürlich auf einen beliebigen einstellen, aber dann gehen alle Vorteile von TypeScript verloren.
    • Validatoren : ValidatorFunctionFormGroupHandler [] - Eine Reihe von Validatoren für Gruppenwerte. Sie können beispielsweise eine FormGroup erstellen, die zwei Werte enthält - das minimale und das maximale Datum für die Periodenauswahlsteuerung. In diesen Validatoren müssen Sie die Funktion / en zur Überprüfung des Datumsbereichs übergeben. Zum Beispiel, dass das Startdatum nicht größer als das Enddatum ist
    • aktivieren : (() => boolean) | null - Die Funktion aktiviert / deaktiviert Validierungen nach Bedingung (immer standardmäßig aktiviert). Es versteht sich, dass das Anwenden der Validierungsfunktion auf eine Gruppe die Validierung auf Gruppenebene deaktiviert. Zum Beispiel haben wir ein Auswahlfeld für ein Ausweisdokument. Sie können mehrere FormGroups mit unterschiedlichen Feldern für Dokumente erstellen: Reisepass, Führerschein, Seemannspass usw. In dieser Funktion überprüfen Sie die Dropdown-Werte. Wenn der ausgewählte Wert nicht dieser Gruppe entspricht, sind alle Validierungsprüfungen deaktiviert. Genauer gesagt wird die Gruppe unabhängig von den darin enthaltenen Werten als gültig betrachtet.

    Lassen Sie uns über FormControl- Felder sprechen, einschließlich des Vorhandenseins von FormGroup und FormArray .
    • ControlTypes - Steuerelementtyp (Control | Group | Array)
    • Verarbeitung : Boolesch - im Analyseprozess. Weil Asynchrone Überprüfungen werden beispielsweise unterstützt, für die eine Serveranforderung erforderlich ist. In diesem Feld finden Sie den aktuellen Status des Scans.
      Darüber hinaus unterstützen FormGroup und FormArray die Wartemethode , mit der Sie warten können, bis die Prüfung abgeschlossen ist. Wenn Sie beispielsweise auf die Schaltfläche "Daten senden" klicken, müssen Sie das folgende Design registrieren.
       await this.form.wait(); if (this.form.invalid) { … 

    • disabled : boolean - Fehlerprüfung ist deaktiviert (Kontrolle ist immer gültig)
    • active : boolean - Fehlerprüfung ist aktiviert. Hängt vom Ergebnis der Aktivierungsfunktion ab. Dieser Wert ist sehr praktisch, um eine Gruppe von Feldern in einem Formular auszublenden und keine zusätzlichen und doppelten Funktionen der Geschäftslogik zu schreiben.
    • ungültig : boolean; - für FormControl - bedeutet, dass das Feld Validierungsfehler enthält. Für FormGroup und FormArray bedeutet dies, dass entweder das Gruppensteuerelement selbst Fehler enthält oder eines der verschachtelten Felder (auf einer der Verschachtelungsebenen) Validierungsfehler enthält. Das heißt, Um die Gültigkeit des gesamten Formulars zu überprüfen, reicht es aus, eine ungültige oder gültige Prüfung der oberen FormGroup durchzuführen.
    • valid : boolean - für FormControl - bedeutet, dass das Feld keine Validierungsfehler enthält. Für FormGroup und FormArray bedeutet dies, dass entweder das Gruppensteuerelement selbst keine Fehler enthält und keines der verschachtelten Felder (auf einer beliebigen Verschachtelungsebene) Validierungsfehler enthält.
    • pristine : boolean - Der Wert im Feld hat sich nach der Initialisierung mit dem Standardwert nicht geändert.
    • Dirty : Boolean - Der Wert im Feld wurde nach der Initialisierung mit dem Standardwert geändert.
    • unberührt : Boolesch - für FormControl - bedeutet, dass das Feld (z. B. Eingabe) nicht scharfgestellt war. Für FormGroup und FormArray bedeutet dies, dass keines der verschachtelten FormControls im Fokus stand. Der Wert false in diesem Feld bedeutet, dass der Fokus nicht nur festgelegt, sondern auch aus dem Feld entfernt wurde.
    • berührt : boolean - Für FormControl - bedeutet, dass das Feld (z. B. Eingabe) im Fokus war. Für FormGroup und FormArray bedeutet dies, dass eines der verschachtelten FormControls im Fokus stand. Der Wert true in diesem Feld bedeutet, dass der Fokus nicht nur festgelegt, sondern auch aus dem Feld entfernt wurde.
    • fokussiert : Boolesch - für FormControl - bedeutet, dass das Feld (z. B. Eingabe) jetzt im Fokus ist. Für FormGroup und FormArray bedeutet dies, dass eines der verschachtelten FormControls jetzt im Fokus steht.
    • Fehler : ValidationEvent [] - Das Feld enthält Validierungsfehler. Im Gegensatz zu den aufgelisteten Feldern enthält dieses Array genau die Fehler von FormControl , FormGroup oder FormArray , d. H. Fehler dieses Steuerelements und nicht alle verschachtelt. Beeinflusst ein gültiges / ungültiges Feld
    • Warnungen : ValidationEvent [] - Das Feld enthält Warnmeldungen. Im Gegensatz zu den aufgelisteten Feldern enthält dieses Array genau die Fehler von FormControl, FormGroup oder FormArray, d. H. Nachrichten dieses Steuerelements, aber nicht alle angehängt. Betrifft nicht das gültige / ungültige Feld
    • informationMessages : ValidationEvent [] - Das Feld enthält Informationsnachrichten. Im Gegensatz zu den aufgelisteten Feldern enthält dieses Array genau die Fehler von FormControl, FormGroup oder FormArray, d. H. Nachrichten dieses Steuerelements, aber nicht alle angehängt. Betrifft nicht das gültige / ungültige Feld
    • Erfolge : ValidationEvent - Das Feld enthält zusätzliche Gültigkeitsnachrichten. Im Gegensatz zu den aufgelisteten Feldern enthält dieses Array genau die Fehler von FormControl, FormGroup oder FormArray, d. H. Nachrichten dieses Steuerelements, aber nicht alle angehängt. Betrifft nicht das gültige / ungültige Feld
    • maxEventLevel () - Die maximale Stufe der derzeit im Feld enthaltenen Validierungsnachrichten.
    • Die Methode gibt einen der Aufzählungswerte in der nächsten Priorität zurück.
      1. ValidationEventTypes.Error;
      2. ValidationEventTypes.Warning;
      3. ValidationEventTypes.Info;
      4. ValidationEventTypes.Success;

    • serverErrors : string [] - Nach dem Senden einer Nachricht an den Server empfiehlt es sich, die Gültigkeit des Formulars auch auf dem Server zu überprüfen. Infolgedessen kann der Server Fehler der endgültigen Formularprüfung zurückgeben, und das Array serverErrors ist für diese Fehler vorgesehen. Eine wichtige Funktion von serverErrors ist die automatische Bereinigung von Validierungsnachrichten, wenn der Fokus von dem Feld verloren geht, dem Serverfehler zugewiesen wurden, und Serverfehler werden auch gelöscht, wenn das Feld geändert wurde.
    • onChange: Delegieren - Zusätzlich zur Standardreaktion des Mobx- Mechanismus können Sie delegieren und eine Rückruffunktion hinzufügen, die aufgerufen wird, wenn sich Daten ändern.
    • setDirty (dirty: boolean): void - Mit dieser Methode können Sie den Wert der ursprünglichen / schmutzigen Felder ändern
    • setTouched (berührt: boolean): void; - Mit dieser Methode kann der Wert der unberührten / berührten Felder geändert werden
    • dispose (): void; - Erforderlich, um das für die Seite verantwortliche Steuerelement in componentWillUnmount aufzurufen.


    Dies waren gemeinsame Felder für alle Steuerelemente, aber jedes Steuerelement verfügt auch über Felder, die für seinen Typ eindeutig sind.
    Formcontrol
    • value - enthält den aktuellen Wert des Feldes. Sie können diesem Feld auch einen neuen Wert zuweisen.


    FormGroup und FormArray enthalten
    • wait - Mit dieser Methode können Sie das Ende der Überprüfungen aller (Validierungen) einschließlich verschachtelter Daten erwarten
    • allControls () - Mit dieser Methode können Sie einen vollständigen Satz aller FormControl abrufen, einschließlich verschachtelter auf verschiedenen Ebenen. Das heißt, Tatsächlich erweitert es ein mehrstufiges FormGroup-Objekt, das auch FormGroup enthalten kann, zu einer großen Liste, die nur aus FormControl besteht. Diese Funktionalität ist erforderlich, wenn wir das erste ungültige Element finden und uns darauf konzentrieren möchten.
      In diesem Fall würde der Code folgendermaßen aussehen:
       await this.form.wait(); if (this.form.invalid) { this.form.setTouched(true); const firstError = this.form.allControls().find(c => c.invalid && !!c.element); if (!!firstError) { firstError.element.focus(); } } ... 



    Validierungen


    Zusätzlich zu den Steuerelementen, mit denen Sie mit Daten arbeiten können, benötigen wir natürlich selbst Validierungen. Das Paket @ quantumart / mobx-form-validation-kit enthält natürlich eine Reihe vordefinierter Validierungen und unterstützt auch die Erstellung benutzerdefinierter benutzerdefinierter Validierungen.
    Ein Beispiel für das Festlegen von Validierungen für FormControl für ein Altersfeld .
     new FormControl<number>( this.userInfo.age, [required(), minValue(18, "    18 .", ValidationEventTypes.Warning)], v => (this.userInfo.age = v) ) 

    Jede Validierung mit den neuesten Parametern dauert:
    • Nachricht - Eine Validierungsnachricht.
    • eventType - Nachrichtenebene. Es werden 4 Nachrichtenebenen unterstützt.
      1. Fehler - Fehler
      2. Warnung - Warnungen
      3. Info - Informationsmeldungen
      4. Erfolg - Nachrichten über die Gültigkeit. Sie können beispielsweise überprüfen, ob das Kennwort wirklich komplex ist.


    Das Paket enthält die folgenden Validierungen:
    • Erforderlich (... - Erforderliches Feld
    • notEmptyOrSpaces (... - Das Feld ist nicht leer und enthält nicht nur Leerzeichen. Tatsächlich erforderlich, unter Berücksichtigung des Leerzeichenverbots.
    • pattern (regExp: RegExp, ... - Der erste Parameter ist der reguläre Ausdruck, mit dem das Feld übereinstimmen soll. Ein Fehler wird generiert, wenn keine Musterübereinstimmung vorliegt.
    • invertPattern (regExp: RegExp, ... - Der erste Parameter ist der reguläre Ausdruck, mit dem das Feld nicht übereinstimmen soll. Bei einer Musterübereinstimmung wird ein Fehler generiert.
    • minLength (minlength: number, .... - Der erste Parameter ist die Mindestlänge des Textes einschließlich. Ein Fehler wird generiert, wenn die Länge kleiner als die übertragene ist.
    • maxLength (maxlength: number, .... - Der erste Parameter ist die maximale Länge des Textes einschließlich. Ein Fehler wird ausgegeben, wenn die Länge länger als die übertragene ist.
    • absoluteLength (Länge: Zahl, .... - Der erste Parameter ist die genaue Länge des Textes. Ein Fehler wird ausgegeben, wenn die Länge nicht mit der angegebenen übereinstimmt.
    • minValue (min: TEntity | (() => TEntity), ... - Diese Validierung ist nur für Zahlen und Daten vorgesehen. Ein Fehler wird gesetzt, wenn der Wert kleiner als der angegebene ist. Die Besonderheit der Validierung ist die Fähigkeit, nicht nur einen bestimmten Wert, sondern auch zu akzeptieren Funktion, dh wenn Sie den Wert in dieser Funktion aus dem Feld @observable des Objekts lesen, wird die Validierung selbst nicht nur neu gestartet, wenn das Feld geändert wird, an das die Validierung gehängt wird, sondern auch, wenn das „verknüpfte Feld“ geändert wird. erster Tag-Feld außer dem als Wert @observable gelesen wird.
    • maxValue (max: TEntity | (() => TEntity), ... - Diese Validierung ist nur für Zahlen und Daten vorgesehen. Ein Fehler wird gesetzt, wenn der Wert größer als der angegebene ist. Die Validierungsfunktion ist die Fähigkeit, nicht nur einen bestimmten Wert, sondern auch zu akzeptieren Funktion, dh wenn Sie den Wert in dieser Funktion aus dem Feld @observable des Objekts lesen, wird die Validierung selbst nicht nur neu gestartet, wenn das Feld geändert wird, an das die Validierung gehängt wird, sondern auch, wenn das „verknüpfte Feld“ geändert wird. erster außer-Tag-Feld, das als Wert @observable gelesen
    • notContainSpaces (... - Im Gegensatz zu notEmptyOrSpaces wird ein Fehler ausgegeben, wenn der Wert sogar mindestens ein Leerzeichen enthält.
    • compare (Ausdruck: (Wert: TEntity) => boolean (... - Wenn Sie Ihre eigene Validierungsfunktion schreiben, wird viel Code zum Kopieren und Einfügen generiert. Dieser Wrapper wurde entwickelt, um dieses Problem zu beheben. Diese Validierungsfunktion akzeptiert eine Funktion als ersten Parameter, der wiederum den aktuellen Wert übergibt Felder, mit denen Sie eine komplexe Prüfung durchführen können, z. B. den Hash für die TIN- oder Passnummer berechnen und dann true / false zurückgeben. Ein Fehler wird angezeigt, wenn die Prüfung false zurückgibt.
    • isEqual (Wert: Zeichenfolge ... - eine einfache Überprüfung der Zeichenfolgenübereinstimmung.

    Im Folgenden werden die Wrapper-Funktionen beschrieben, die den Ablauf der Validierungsauslöser steuern.
    Es ist zu beachten, dass der an FormControl , FormGroup , FormArray übergebene Validierungssatz in einem einzelnen Array gestartet wird und tatsächlich keine Ausführungssequenz aufweist. Als Ergebnis der Arbeit werden wir in den Feldern Fehler , Warnungen , Informationsnachrichten , Erfolgsarrays haben, die aus Fehlern, Warnungen bestehen, die zu einem einzigen Array zusammengefasst sind, usw.
    Oft möchte der Kunde nur einen Fehler sehen und nicht alle auf einmal. Darüber hinaus kann der TOR so ausgelegt werden, dass eine Prüfung erst durchgeführt wird, nachdem die vorherige bestanden wurde.
    Um dieses Problem zu lösen, wird wrapperSequentialCheck verwendet. Sein Aufruf und seine Anwendung unterscheiden sich nicht von dem üblichen Funktionsvalidator, aber am Eingang empfängt er ein Array von Validatoren, die nacheinander gestartet werden, d. H. Die nächste Validierung beginnt erst, nachdem die vorherige fehlerfrei bestanden wurde.
    Die zweite Wrapper-Funktion ist die Flusssteuerungsfunktion von Validierungen. wrapperActivateValidation als erster Parameter übernimmt eine Funktion, in die die Bedingungen für die Validierungsaktivierung geschrieben werden sollen. Im Gegensatz zur Aktivierungsfunktion, die an FormControl übergeben wird, ist diese Prüfung für eine komplexere Logik ausgelegt. Angenommen, wir haben einen gemeinsamen Builder für die gesamte FormGroup- Zahlungsform, und außerdem gibt es auf dem Server nur eine Methode, die einen gemeinsamen Satz von Feldern akzeptiert. Der Haken ist jedoch, dass wir dem Benutzer je nach "Zahlungsart" unterschiedliche Felder anzeigen, obwohl es sich um ein Formular handelt. Mit wrapperActivateValidation können Sie also eine Logik schreiben, in der je nach Zahlungsart verschiedene Prüfungen durchgeführt werden.
    Die Verwendung von Wrappern sieht genauso aus wie normale Funktionen.
     new FormControl( this.userInfo.megapole, [wrapperActivateValidation(() => this.info.A === 10, [ required(), pattern(/\^d{10}$/) ]), wrapperActivateValidation(() => this.info.A === 20, [ wrapperSequentialCheck([ notContainSpaces(), pattern(/\^d{20}$/) ]) ])], v => (this.userInfo.megapole = v) ) 

    Dieses Beispiel zeigt, dass die erforderlichen (), Muster- (/ \ ^ d {10} $ /) Prüfungen nur mit this.info.A === 10 und if this.info.A === 20 durchgeführt werden , dann funktionieren notContainSpaces (), Mustervalidierungen (/ \ ^ d {20} $ /) , außerdem funktionieren diese Validierungen im Gegensatz zum ersten Fall nacheinander.

    Natürlich wird der Moment kommen, in dem die Standardvalidierungen nicht mehr ausreichen.
    Dann müssen Sie Ihre eigenen asynchronen Funktionen schreiben. Glücklicherweise geschieht dies ohne besondere Schwierigkeiten.
    FormControl wurde ursprünglich durch asynchrone Validierungsfunktionen geschärft, die möglicherweise Daten an den Server senden möchten, und diese Antwort muss warten. Infolgedessen sind alle Validierungen asynchron.
     async function checkValueOnServer(control: FormControl): Promise<ValidationEvent[]> { if (control.value == null) { return []; } const result = await sendToServer(control.value); if (result.errorMessage) { return [ { message: result.errorMessage, type: ValidationEventTypes.Error, }, ]; } return []; } 

    Hier müssen Sie auf zwei Objekte achten.
    Zuerst kümmern wir uns immer um das Array. Das heißt, Auf Wunsch können Sie sogar mehrere Fehlermeldungen gleichzeitig zurückgeben.
    Der zweite Punkt ist das zurückgegebene Objekt und enthält die folgenden Felder.
    • Schlüssel ?: Zeichenfolge - Ein optionales Feld, mit dem Sie einen "Schlüssel" für eine bestimmte Validierung angeben können. Für alle Basisschlüssel ist der Schlüssel eindeutig und entspricht ihrem Namen. Möglicherweise möchten Sie den Schlüssel verwenden, um die Liste in Reaktion zu rendern, aber wie die Praxis gezeigt hat, ist dies eine schlechte Idee. In Zukunft werde ich im Beispiel zeigen, dass es besser ist, Nachrichten zu verwenden und die Taste überhaupt nicht zu berühren. In jedem Fall ist es wie in Angunar, aber sein Bedarf wurde tatsächlich auf 0 reduziert.
    • message : string - eine Validierungsnachricht. Pflichtfeld.
    • Typ : ValidationEventTypes - Nachrichtentyp.
      1. Fehler - Fehler
      2. Warnung - Warnungen
      3. Info - Informationsmeldungen
      4. Erfolg - Nachrichten über die Gültigkeit. Sie können beispielsweise überprüfen, ob das Kennwort wirklich komplex ist.

    • AdditionalData ?: any - zusätzliche Informationen, die bei Bedarf zusammen mit der Validierung übertragen werden können. Es kann sich um ein zusätzliches HTML-Markup oder einen bestimmten Stil handeln. Im Allgemeinen können Sie alles in jedes setzen.


    Erweiterungen


    Jede Magie basiert auf trivialen Dingen. In diesem Fall muss FormControl in einem bestimmten Eingabefeld verknüpft werden, damit die Fokuseinstellung funktioniert und Änderungen aus den Feldern abgerufen werden sollen .
    Weil FormControl schränkt den Entwickler nicht auf die Art der validierten Daten ein, da aufgrund seiner Vielseitigkeit ein gewisses Maß an Anwendbarkeit in Reaktionselementen geopfert werden musste.
    Gleichzeitig war es für die Eingabe und den Textbereich möglich, einfache Funktionen für die Datenbindung an einem Element zu erstellen. Für andere Komponenten muss der Prozessor nur minimale Anstrengungen unternehmen, um Daten zu ersetzen.

    Für die Eingabe sieht die Bindung des Elements an FormControl (Name) folgendermaßen aus.
    <input type = "text" {... InputFormControl.bindActions (controls.name)} />
    Für den Textbereich ist die Bindung wie folgt
    <textarea {... TextAreaFormControl.bindActions (controls.name)} />

    InputFormControl.bindActions und TextAreaFormControl.bindActions akzeptieren zwei Parameter:
    • formControl : FormControl - eigentlich FormControl, das zum Binden verwendet wird. Erforderlich.
    • Ereignisse ? - Ein optionaler Parameter mit einer Liste von Funktionen, die aufgerufen werden können, wenn Sie sie anpassen müssen. , bindActions - Element, , element FormControl -, . . event. .
      • ref
      • onChange
      • onBlur
      • onFocus


    , FormControl - .
     this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ) }); 

    this.userInfo.name , FormControl . FormControl.for
     this.form = new FormGroup<IUserInfo>({ name: FormControl.for(this.userInfo, 'name', []) }); 

    , name name . , TypeScript, name , . userInfo — .

    — . :) :)


    React TypeScript mobx.
    .
    npm install @quantumart/mobx-form-validation-kit

    ,
    :

    ,
    npm init –y
    npm install --save-dev webpack webpack-cli
    npm install --save react react-dom
    npm install --save-dev @types/react @types/react-dom
    npm install --save-dev typescript ts-loader source-map-loader


    tsconfig.json
     { "compilerOptions": { "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, "module": "commonjs", "target": "es6", "jsx": "react", "experimentalDecorators": true, "emitDecoratorMetadata": true } } 


    • src\components\Hello.tsx
    • src\index.tsx
    • index.html
    • src\assets\global.scss


    src\components\ Hello.tsx
     import * as React from "react"; export class Hello extends React.Component { render() { return ( <h1> Hello from TypeScript and React! </h1> ); } } 

    src\ index.tsx
     import * as React from "react"; import * as ReactDOM from "react-dom"; import { Hello } from "./components/Hello"; ReactDOM.render( <Hello />, document.getElementById("example") ); 

    index.html
     <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> </head> <body> <div id="example"></div> <!-- Dependencies --> <script src="./node_modules/react/umd/react.development.js"></script> <script src="./node_modules/react-dom/umd/react-dom.development.js"></script> <!-- Main --> <script src="./dist/main.js"></script> </body> </html> src\assets\global.scss .row { display: inline; } 



    webpack-dev-server
    npm install --save-dev webpack-dev-server
    npm install --save-dev awesome-typescript-loader
    npm install --save-dev html-webpack-plugin

    webpack.config.js
     const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.tsx', resolve: { extensions: ['.ts', '.tsx', '.js'] }, output: { path: path.join(__dirname, '/dist'), filename: 'bundle.min.js' }, module: { rules: [ { test: /\.tsx?$/, loader: 'awesome-typescript-loader' }, { test: /\.(scss|css)?$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { importLoaders: 1, }, }, { loader: 'sass-loader', options: { sourceMap: true } }, ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: './index.html' }) ] } 

    , mobx React.
     "mobx": "4", "mobx-react": "^6.1.1", 

    C IE10 mobx, 4 , package.json.

      "style-loader": "^0.23.1", "css-loader": "^3.1.0", "node-sass": "^4.12.0", "sass-loader": "^7.1.0" 


    npm install

    , .
    npm install @quantumart/mobx-form-validation-kit



    package.json
     { "name": "ttt", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack-dev-server --mode development --open", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "MIT", "devDependencies": { "@types/react": "^16.9.5", "@types/react-dom": "^16.9.1", "awesome-typescript-loader": "^5.2.1", "html-webpack-plugin": "^3.2.0", "source-map-loader": "^0.2.4", "ts-loader": "^6.2.0", "typescript": "^3.6.3", "webpack": "^4.41.0", "webpack-cli": "^3.3.9" }, "dependencies": { "@quantumart/mobx-form-validation-kit": "^1.0.8", "mobx": "4", "mobx-react": "^6.1.1", "react": "^16.10.2", "react-dom": "^16.10.2", "webpack-dev-server": "^3.8.2", "style-loader": "^0.23.1", "css-loader": "^3.1.0", "node-sass": "^4.12.0", "sass-loader": "^7.1.0" } } 


    npm run start


    Hello from TypeScript and React!


    Hello . RegistrationStore RegistrationStore.ts
    src\RegistrationStore.ts
     import { observable } from "mobx"; export class RegistrationStore { @observable public userInfo = { name: "" }; } export const registrationStore = new RegistrationStore(); 

    Hello.ts, .
     import * as React from "react"; import { observer } from "mobx-react"; import { registrationStore } from "../RegistrationStore"; @observer export class Hello extends React.Component { private changeName = (event: React.ChangeEvent<HTMLInputElement>) => { registrationStore.userInfo.name = event.target.value; }; render() { return ( <React.Fragment> <h1>, {registrationStore.userInfo.name}</h1> <div className="row"> <span>:</span> <input type="text" value={registrationStore.userInfo.name} onChange={this.changeName} /> </div> </React.Fragment> ); } } 

    , Store Mobx. input.
    , . , . «» . , .

    @quantumart/mobx-form-validation-kit

    - .
    stc/ErrorWraper.tsx
     import * as React from "react"; import { observer } from "mobx-react"; import { FormControl } from "@quantumart/mobx-form-validation-kit"; interface Props { formControl: FormControl; } @observer export class ErrorWraper extends React.Component<Props> { render() { return ( <div> {this.props.children} {this.props.formControl.errors.map(error => ( <span key={error.message} className="error"> {error.message} </span> ))} </div> ); } } 

    , -, .

    Hello.tsx .
    - — changeName. {...InputFormControl.bindActions(controls.name)} . .
    - – input, input , , , .
    - – form store , , , componentWillUnmount registrationStore.form.dispose() . mobx FromControl .
     import * as React from "react"; import { observer } from "mobx-react"; import { registrationStore } from "../RegistrationStore"; import { ErrorWraper } from "../ErrorWraper"; import { InputFormControl } from "@quantumart/mobx-form-validation-kit"; @observer export class Hello extends React.Component { constructor(props: any) { super(props); registrationStore.initForm(); } componentWillUnmount() { registrationStore.form.dispose(); } render() { const controls = registrationStore.form.controls; return ( <React.Fragment> <h1>, {registrationStore.userInfo.name}</h1> <div className="row"> <span>:</span> <ErrorWraper formControl={controls.name}> <input type="text" {...InputFormControl.bindActions(controls.name)} /> </ErrorWraper> </div> </React.Fragment> ); } } 

    RegistrationStore.ts.
    .
    ( ) userInfo, form. - userInfo.
     import { observable } from "mobx"; import { FormControl, FormGroup, AbstractControls } from "@quantumart/mobx-form-validation-kit"; interface IUserInfo extends AbstractControls { name: FormControl; } export class RegistrationStore { @observable public userInfo = { name: "" }; @observable public form: FormGroup<IUserInfo>; public initForm(): void { this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ) }); } } export const registrationStore = new RegistrationStore(); 

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


All Articles