FrageAntwort – Referenz

Alles auf einen Blick. Wie die Teile zusammenspielen, zeigen die Beispiele in der Navigation.

Das EditorTemplate rendert eine Frage samt Antwortmöglichkeit und schickt sie einzeln und asynchron an den Server. Es bringt Formular, Absenden-Schaltfläche und Ajax-Ablauf selbst mit.

Einbindung

@for (var idx = 0; idx < Model.FrageAntwortListe.Count; idx++)
{
    @Html.EditorFor(x => x.FrageAntwortListe[idx], UiEditor.Kompetenzen.FrageAnwort)
    <hr />
}

Den Templatenamen liefert die Konstante UiEditor.Kompetenzen.FrageAnwort aus FMH.Komponente.Kompetenzen. Ihr Wert schreibt sich ohne das zweite «t», wie die Datei FrageAnwort.cshtml. Angegeben werden muss er, weil FrageAntwortViewModel keinen [UIHint] trägt.

Die Modellklassen

BeurteilungViewModel – die Klammer um die Fragen:

Eigenschaft Bedeutung
FrageAntwortListe Die Fragen. Über sie läuft die Schleife in der View.
FachDelegierterFmhId, FachDelegierterName Der Fachdelegierte. Vom Template nicht gerendert – für die eigene Seite.
FachfremdDelegierterFmhId, FachfremdDelegierterName Dasselbe für den fachfremden Delegierten.

FrageAntwortViewModel – eine Frage:

Eigenschaft Bedeutung
Id Schlüssel der Frage. Geht als verstecktes Feld mit und ist die Zuordnung im Endpunkt.
Reihenfolge Wird der Frage vorangestellt («1. …»). Sortiert wird nicht automatisch.
Frage Der Fragetext. Geht ebenfalls als verstecktes Feld mit.
AktuelleRolle Steuert die gesamte Darstellung, siehe unten.
AntwortFachDelegierter Die Antwort des Fachdelegierten (AntwortTyp).
AntwortTextFachDelegierter Die Begründung dazu, mehrzeilig.
AntwortFachFremdDelegierter Die fachfremde Antwort.
AntwortTextFachFremdDelegierter Die Begründung dazu.
AntwortSelection Die angebotenen Antworten als SelectListItem. Vorbelegt mit «Ja» und «Nein».
HatFachFremdDelegierterBeantwortet Ob eine fachfremde Antwort vorliegt – nur dann zeigt das Template sie dem Fachdelegierten.
IstUneinig Ob beide Rollen geantwortet haben und die Antworten voneinander abweichen.
GibAntwortTypText(typ) Der Anzeigetext zu einem AntwortTyp aus AntwortSelection.

Die Aufzählungen

Rolle – wer die Frage gerade vor sich hat:

Wert Bearbeitet Angezeigt Speichern-Schaltfläche
FachDelegierter AntwortFachDelegierter die fachfremde Antwort, sofern vorhanden ja
FachFremdDelegierter AntwortFachFremdDelegierter die Antwort des Fachdelegierten ja
Abgeschlossen – beide Antworten nein
None – beide Antworten ja

AntwortTyp – die Antwort selbst: Unbeantwortet (0), Ja (1), JaMitVorbehalt (2), Nein (3). Angeboten werden über AntwortSelection zunächst nur Ja und Nein; JaMitVorbehalt und Unbeantwortet erscheinen erst, wenn einer der beiden Werte bereits gesetzt ist. Alte Beurteilungen bleiben so lesbar, ohne dass die Auswahl für neue Fälle wächst.

AntwortStatus – der Gesamtstand für die Rückmeldung: Unbeantwortet (0), TeilweiseBeantwortet (1), KomplettBeantwortet (2).

Die Endpunkte

Das Template baut die Adresse seines Formulars ohne Controllernamen. Es postet damit an den Controller, der die Seite gerendert hat, dort müssen die Actions liegen:

Rolle Action
FachDelegierter AntwortFD
FachFremdDelegierter und alles Übrige AntwortFFD

Beide nehmen ein flaches FrageAntwortViewModel entgegen:

[HttpPost]
public IActionResult AntwortFD(FrageAntwortViewModel modell)

Das ist kein Versehen: Das Skript der Komponente kürzt beim Absenden jeden Feldnamen auf sein letztes Segment, aus FrageAntwortListe[0].Id wird Id. Ein Parameter, der die Liste erwartet, bliebe deshalb leer.

Die Antwort des Endpunkts

AntwortResultat:

Eigenschaft Wirkung
Nachricht Text der Snackbar, die die Komponente einblendet.
Status AntwortStatus; reine Information für den Browser, die Komponente wertet ihn nicht aus.
IconTyp Material-Design-Code des Snackbar-Symbols. Vorgabe check_circle; über IconTypeDictionary.Get(IconType.…) aus einem IconType zu gewinnen.
Metadaten Frei belegbares Wörterbuch. Geht unverändert an das Browser-Ereignis.

Für den Fehlerfall den Statuscode auf 400 setzen und ein AntwortResultat mit gefüllter Nachricht zurückgeben, das Skript zeigt sie als Fehler-Snackbar und markiert die Schaltfläche.

Das Browser-Ereignis

Nach jeder erfolgreich gespeicherten Antwort löst die Komponente am window ein CustomEvent namens FrageAntwortStatus aus. Sein detail ist das AntwortResultat als JSON-Objekt, also Nachricht, Status, IconTyp und Metadaten in Pascal Case.

window.addEventListener('FrageAntwortStatus', function (ereignis) {
    var resultat = ereignis.detail;
});

Das Ereignis wird nur ausgelöst, wenn die Antwort ein Objekt ist. Antwortet der Endpunkt mit einer blossen Zeichenkette, erscheint die Snackbar, aber kein Ereignis.

Was das Template selbst erledigt

  • Ein Formular je Frage. Die Seite darf sie nicht in ein weiteres Formular einschliessen, verschachtelte Formulare erlaubt HTML nicht.
  • Absenden per Ajax, inklusive Sperren und Freigeben der Schaltfläche: Sie startet gesperrt und wird erst durch eine Änderung an Auswahl oder Text wieder aktiv.
  • Snackbar mit der Rückmeldung des Endpunkts.

Gestaltung

Die Klassen (frage-antwort--container, frage-antwort--antwort-fd-…) stecken im SCSS-Bundle dieses Pakets, der Ajax-Ablauf in jquery-fmh-sitesetup.js der Basis. Fehlt die Einrichtung dafür, bleibt ein ungestaltetes Formular, das die Seite neu lädt; was dazugehört, steht unter Vorbedingungen.