Textbox (DisplayTemplate)

Konfigurationen des TextboxDisplay-DisplayTemplates. Es stellt einen Wert schreibgeschützt als Schlüssel/Wert-Paar dar (Einbindung über @Html.DisplayFor(...) mit [UIHint(UiDisplay.Basis.Textbox)]). Jedes Beispiel zeigt in Tabs die cshtml und das ViewModel; darunter die Darstellung mit der aufklappbaren Rubrik Anleitung.

Textbox (Grundfall)

Ein Textwert schreibgeschützt als Schlüssel/Wert-Paar, die Beschriftung über dem Wert. Konfiguriert wird allein über die Data Annotations.

@model DisplayTextboxBeispielViewModel

@Html.DisplayFor(m => m.Vorname)
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;

namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
    public class DisplayTextboxBeispielViewModel
    {
        [Display(Name = "Vorname")]
        [UIHint(UiDisplay.Basis.Textbox)]
        [DisplayAlignment(Alignment.Vertical)]
        public string Vorname { get; set; } = "Hans Muster";
    }
}

Darstellung

Vorname
Hans Muster

Das TextboxDisplay-DisplayTemplate stellt einen Textwert schreibgeschützt als Schlüssel/Wert-Paar dar, Beschriftung und Wert, ohne Eingabefeld. Die Verwendung ist analog zu den EditorTemplates: [UIHint] am Modell, Html.DisplayFor(...) in der View.

[Display(Name = "Vorname")]
[UIHint(UiDisplay.Basis.Textbox)]
public string Vorname { get; set; } = "Hans Muster";
@Html.DisplayFor(m => m.Vorname)

Standardmässig steht die Beschriftung über dem Wert (Alignment.Vertical).

Weitere Konfigurationen

Konfiguration Wirkung
[Display(Name = "…")] Beschriftung des Schlüssel/Wert-Paars
[DisplayAlignment(Alignment.Horizontal)] Beschriftung und Wert nebeneinander, siehe Beispiel «Textbox horizontal»
[HelpText(Name = "…")] Info-Icon mit Tooltip neben der Beschriftung, siehe Beispiel «Textbox mit Hilfetext»
[AdditionalMetadata(UiMetadata.Basis.Bold, true)] Stellt den Wert fett dar. Voraussetzung: der AdditionalMetadataProvider, den AddFmhWidgetOptions() registriert
[AdditionalMetadata(UiMetadata.Basis.ValueColorClass, "…")] Hinterlegt den Wert grau (bg-light); das Template prüft nur, ob der Schlüssel gesetzt ist, gleiche Provider-Voraussetzung

Textbox horizontal

Beschriftung und Wert nebeneinander über [DisplayAlignment(Alignment.Horizontal)]; das zweite Feld zeigt, was bei einer zu langen Beschriftung passiert.

@model DisplayTextboxHorizontalBeispielViewModel

@* Zwei Felder untereinander, beide horizontal ausgerichtet: So wird sichtbar, dass die
   Schlüsselspalte gleich breit bleibt und eine zu lange Beschriftung gekürzt wird. *@
@Html.DisplayFor(m => m.Vorname)

@Html.DisplayFor(m => m.ZweiterVorname)
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;

namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
    /// <summary>
    /// Zwei Felder nebeneinander gestellt; die zweite Beschriftung ist bewusst zu lang für die
    /// Schlüsselspalte und zeigt die Kürzung mit «…».
    /// </summary>
    public class DisplayTextboxHorizontalBeispielViewModel
    {
        [Display(Name = "Vorname")]
        [UIHint(UiDisplay.Basis.Textbox)]
        [DisplayAlignment(Alignment.Horizontal)]
        public string Vorname { get; set; } = "Hans Muster";

        [Display(Name = "Zweiter Vorname gemäss amtlichem Ausweis")]
        [UIHint(UiDisplay.Basis.Textbox)]
        [DisplayAlignment(Alignment.Horizontal)]
        public string ZweiterVorname { get; set; } = "Peter";
    }
}

Darstellung

