HTML Input mit Bootstrap Edit Template umranden per Angular

Wer umfangreiche Formulare für den Webbrowser erstellt, wird sich bald wünschen weniger Code tippen zu müssen. Ein HTML Input wird mit Attributen versehen, einer Fehlermeldung, einem Label und einigen Klassen.

   1:  <div class="form-group">
   2:      <label class="col-xs-2 control-label" for="text1">Label</label>
   3:      <div class="col-xs-10">
   4:          <input type="text" id="text1" class="form-control" />
   5:          <span class="help-block">Fehlermeldung</span>
   6:      </div>
   7:  </div>

 

Tippen möchte ich aber nur etwas in der Form

 
   1:  <input type="text" id="text1" label="Name:" 
fehlermeldung="bitte füllen" required />

 

Der HTML Code außen rum soll sich automatisch daraus generieren. Ein Anwendungsfall für eine Angular.js Direktive. Das folgende Beispiel ist also der Prototyp zum Prototyp einer zukünftigen SPA Anwendung.

image

Dazu wird eine Angular App im HTML Code deklariert, samt zugehörigem Controller.

   1:  <body ng-app="App">
   2:      <div ng-controller="ExampleController">
   3:          <div formulargruppe data-label="Firmenname" 
data-fehlermeldung="Da muss was rein">
   4:              <input type="text" required name="feld1" 
ng-model="Customer.CompanyName"
   5:                      placeholder="Firma"/>
   6:          </div>
   7:      </div>

Wer sehr korrekt sein will, setzt ein data- vor die Eigenschaftsattribute wie fehlermeldung oder label. Es geht auch ohne. In Zeile 3 wird die Direktive Formulargruppe eingebunden. Auf keinen Fall in Direktiven einen Bindestrich im Namen verwenden, da dieser intern per Konvention entfernt wird.

Direktiven würde ich mit Behaviours aus XAML vergleichen. Damit lassen sich einem UI Element neue Eigenschaften, Visualisierung und Events zuordnen.

Das Ziel ist um jedes bestehende INPUT-Element eine Bootstrap-passende Formatierung zu legen und die Attribute aus dem INPUT weiter zu verwenden.

Die Direktive formulargruppe liefert mit einer Art Konstruktormethode Daten zurück. Mit restrict A ist die Nutzung nur als Attribut zulässig. Transclude ersetzt das bestehende DIV (Zeile 3 obiges Listing) mit dem Inhalt aus dem Template (Zeile 10 folgendes Listing). Das Input Element wandert dann an die Stelle ng-transclude, aus dem HTML Template.

Der besondere Gag ist die Datenbindung an einen lokalen Scope. Nicht zu verwechseln mit dem $Scope aus dem Viewmodel. Die Attribute label und Fehlermeldung und deren Werte aus der HTML-Seite (Zeile 3), werden durch de Zuweisung scrope: zu Eigenschaften. Diese können dann in Zeile 11 und 14 im Template frei gebunden werden. Das erinnert ein wenig an die ContentTemplates aus XAML und die Bindinglogik.

   1:     <script src="Scripts/angular.js"></script>
   2:      <script>
   3:          angular.module('App', [])
   4:           .directive('formulargruppe', function () {
   5:               return {
   6:                   restrict: 'A',
   7:                   transclude: true,
   8:                   replace: true,
   9:                   scope: { label: '@', fehlermeldung: '@' },
  10:                   template: '<div class="form-group">' +
  11:           '<label class="col-xs-2 control-label" for="text1">
{{label}}</label>' +
  12:           '<div class="col-xs-10">' +
  13:           ' <div ng-transclude ></div>' +
  14:           ' <span class="help-block">{{fehlermeldung}}</span> </div></div>',
  15:                              }
  16:   
  17:               }
  18:           })
  19:          .controller('ExampleController', ['$scope', function ($scope) {
  20:          ...
  21:          }]);

 

Das bleibt ein nicht unerhebliches Problem. Bootstrap braucht im Input-Element, für die runden Ecken, eine CSS Klasse form-control. Man könnte diese Klasse im Ausgangs-HTML-Code definieren, schöner wäre aber ein Automatismus über die Direktive. Allerdings ist im HTML Template kein INPUT vorhanden.

Genau für diesen Zweck, nämlich per Logik, das Template zu manipulieren, wurde die Link-Eigenschaft geschaffen. Im folgenden JavaScript Code wird das erste und einzige INPUT-Element selektiert. Dieses muss in einen Angular-Elementtyp umgewandelt werden, um die Jquery-Methode addClass nutzen zu können.

   1:  link: function (scope, element, attrs {
   2:          var input1 = element[0].querySelector("input");
   3:          angular.element(input1).addClass('form-control');

 

Letztendlich noch ein Blick auf den erzeugten HTML Code. Es fällt auf, dass ein zusätziches DIV um das INPUT Element gerendert wird. Erkennbar am Attribut ng-transclude. In meinen Tests mit allen möglichen Varianten Direktive als Element oder Attribut wurde auch ein  <span class="ng-scope">hannes</span> eingefügt.

   1:  <div ng-transclude="">
   2:            
   3:    <input name="feld1" class="ng-scope ng-pristine ng-untouched 
   4:  form-control ng-invalid ng-invalid-required" required=""
   5:   type="text" placeholder="Firma" 
   6:  ng-model="Customer.CompanyName">
   7:   
   8:  </div>

Dies ist nur der Anfang für ein vollständiges Angular-Formular mit Validierung und Bootstrap Design. Gezeigt wurde der Einsatz einer Direktive mit HTML Template und Binding. Mehr lernen Sie in meinem ppedv Angular Workshop auf der #ADCX.

Kommentare sind geschlossen