PHP-Neuling: Fensterposition nach form submit merken

Hallo Miteinander

ich versuche mich gerade an einer Art "Kalender" zur Urlaubsplanung in PHP (SQL)

Optisch sieht das ca so aus: http://prntscr.com/1uq7xui

Die einzelnen Felder sind divs mit select-feldern. jedes Selectfeld hat ein eigenes Submit drin, sodass das Formular direkt abgeschickt wird, wenn ich in einem Feld "U", "K" oder "S" wähle.

Nun habe ich 2 Sachen bei denen ich noch keine Lösung finden konnte, u.a. auch weil meine javascript Kenntnisse nur mäßig sind

1.) Fensterposition merken Um die letzten Monate zu sehen muss die Ansicht gescrollt werden. Das ist jetzt an sich nicht schlimm. Doof ist aber, dass beim Absenden des Formulars die Site direkt neu geladen wird, und der Fensterfokus zurückgesetzt wird. Ich muss also für einen weiteren Tag o.ä. wieder herunterscrollen.

Wie kann ich also unmittelbar vor dem submit die aktuelle Position des Fensters (X/Y) abspeichern und direkt nach dem reload er Seite wieder abrufen, sodass nicht gescrollt werden muss?

Ich kenne das von anderen Websites, also muss es ja grundlegend machbar sein

2.) Mehrere Selects zusammenfassen Das ist auch eine Idee, damit man bei bspw. 14 (10) Tagen Urlaub nicht auch 10 Selectfelder wählen muss, sondern eventuell Gruppieren kann sodass eine ganze Woche gewählt werden kann Dazu auch gerne Quellcode wenn's soweit ist :)

Vg und bleibt gesund