Vorname
Hans Muster
Zweiter Vorname gemäss amtlichem Ausweis
Peter

Über [DisplayAlignment(Alignment.Horizontal)] stehen Beschriftung und Wert nebeneinander statt untereinander; der Container bekommt dafür die Klasse siwf-display-horizontal.

[Display(Name = "Vorname")]
[UIHint(UiDisplay.Basis.Textbox)]
[DisplayAlignment(Alignment.Horizontal)]
public string Vorname { get; set; }

Das Attribut wird direkt aus den Model-Metadaten gelesen (ToDisplayAlignment()), ein zusätzlicher Provider ist dafür nicht nötig. Ohne Angabe gilt Alignment.Vertical.

Was bei langen Beschriftungen passiert. In der horizontalen Darstellung ist die Schlüsselspalte eine Flex-Spalte mit min-width: 100px und white-space: nowrap; eine zu lange Beschriftung wird abgeschnitten und mit … beendet, statt die Zeile zu sprengen. Den vollen Text zeigt ein Tooltip: Die Schlüsselspalte trägt dafür die Klasse fmh-grid-ellipsis, die initGridEllipsisTooltip() aus dem Skript-Bundle der Basis auswertet. Das zweite Feld im Beispiel ist genau dafür da. Die Kürzung selbst kommt aus dem SCSS der Basis, die …-Regel aus dem SCSS der Tabelle, in einer Anwendung ohne dieses Paket bleibt der Text also schlicht abgeschnitten.

Dieselbe Ausrichtung kennen auch TextareaDisplay, EmailDisplay und TelefonDisplay, jeweils mit einem eigenen Beispiel auf deren Demoseite. AuswahlboxDisplay und CheckInfoDisplay werten das Attribut nicht aus.

Textbox mit Aktions-Icon

Ein Icon zum Kopieren in die Zwischenablage, das der IconBuilder an das Wert-Element hängt. Der Weg ist von den DisplayTemplates unabhängig.

@using databinding.WebSecurity.HtmlSanitizer.AspNetCore.Extensions
@using FMH.Komponente.Infrastruktur.Schnittstellen.Ui
@model DisplayTextboxKopierenBeispielViewModel

@Html.DisplayFor(m => m.Name)

@* AppendToElement hängt das Icon an das Wert-Element der Anzeige; TextboxDisplay setzt dort die
   Id des Eigenschaftsnamens, hier also "#Name". Ohne diese Angabe stünde das Icon an genau
   dieser Stelle im Markup, also unterhalb der Anzeige. *@
@Html.Fmh(
    Fmh.Icon(IconType.ContentCopy)
        .Tooltip("Text in die Zwischenablage kopieren.")
        .Id("icoNameKopieren")
        .Attributes(new { style = "cursor:pointer;" })
        .AppendToElement("#Name")
        .WithClientScript(
            @<script>
        // Delegation an das Dokument: Das Icon fügt der Builder selbst per Skript ein, ein
        // direkt gebundener Handler wäre auf die Reihenfolge der beiden Skripte angewiesen.
        document.addEventListener("click", async function (ereignis) {
            const icon = ereignis.target.closest("#icoNameKopieren");

            if (icon === null) {
                return;
            }

            // SanitizedRaw statt roher Ausgabe: Sonst landen Umlaute als HTML-Entitäten
            // ("M&#xFC;ller") in der Zwischenablage.
            await navigator.clipboard.writeText("@Html.SanitizedRaw(Html.ValueFor(m => m.Name))");

            icon.textContent = "check";
            setTimeout(function () { icon.textContent = "content_copy"; }, 5000);
        });
    </script>))
using System.ComponentModel.DataAnnotations;

namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
    /// <summary>
    /// Textbox-Anzeige, an die ein Aktions-Icon gehängt wird.
    /// </summary>
    /// <remarks>
    /// Der Wert trägt bewusst Umlaute und einen Bindestrich: An ihm zeigt sich, warum der Text im
    /// Skript über SanitizedRaw ausgegeben wird und nicht roh.
    /// </remarks>
    public class DisplayTextboxKopierenBeispielViewModel
    {
        [Display(Name = "Name")]
        [UIHint(UiDisplay.Basis.Textbox)]
        public string Name { get; set; } = "Hans Müller-Schöni";
    }
}

