Kolumne: .NETversum - Tipps und Tricks rund um .NET und Visual Studio

AngularJS: Verschachtelte Formulare validieren
Kommentare

Dr. Holger Schwichtenberg (MVP) und FH-Prof. Manfred Steyer teilen in der Kolumne “.NETversum” ihr Expertenwissen rund um .NET-Tools und WPF mit.

Wiederholungen in Formularen führen zu nicht ganz offensichtlichen Problemen bei der Validierung mit AngularJS. Listing 1 zeigt ein Formular mit einer Tabelle, die 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, das 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, die dazu führt, dass das Eingabefeld einen roten Rahmen erhält.

Verschachtelte Formulare mit AngularJS validieren

Listing 1: Problematisches Mark-up mit wiederholenden Formular-Elementen
<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 den 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.

Schnell und überall: Datenzugriff mit Entity Framework Core 2.0

Dr. Holger Schwichtenberg (www.IT-Visions.de/5Minds IT-Solutions)

C# 7.0 – Neues im Detail

Christian Nagel (CN innovation)

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.

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

Listing 2: Wiederholgruppen in Formular mit „ng-form“
<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 Abschnitte ein Validierungsfehler vorliegt, kann er für diese Abschnitte einen gemeinsamen übergeordneten Abschnitt definieren. Das Beispiel in Listing 3 nennt diesen Abschnitt, den es auf der Ebene der Tabelle einrichtet, outerForm. Im unteren Bereich prüft das Beispiel unter Verwendung von outerForm.$invalid, ob innerhalb dieses Abschnitts, der die Wiederholgruppe beinhaltet, ein Validierungsfehler vorkommt.

Listing 3: Validierungsinformationen für mehrere Formularabschnitte ermitteln
<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>

Laufwerksname ändern

Eine Software kann einen Laufwerksnamen eines lokalen oder entfernten Laufwerks mithilfe der WMI-Klasse Win32_LogicalDisk ändern. Dort ist die Eigenschaft VolumeName beschreibbar. Wichtig ist, dass die Änderung erst gespeichert wird, wenn man die Methode Put() aufruft. In Listing 4 erfolgt ein Neuladen des Objekts mit Get() nach dem Put(), um sicher zu prüfen, dass die Änderung im System persistiert wurde. Zu beachten ist, dass für die Änderung des Laufwerksnamens des Laufwerks C administrative Rechte notwendig sind. Alle anderen beschreibbaren Laufwerksnamen können auch normale Benutzer ändern. Der nachstehenden Methode SetVolumeName() kann man optional einen Computernamen übergeben. Sonst wird mit „.“ der lokale Computer angesprochen.

Listing 4: Neuladen des Objekts
/// <summary>
///  Ändern des Laufwerksnamens
/// </summary>
/// <example>
///  SetVolumneName("E:","MeinUSBStick", "MeinPC");
/// </example>
public void SetVolumeName(string computer, string driveLetter, string newName)
{
  // WMI-Pfad zusammensetzen
  string path = @"\\" + computer + @"\root\cimv2:Win32_LogicalDisk.DeviceID='" + driveLetter + "'";
 
  // Zugriff auf WMI-Objekt
  ManagementObject drive = new ManagementObject(path);
 
  // Ausgabe des bisherigen Namens
  Console.WriteLine("Volume name before:" + drive["VolumeName"].ToString());
 
  // Neuer Name festlegen
  drive["VolumeName"] = newName;
 
  // Speichern
  drive.Put(); 
 
  // Nun alle Eigenschaften laden
  drive.Get(); 
 
  // Kontrollausgabe
  Console.WriteLine("Volume name after:" + drive["VolumeName"].ToString());
}

Aufmacherbild: Man Filing Out An Application On Wooden Table via Shutterstock.com / Urheberrecht: Rawpixel

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -