Sie sind hier: Weblog

Komplexe Formulare mit ng-form in AngularJS

Foto ,
28.01.2015 23:28:00

Wiederholungen in Formularen führen zu nicht ganz offensichtlichen Problemen bei der Validierung. Das nachfolgende Listing demonstriert dies. Es zeigt ein Formular mit einer Tabelle, welche Airlines darstellt. Jede Zeile steht für eine Airline und jede Zelle enthält ein Eingabefeld für eine Eigenschaft der jeweiligen Airline. Das Feld, welches an die Eigenschaft name gebunden ist, hat der Entwickler mit dem Attribut required als Pflichtfeld gekennzeichnet. Im Fall einer erfolglosen Validierung erhält die umschließende Zelle die CSS-Klasse has-error, welche dazu führt, dass das Eingabefeld einen roten Rahmen erhält.

    <form name="form1">
        <table>

            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Allianz</th>
            </tr>

            <tr ng-repeat="a in vm.airlines">
                <td><input ng-model="a.id" name="id" class="form-control"></td>
                <td class="form-group" ng-class="{has-error: form1.name.$invalid}">
                    <input ng-model="a.name" name="name" required class="form-control">
                </td>
                <td><input ng-model="a.allianz" name="allianz" class="form-control"></td>
            </tr>

        </table>
    </form>

Auf dem ersten Blick funktioniert dieses Beispiel wie gewünscht. Bei näherer Betrachtung fällt hingegen auf, dass die Anwendung nur Validierungsfehler für die letzte Zeile anzeigt. Ein solcher Validierungsfehler führt jedoch dazu, dass AngularJS sämtliche Felder mit einem roten Rahmen darstellt. Dies liegt daran, dass die Direktive ng-repeat pro Wiederholung eine Eigenschaft form1.name einrichtet. Existiert diese Eigenschaft bereits, überschreibt ng-repeat sie. Aus diesem Grund ist nur die letzte Iteration für die Validierung ausschlaggebend. Dieses Problem kann der Entwickler durch Einsatz der Direktive ng-form umgehen. Diese Direktive ist nicht als Ersatz für das Element form gedacht, sondern kommt zum Unterteilen eines Formulars in mehrere Abschnitte zum Einsatz. Pro Abschnitt richtet AngularJS einen eigenen untergeordneten Scope mit einem Form-Controller ein. Somit existiert pro Abschnitt ein eigener Form-Controller und der Entwickler kann jeden Abschnitt für sich validieren.

Das nächste Listing definiert zur Veranschaulichung für jede mit ng-repeat durchgeführte Wiederholung einen Abschnitt, den AngularJS auch separat validiert, ein. An ng-form übergibt das betrachtete Beispiel den Namen des jeweiligen Abschnitts. Dieser lautet auf airlineForm. Auf den für die Validierung zu nutzenden Controller greift es in weiterer Folge unter Angabe dieses Namens zu (airlineForm.name).

<form name="form2">

    <table>

        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Allianz</th>
        </tr>

        <tr ng-repeat="a in vm.airlines" ng-form="airlineForm">
            <td><input ng-model="a.id" name="id" class="form-control"></td>
            <td class="form-group" ng-class="{has-error: airlineForm.name.$invalid}">
                <input ng-model="a.name" name="name" required class="form-control">
            </td>
            <td><input ng-model="a.allianz" name="allianz" class="form-control"></td>
        </tr>

    </table>


</form>

Möchte der Entwickler nun herausfinden, ob in einem der durch das Zusammenspiel von ng-form und ng-repeat generierten Abschnitten ein Validierungsfehler vorliegt, kann er für diese Abschnitte einen gemeinsamen übergeordneten Abschnitt definieren. Das Beispiel im nachfolgenden Listing nennt diesen Abschnitt, welchen es auf der Ebene der Tabelle einrichtet, outerForm. Im unteren Bereich des Beispiels prüft das Beispiel unter Verwendung von outerForm.$invalid, ob innerhalb dieses Abschnitts, welcher die Wiederholgruppe beinhaltet, ein Validierungsfehler vorkommt.

<form name="form2">

    <table ng-form="outerForm">

        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Allianz</th>
        </tr>

        <tr ng-repeat="a in vm.airlines" ng-form="airlineForm">
            <td><input ng-model="a.id" name="id" class="form-control"></td>
            <td class="form-group" ng-class="{has-error: airlineForm.name.$invalid}">
                <input ng-model="a.name" name="name" required class="form-control">
            </td>
            <td><input ng-model="a.allianz" name="allianz" class="form-control"></td>
        </tr>

    </table>

    <div ng-show="outerForm.$invalid" style="color: red">
        Tabelle mit Airlines weist Fehler auf!
    </div>
</form>