Newbie

  1. Hallo PHP-Neuling,

    du bist nicht zum ersten Mal bei uns, aber ich habe kein Notizbuch über die Kenntnisstände aller Forenbenutzer… Ich bin ja kein Lehrer 😉. Und es ist ja auch denkbar, dass jemand, der sich vor einem halben Jahr als Anfänger zeigte, mittlerweile eine Menge dazugelernt hat.

    javascript Kenntnisse ... mäßig

    Mäßig bedeutet: einfache Sachen bekommst Du eigenständig hin und du hast ein Grundverständnis der Sprache. Du kennst aber nur einen Basis-Satz von Programmierschnittstellen und weißt nicht, was es alles gibt.

    Mäßig bedeutet nicht: Du kannst ausschließlich fertige Code-Snippets zusammenkopieren und kapierst nicht, was sie tun. Eventuell kannst Du leichte Anpasungen vornehmen, z.B. IDs oder Klassennamen. Diesen Kenntnisstand würde ich mit "gering" klassifizieren.

    Das lässt sich noch mit "ahnungslos" unterbieten, in dem Fall müsste man Dir auch sagen, wohin Du Codesnippets kopieren musst und was Du anpassen musst.

    Deute ich dein "mäßig" richtig? Oder ist es ein Euphemismus für "gering"?

    jedes Selectfeld hat ein eigenes Submit drin, sodass das Formular direkt abgeschickt wird,

    Das geht nicht ohne JavaScript, d.h. du hast bereits einen change- oder input-Handler für die select-Felder registriert, der den Submit auslöst. Hoffentlich einen, der mit Bubbling arbeitet und an einer zentralen Stelle hängt, und nicht einen eigenen für jedes select.

    Diesen Eventhandler kannst Du nutzen, um vor dem Submit die action des Forms zu manipulieren. Gib jedem Monatscontainer eine passende ID, z.B. "monat_202101" für den Januar, und füge der Form-Action vor dem Submit eine Hash-Komponente wie #monat_202101 hinzu. Der Browser wird den Monat, für den submittet wurde, dann automatisch nach oben positionieren. An Stelle einer Manipulation des action Attributs im Form hätte ich Dir ja lieber vorgeschlagen, jedem select Element ein formaction-Attribut zu geben, aber das gibt's da nicht.

    Ein Schritt aufwärts: AJAX

    Besser - sofern es Dich nicht überfordert - wäre eine Lösung mit AJAX, d.h. du machst keinen Form-Submit, sondern postest auf ein API Script, das nur die Änderung speichert. Für den User passiert gar nichts, das erfolgt rein im Hintergrund. Den Ajax-Aufruf kannst Du mit XMLHttpRequest, jQuery oder - am besten - mit fetch implementieren. Unser fetch-Artikel im Selfwiki ist leider immer noch nur ein Stub, ich muss Dich deshalb für eine Lektüre zu Mozilla schicken. Eine deutsche Einführung habe ich auch hier gesehen.

    Serverseitig wird ein POST durch fetch wie POST durch ein Form verarbeitet, wenn Du die Daten als FormData sendest:

    let formdata = new FormData(document.forms.kalender);
    fetch('/calendarchange.php', {
      method: 'POST',
      body: formdata
    });
    

    Wenn Du auch Antworten vom Server brauchst - und sei es eine Fehlermeldung oder Updates anderer Kalenderzellen, wäre ein JSON-String sinnvoll, den Du in JS mit JSON.parse in ein Objekt umwandeln kannst. Das ist dann aber schon etliches mehr an JavaScript, du musst die Server-Antwort dann auch entgegennehmen und dann sind wir bereits bei Promises. Das wird in den Links oben gezeigt, aber man muss dann schon verstehen, was passiert.

    Was man auch findet, sind Serverkomponenten, die ein fertiges HTML Snippet liefern. In deinem Fall könnte das ein fertiger HTML Block für den Monat oder den Tag sein, und du überschreibst einfach das innerHTML Attribut.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hi Rolf, wie immer vieeeelen Dank. Du nimmst dir immer so enorm viel Zeit.

      Um meine Kenntnisse einzuordnen. Ich kann bestehende Scripte sehr gut abwandeln und bearbeiten. Mir ist auch meist bewusst wie ich sie wo einzubauen habe und wie ich sie aufrufe. Zumeist fehlt es mir an Kreativität um mir die komplette Syntax selbst aus den Ärmeln zu leiern.

      Also siedeln wir mich mal zwischen "gering" und "mäßig" ein.

      Ich habe tatsächlich mit hilfe von Schleifen für jedes SELECT eine eigene Form erstellt bzw. erstellen lassen. Ich versuche das mal anhand von Quellcode zu verdeutlichen

      for($d = 1; $d <= $daysJAN; $d++){ 	?>
      
      <div id="tag"><?= $d ?> 
      <?php echo strftime("%a", mktime(0, 0, 0, 1, $d, $YEAR));?>
      	<form name="iselect_1<?= 'd'.$d?>">
      	<select name="iselect_1<?= 'd'.$d?>" onchange="document.forms.iselect_1<?= 'd'.$d?>.submit()">
      
      

      $daysJAN beinhaltet die Anzahl der Tage des Monats Januar. Kann man auch fix machen, hab dafür aber eine PHP Funktion genutzt in der DB habe ich dann Felder wie "d1", "d11","d31" für die Tage entsprechend. die for Schleife rennt dann da komplett durch. Das update läuft über ein externes php script

      Ich weiß tatsächlich nicht, was "Bubbling" ist. Aber das bekomme ich ja raus :)

      Ich schau mir mal AJAX an. Eventuell kann ich ja da schlau draus werden

      Vg

      1. Hallo PHP-Neuling,

        du machst Dir die Form-Ermittlung unnötig kompliziert. Wenn der Browser den Code in onchange ausführt, setzt er this auf das Element, an dem onchange notiert ist, also das Select-Element. Dieses hat eine form-Eigenschaft, die auf dessen Form verweist. Das Form braucht dann eigentlich gar keinen Namen mehr (es sei denn, den verwendest Du anderswo noch). Dem Select-Element würde ich bei dieser Konstruktion einen Namen geben, der immer gleich ist. Welches Datum geändert wird, steuerst Du über die Action-URL des Forms:

        <form action="kalender.php?datum=20211004">
           <select name="auswahl" onchange="this.form.submit()">
              <option value="...">...</option>
              <option value="...">...</option>
              <option value="...">...</option>
           </select>
        </form>
        

        Dann findest Du in $_GET["datum"] das Datum und in $_POST["auswahl"] den ausgewählten Wert. Bzw. Du verwendest $_REQUEST["datum"] und $_REQUEST["auswahl"], wenn Du Dir keinen Kopf drum machen willst, ob es ein GET- oder POST-Parameter ist.

        Und was ist bubbling? Tja, hier eine ausführliche und im wahresten Sinne des Wortes erschöpfende Lektüre im Selfwiki.

        Ob Dir bubbling viel nützt, darüber kann man geteilter Meinung sein. Das eine onchange-Attribut, das außer this.form.submit() nichts tut, macht den Kohl auf der Seite nicht viel fetter.

        Angenommen, du hast folgendes auf der Seite, natürlich mit noch viel mehr forms:

        <body>
          <section id="kalender">
            <div id="monat_2021_10">
              <form action="termine.php?datum=20211004">
                <select name="auswahl" onchange="this.form.submit()">
                </select>
              </form>
              <form action="termine.php?datum=20211005">
                <select name="auswahl" onchange="this.form.submit()">
                </select>
              </form>
            </div>
          </section>
        </body>
        

        Dann könnte man den Change-Handler von den select-Elementen entfernen und auf das section-Element legen:

        <body>
          <section id="kalender">
            <div id="monat_2021_10">
              <form action="termine.php?datum=20211004">
                <select name="auswahl" >
                </select>
              </form>
              <form action="termine.php?datum=20211005">
                <select name="auswahl">
                </select>
              </form>
            </div>
          </section>
          <script>
          document.getElementById("kalender").addEventListener("change",
            function(event) { 
              let selectElement = event.target;
              if (selectElement.tagName != "SELECT") return;  // falsches Element
              selectElement.form.submit();
            });
          </script>
        </body>
        

        Das Script muss so, wie es gebaut ist, hinter dem Kalender-Container stehen, sonst findet es ihn nicht. Ob das bei Dir eine section mit id="kalender" ist, weiß ich natürlich nicht - du musst bei Dir das Container-Element identifizieren, das alle Kalendertage enthält, und dessen ID bei getElementById angeben.

        Auf diesem Element wird nun mit addEventListener ein change-Eventhandler registriert. Das ist so ähnlich wie onchange, aber im Script statt im HTML, und man kann - falls man will - auch mehr als einen Handler für ein Event registrieren.

        Die Funktion, die auf das Event reagieren soll, bekommt das event-Objekt übergeben. Darin finden sich Informationen zum verarbeiteten Event, die Event-Schnittstelle (also die Eigenschaften und Methoden dieses Objekts) ist hier näher beschrieben.

        Es gibt jetzt nur noch eine Eventhandler-Registrierung, statt eine pro select. Der Eventhandler bekommt nun die change-Events aller Elemente im Kalender-Container mit, deswegen fragt die Funktion als erstes ab, ob es auch ein select-Element war (über den tagName). Wenn nicht, springt sie gleich wieder zurück. Und wenn doch, schickt sie dem zugehörigen Form ein submit. Fertig 😀

        Rolf

        --
        sumpsi - posui - obstruxi