Formular zurücksetzen

Ein Suchformular soll sich leeren lassen – aber nicht blind. Der Reset-Knopf des Browsers stellt die ursprünglich gerenderten Werte wieder her und ist damit für diesen Zweck ungeeignet.

Die Schaltfläche vom Typ DeleteForm leert die Felder stattdessen gezielt: Was in IgnoreForFormReset steht, bleibt unberührt; was in DefaultValueForFormReset steht, bekommt einen festen Wert; alles Übrige wird geleert. Das nötige Skript erzeugt der Builder selbst.

Suchformular mit Ausnahmen und Standardwert

Der Browser-Reset stellt die ursprünglich gerenderten Werte wieder her – ButtonType.DeleteForm leert die Felder stattdessen gezielt: «Name» bleibt stehen, «Dossier» bekommt einen Standardwert, alles Übrige wird geleert.

@using FMH.Komponente.Infrastruktur.Schnittstellen.Ui
@model FormularResetBeispielViewModel

@* Ein Reset-Button des Browsers stellt die *ursprünglich gerenderten* Werte wieder her – das ist
   selten das, was ein Suchformular braucht. ButtonType.DeleteForm leert stattdessen die Felder,
   mit zwei Ausnahmen:

   - IgnoreForFormReset nennt Felder, die unberührt bleiben,
   - DefaultValueForFormReset nennt Felder, die einen bestimmten Wert bekommen.

   Alles Übrige wird geleert. Das Skript dazu erzeugt der Builder selbst; ein eigenes JavaScript
   ist nicht nötig. *@
@* Das Formular sendet in dieser Demo nichts ab – die Schaltfläche «Suchen» ist deshalb vom Typ
   Button. Für DeleteForm zählt nur, dass es ein umschliessendes <form> gibt: Das erzeugte Skript
   arbeitet auf dem nächstgelegenen Formular. *@
<form method="post">
    <div style="max-width: 30rem;">
        @Html.EditorFor(m => m.Name)
        @Html.EditorFor(m => m.DossierId)
        @Html.EditorFor(m => m.Pensum)
        @Html.EditorFor(m => m.Von)
        @Html.EditorFor(m => m.Bis)
    </div>

    <div class="mt-3 d-flex gap-2">
        @Html.Fmh(
            Fmh.Button()
                .Text("Suchen")
                .Icon(IconType.Search)
                .Type(ButtonType.Button)
                .Size(ButtonSize.Sm))

        @Html.Fmh(
            Fmh.Button(ButtonType.DeleteForm)
                .Text("Zurücksetzen")
                .Icon(IconType.Delete)
                .Size(ButtonSize.Sm)
                .Attributes(new { id = "btnResetForm" })
                .IgnoreForFormReset(nameof(Model.Name))
                .DefaultValueForFormReset(new DefaultValue { Field = nameof(Model.DossierId), Value = "4" }))
    </div>
</form>
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace FMH.Komponente.WebUI.Areas.Infrastruktur.Models
{
    /// <summary>
    /// Ein Suchformular für das Beispiel «Formular zurücksetzen».
    /// </summary>
    /// <remarks>
    /// Bewusst gemischte Feldarten: Die Schaltfläche vom Typ <c>DeleteForm</c> geht über
    /// <c>input</c>, <c>select</c> und <c>textarea</c> und muss mit allen umgehen können.
    /// </remarks>
    public class FormularResetBeispielViewModel
    {
        /// <summary>
        /// Holt oder setzt den Namen. Bleibt beim Zurücksetzen stehen (IgnoreForFormReset).
        /// </summary>
        [Display(Name = "Name")]
        public string Name { get; set; } = "Muster";

        /// <summary>
        /// Holt oder setzt das Dossier. Bekommt beim Zurücksetzen einen Standardwert.
        /// </summary>
        [Display(Name = "Dossier")]
        [UIHint(UiEditor.Basis.DropdownList)]
        [AdditionalMetadata("Selection", nameof(Dossiers))]
        public int? DossierId { get; set; } = 2;

        /// <summary>
        /// Holt die Auswahlliste des Dossiers.
        /// </summary>
        public IEnumerable<SelectListItem> Dossiers { get; } = new List<SelectListItem>
                                                               {
                                                                   new ("Dossier 2024", "2"),
                                                                   new ("Dossier 2025", "3"),
                                                                   new ("Dossier 2026", "4"),
                                                               };

        /// <summary>
        /// Holt oder setzt das Pensum. Wird beim Zurücksetzen geleert.
        /// </summary>
        [Display(Name = "Pensum in %")]
        public string Pensum { get; set; } = "80";

        /// <summary>
        /// Holt oder setzt den Beginn des Zeitraums. Wird beim Zurücksetzen geleert.
        /// </summary>
        [Display(Name = "Von")]
        [DataType(DataType.Date)]
        public DateTime? Von { get; set; } = new DateTime(2026, 1, 1);

        /// <summary>
        /// Holt oder setzt das Ende des Zeitraums. Wird beim Zurücksetzen geleert.
        /// </summary>
        [Display(Name = "Bis")]
        [DataType(DataType.Date)]
        public DateTime? Bis { get; set; } = new DateTime(2026, 12, 31);
    }
}

Darstellung

Ein Suchformular soll sich leeren lassen – der Reset-Knopf des Browsers taugt dafür nicht: Er stellt die ursprünglich gerenderten Werte wieder her, nicht einen leeren Zustand.

Dafür gibt es den Schaltflächen-Typ DeleteForm:

@Html.Fmh(Fmh.Button(ButtonType.DeleteForm)
    .Text("Zurücksetzen")
    .Icon(IconType.Delete)
    .Attributes(new { id = "btnResetForm" })
    .IgnoreForFormReset(nameof(Model.Name))
    .DefaultValueForFormReset(new DefaultValue { Field = nameof(Model.DossierId), Value = "4" }))
Aufruf Wirkung
.IgnoreForFormReset(params string[]) Diese Felder bleiben unberührt.
.DefaultValueForFormReset(params DefaultValue[]) Diese Felder bekommen den angegebenen Wert. DefaultValue hat Field und Value.
alles Übrige wird geleert.

Beide Methoden wirken nur in Verbindung mit ButtonType.DeleteForm; an einer gewöhnlichen Schaltfläche bleiben sie ohne Folge.

Es braucht kein eigenes JavaScript

Der Builder registriert beim Rendern selbst einen Klick-Listener für seine Id. Der arbeitet auf dem nächstgelegenen umschliessenden <form> und geht dessen input, select und textarea durch. Die Schaltfläche gehört deshalb in das Formular, das sie zurücksetzen soll.

Was zu beachten ist

  • IgnoreForFormReset vergleicht nicht exakt, sondern per Teilzeichenkette. IgnoreForFormReset("Name") verschont damit auch Vorname, Nachname und FormularName. Bei ähnlich benannten Feldern den längeren, eindeutigen Namen angeben.
  • .Attributes(new { id = … }) setzen. Der erzeugte Listener spricht die Schaltfläche über ihre Id an; ohne eigene Id ist nicht vorhersagbar, welche gemeint ist.
  • Value ist immer eine Zeichenkette – auch für Zahlen und Auswahlfelder. Bei einer Auswahlbox ist es der Value des Eintrags, nicht sein Anzeigetext.
  • Der Vorgang läuft rein im Browser; der Server erfährt davon nichts, solange das Formular nicht abgesendet wird.