Darstellung

Name
Hans Müller-Schöni

Neben der Anzeige lässt sich eine Aktion setzen, hier ein Icon, das den Wert in die Zwischenablage kopiert. Der Weg dahin gehört zum IconBuilder und ist von den DisplayTemplates unabhängig; am ViewModel ändert sich nichts.

@Html.Fmh(Fmh.Icon(IconType.ContentCopy)
    .Tooltip("Text in die Zwischenablage kopieren.")
    .Id("icoNameKopieren")
    .Attributes(new { style = "cursor:pointer;" })
    .AppendToElement("#Name")
    .WithClientScript(@<script> … </script>))
Baustein Wirkung
.AppendToElement("#Name") Das Icon wird nicht an dieser Stelle im Markup ausgegeben, sondern per Skript an das Element mit diesem Selektor gehängt. TextboxDisplay gibt dem Wert-Element die Id des Eigenschaftsnamens, hier also #Name.
.WithClientScript(@<script>…</script>) Der Block wird über Html.PostScript nach den Bundles ausgegeben, jQuery und die Skripte der Komponenten stehen darin also bereit.
.Id("…"), .Tooltip("…"), .Attributes(new { … }) Id für den Zugriff im Skript, Titel als Tooltip, freie HTML-Attribute wie der Mauszeiger.

Drei Punkte, die den Unterschied machen:

  • Der Wert gehört sanitisiert ins Skript. @Html.SanitizedRaw(Html.ValueFor(m => m.Name)) statt roher Ausgabe: Ohne sie landen Umlaute als HTML-Entitäten (M&#xFC;ller) in der Zwischenablage. Nötig ist dafür @using databinding.WebSecurity.HtmlSanitizer.AspNetCore.Extensions.
  • Der Handler hängt am Dokument. Das Icon fügt der Builder selbst per Skript ein; ein direkt gebundener Handler wäre auf die Reihenfolge der beiden Skripte angewiesen, die Delegation an document nicht.
  • Inline-Skript und Content-Security-Policy. WithClientScript gibt genau das aus, was im Block steht. Unter einer strengen Richtlinie braucht der Block eine Nonce (Html.GetNonceValue()); die Demo-Anwendung erlaubt Inline-Skripte über AddUnsafeInlineScriptSrc(). Für Skripte, die nicht zu einer Icon-Aktion gehören, ist die eigene Datei unter wwwroot/js/… der bessere Weg.

navigator.clipboard verlangt einen sicheren Kontext, also HTTPS oder localhost.

Textbox mit Hilfetext

Info-Icon mit Tooltip neben der Beschriftung über [HelpText]; steht ebenso bei den übrigen DisplayTemplates zur Verfügung.

@model DisplayTextboxHilfetextBeispielViewModel

@Html.DisplayFor(m => m.Vorname)
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;

namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
    public class DisplayTextboxHilfetextBeispielViewModel
    {
        [Display(Name = "Vorname")]
        [UIHint(UiDisplay.Basis.Textbox)]
        [HelpText(Name = "Der amtliche Vorname gemäss Ausweis.")]
        public string Vorname { get; set; } = "Hans Muster";
    }
}

Darstellung

Vorname info
Hans Muster

Über [HelpText] erscheint neben der Beschriftung ein Info-Icon; der hinterlegte Text wird als Tooltip angezeigt. Der Text kommt direkt aus Name oder, mit gesetztem ResourceType, lokalisiert aus einer Ressource.

[Display(Name = "Vorname")]
[UIHint(UiDisplay.Basis.Textbox)]
[HelpText(Name = "Der amtliche Vorname gemäss Ausweis.")]
public string Vorname { get; set; }

Diese Möglichkeit steht bei allen DisplayTemplates zur Verfügung, die ein Schlüssel/Wert-Paar rendern, also auch bei Textarea, E-Mail und Telefon.