# Keine Seite neu laden nach einem Formular



## Dragosius (9. Dezember 2021)

Hallo,

ich bin nach wie vor dabei eine sehr alte Software zu modernisieren und habe da wieder eine Frage:

Ich habe folgendes HTML-Formular:

```
<script>
function resetinput() {
    document.forms['form'].elements['text'].value=document.forms['form'].elements['text2'].value;
    document.forms['form'].elements['text2'].value='';
    document.forms['form'].submit();
    document.forms['form'].elements['text2'].focus();
    document.forms['form'].elements['text2'].select();
}
</script>

<form name="form" method="post" action="eingabe.php" onSubmit="resetinput(); return false;">
<input type="text" name="text2" autofocus autocomplete="off" maxlength="255" value="" size="111">
<input name="text" value="" type="hidden"><select name="user_chat_back">
<option value="5">5&nbsp;Zeilen
<option value="6">6&nbsp;Zeilen
<option value="7">7&nbsp;Zeilen
<option value="8">8&nbsp;Zeilen
<option selected value="9">9&nbsp;Zeilen
<option value="10">10&nbsp;Zeilen
</select>
<input name="id" value="[ID]" type="hidden">
</form>
```

Wie kann ich es verhindern, dass die Seite nach dem Abschicken des Formulars neu geladen wird?

Was ich herausgefunden habe, ist das mit Ajax möglich?

Vielen Dank


----------



## Sempervivum (9. Dezember 2021)

Ja, da liegst Du richtig, mit Ajax geht es. Hier eine Demo aus der Schublade mit der fetch-API:

```
<form>
        <input type="text" name="param1" value="some-param">
        <input type="text" name="param2" value="some-other-param">
        <input type="number" name="numparam" value="1.24">
        <button type="submit">Abschicken</button>
    </form>
    <span id="out"></span>
    <script>
        document.querySelector('form').addEventListener('submit', event => {
            event.preventDefault();
            fetch('testpost.php', {
                method: 'post',
                body: new FormData(document.querySelector('form'))
            }).then(res => {
                return res.text();
            }).then(res => {
                console.log(res);
                document.getElementById('out').innerHTML = res;
            });
        })
    </script>
```
Versuche, es auf deine Gegebenheiten anzupassen.


----------



## Dragosius (9. Dezember 2021)

Danke dir 

Wie kann ich es realisieren, dass nach dem Absenden wieder bei einem bestimmten input-Feld der Cursor drinnen steht, so dass man gleich erneut wieder was rein schreiben kann?

"autofocus" scheint hier nicht zu funktionieren.


----------



## Sempervivum (9. Dezember 2021)

Dafür gibt es die Funktion focus():
HTMLElement.focus() - Web APIs | MDN


----------



## Dragosius (9. Dezember 2021)

Könntest du mir da etwas helfen?
Dies sollte funktionieren, wenn man auf den Button klickt, als auch den Text mit "Enter" abschickt.


```
<form action="eingabe.php" method="post">
    <input type="text" name="text2" autofocus autocomplete="off" maxlength="255" value="" size="111">
<input name="text" value="" type="hidden">
<select name="user_chat_back">
<option value="5">5&nbsp;Zeilen
<option value="6">6&nbsp;Zeilen
<option value="7">7&nbsp;Zeilen
<option value="8">8&nbsp;Zeilen
<option value="9">9&nbsp;Zeilen
<option selected value="10">10&nbsp;Zeilen
</select>
<input name="id" value="[id]" type="hidden">
<button type="submit">Go!</button>
</form>
<span id="out"></span>
<script>
    document.querySelector('form').addEventListener('submit', event => {
        event.preventDefault();
        fetch('eingabe.php', {
            method: 'post',
            body: new FormData(document.querySelector('form'))
        }).then(res => {
            return res.text();
        }).then(res => {
            console.log(res);
            document.getElementById('out').innerHTML = res;
        });
    })
</script>
```


----------



## Sempervivum (9. Dezember 2021)

Wenn ich das was Du gepostet hast, teste, funktioniert es einwandfrei, sowohl bei Klick auf den Button als auch wenn ich im Textfeld Enter drücke. Liegt der Fehler vielleicht woanders? Hast Du noch mehr Formulare auf der Seite?


----------



## Dragosius (9. Dezember 2021)

Ja da war noch eins, was ich ausgebaut habe.

Jetzt wird es interessant.

Ausgangslage:



Wenn ich da nun Text absenden will, sieht es so aus:


Der Text wird dabei nicht abgesendet.


----------



## Sempervivum (9. Dezember 2021)

Was soll denn passieren, wenn der Text abgesendet wird? Er wird ja an eingabe.php geschickt und muss dort irgend wie verarbeitet werden. Ist der untere Block mit dem leeren Textfeld die Antwort vom Server bzw. vom Skript eingabe.php?


----------



## Dragosius (9. Dezember 2021)

Es soll eine Funktion aufgerufen werden, welche weiter oben eingebunden ist:


```
if (isset($text2) && strlen($text2) != 0) {
    $text = $text2;
}

if($text != "") {
    schreibe_nachricht_chat($text, $privat, $user_chat_back, $o_id, $benutzerdaten);
}
```

Das funktioniert nicht mehr, da die Seite nicht neu geladen wird, oder?

Aber warum wird denn die Eingabezeile dann eigentlich ein 2. Mal angezeigt?


----------



## Sempervivum (9. Dezember 2021)

Die Seite wird zwar nicht neu geladen aber da sie über Ajax bzw. fetch aufgerufen wird, sollte das Skript aufgerufen werden.
Aber erst Mal grundsätzlich: Ich vermute, die Ausgangsseite und die Seite, die Du über Ajax aufrufst, sind ein und die selbe, nämlich eingabe.php, nicht wahr? Das wäre dann die Erklärung dafür, dass die Eingabezeile zwei Mal auftaucht. Das funktioniert bei einem Affenformular aber nicht bei dem Verfahren mit Ajax. Dort darfst Du nur das PHP-Skript ausführen und die Ausgaben, die Du brauchst, ausgeben und dann wieder auf der Ausgangsseite eintragen.
Bei dem Codeschnipsel, das Du oben gepostet hast, fehlt leider der Zusammenhang: Wo kommt $text2 her? Und was macht die Funktion schreibe_nachricht_chat?


----------



## Dragosius (9. Dezember 2021)

Du hast mit deiner Vermutung Recht, es ist die gleiche Datei.

Hierbei handelt es sich um die Eingabe des Benutzers für einen Chat.
Mit der Funktion wird praktisch die Eingabe in der Datenbank gespeichert.

Hier mal der Code in der richtigen Reihenfolge, wie ich ihn gerade eingebaut habe:


```
<?php
$text = filter_input(INPUT_POST, 'text');
if( $text == '') {
    $text = filter_input(INPUT_GET, 'text');
}
$text2 = filter_input(INPUT_POST, 'text2');
$privat = filter_input(INPUT_POST, 'privat', FILTER_SANITIZE_STRING);
$user_chat_back = filter_input(INPUT_POST, 'user_chat_back', FILTER_SANITIZE_NUMBER_INT);

if (isset($text2) && strlen($text2) != 0) {
    $text = $text2;
}

if($text != "") {
    schreibe_nachricht_chat($text, $privat, $user_chat_back, $o_id, $benutzerdaten);
}

?>
<div style="margin-top: 3px; margin-left: 5px;">
<?php
// Eingabeformular mit Menu und Farbauswahl
reset($farbe_chat_user);

$text2_typ = "<input type=\"text\" name=\"text2\" autofocus autocomplete=\"off\" maxlength=\"" . ($chat_max_eingabe - 1) . "\" value=\"\" size=\"" . $chat_eingabe_breite . "\">\n";
?>
<form action="eingabe.php" method="post">
    <?php
    echo $text2_typ;
    // Unterscheidung Normal oder sicherer Modus
    if ($sicherer_modus == 1 || $benutzerdaten['u_sicherer_modus'] == "1") {
        echo "<input name=\"text\" value=\"\" type=\"hidden\">\n"
            . "<select name=\"user_chat_back\">\n";
        for ($i = 10; $i <= 40; $i++) {
            echo "<option " . ($chat_back == $i ? "selected " : "") . "value=\"$i\">$i $t[eingabe1]\n";
        }
        echo "</select>\n";
    } else {
        echo "<input name=\"text\" value=\"\" type=\"hidden\">\n";
    }
    echo "<input name=\"id\" value=\"$id\" type=\"hidden\">\n";
    ?>
    <button type="submit">Go!</button>
</form>
<span id="out"></span>
<script>
    document.querySelector('form').addEventListener('submit', event => {
        event.preventDefault();
        fetch('eingabe.php', {
            method: 'post',
            body: new FormData(document.querySelector('form'))
        }).then(res => {
            return res.text();
        }).then(res => {
            //console.log(res);
            document.getElementById('out').innerHTML = res;
        });
    })
</script>
</div>
```


----------



## Sempervivum (9. Dezember 2021)

OK, das ist schon wesentlich aufschlussreicher. Erst Mal fehlt da das ganze Grundgerüst mit head und body oder hast Du es weg gelassen, weil es in dem Zusammenhang nicht wichtig ist?
Was funktioniert denn jetzt nicht? Wird der Text nicht in die Datenbank eingetragen?


----------



## Dragosius (9. Dezember 2021)

Der Text wird nicht abgesendet, sondern die 2. doppelte Zeile angezeigt.

Eventuell ist es doch einfacher, dir den Link zu schicken:
mainChat/eingabe.php at main · ePfirsich/mainChat

Dort wird aktuell die Eingabe über eine andere Datei in einem anderen Frame (Ja der Chat läuft noch in Frames) abgewickelt.
Genau das will ich entfernen, damit ich den anderen verstecken Frame nicht mehr brauche, da ich die Frames natürlich irgendwann los werden möchte.


----------



## Sempervivum (9. Dezember 2021)

> Der Text wird nicht abgesendet, sondern die 2. doppelte Zeile angezeigt.


Beides schließt sich nicht aus. Hast Du dich davon überzeugt, dass er nicht abgesendet wird?


----------



## Dragosius (10. Dezember 2021)

Sempervivum hat gesagt.:


> Beides schließt sich nicht aus. Hast Du dich davon überzeugt, dass er nicht abgesendet wird?


Ja wird er, da er sonst im Chat angezeigt werden würde.
Wenn man in der 2. erschienen Eingabezeile dann übrigens was eintippt, wird der Text aus der 1. und 2. Eingabezeile abgesendet.


----------



## Sempervivum (10. Dezember 2021)

Bevor Du da mit der Fehlersuche weiter machst, empfehle ich, zunächst die PHP-Datei aufzutrennen: In eingabe.php nur die Genererieung des Formulars und in senden.php nur den Code für das Senden. Und senden.php dann im fetch als URL übergeben:

senden.php:

```
<?php
$text = filter_input(INPUT_POST, 'text');
if( $text == '') {
    $text = filter_input(INPUT_GET, 'text');
}
$text2 = filter_input(INPUT_POST, 'text2');
$privat = filter_input(INPUT_POST, 'privat', FILTER_SANITIZE_STRING);
$user_chat_back = filter_input(INPUT_POST, 'user_chat_back', FILTER_SANITIZE_NUMBER_INT);

if (isset($text2) && strlen($text2) != 0) {
    $text = $text2;
}

if($text != "") {
    schreibe_nachricht_chat($text, $privat, $user_chat_back, $o_id, $benutzerdaten);
}

?>
```

eingabe.php:

```
<div style="margin-top: 3px; margin-left: 5px;">
<?php
// Eingabeformular mit Menu und Farbauswahl
reset($farbe_chat_user);

$text2_typ = "<input type=\"text\" name=\"text2\" autofocus autocomplete=\"off\" maxlength=\"" . ($chat_max_eingabe - 1) . "\" value=\"\" size=\"" . $chat_eingabe_breite . "\">\n";
?>
<form action="eingabe.php" method="post">
    <?php
    echo $text2_typ;
    // Unterscheidung Normal oder sicherer Modus
    if ($sicherer_modus == 1 || $benutzerdaten['u_sicherer_modus'] == "1") {
        echo "<input name=\"text\" value=\"\" type=\"hidden\">\n"
            . "<select name=\"user_chat_back\">\n";
        for ($i = 10; $i <= 40; $i++) {
            echo "<option " . ($chat_back == $i ? "selected " : "") . "value=\"$i\">$i $t[eingabe1]\n";
        }
        echo "</select>\n";
    } else {
        echo "<input name=\"text\" value=\"\" type=\"hidden\">\n";
    }
    echo "<input name=\"id\" value=\"$id\" type=\"hidden\">\n";
    ?>
    <button type="submit">Go!</button>
</form>
<span id="out"></span>
<script>
    document.querySelector('form').addEventListener('submit', event => {
        event.preventDefault();
        fetch('senden.php', {
            method: 'post',
            body: new FormData(document.querySelector('form'))
        }).then(res => {
            return res.text();
        }).then(res => {
            //console.log(res);
            document.getElementById('out').innerHTML = res;
        });
    })
</script>
</div>
```


----------



## Dragosius (10. Dezember 2021)

Hallo,

jetzt funktioniert das Senden soweit ganz gut.
Nur wird leider der Text nach dem Absenden in der Eingabe nicht gelöscht.
Wie kann ich denn das noch umsetzen?


----------



## Sempervivum (10. Dezember 2021)

Das ist relativ einfach: Im then-Zweig des fetch das Eingabefeld löschen:

```
<script>
    document.querySelector('form').addEventListener('submit', event => {
        event.preventDefault();
        fetch('senden.php', {
            method: 'post',
            body: new FormData(document.querySelector('form'))
        }).then(res => {
            return res.text();
        }).then(res => {
            //console.log(res);
            document.querySelector('input[name="text2"]').value = '';
            document.getElementById('out').innerHTML = res;
        });
    })
</script>
```


----------



## Dragosius (10. Dezember 2021)

Vielen Dank,
bisher funktioniert es ganz gut.

Ich habe auch gleich noch ein bisschen aufgeräumt. (Unter anderem "text2" nun komplett entfernt, da ich es hier nicht mehr brauche)


----------



## Dragosius (11. Dezember 2021)

Ich hätte da noch eine ähnliche Frage dazu:

Ist es auch irgendwie möglich, dies mit einem Linz zu realisieren?
Also dass wenn ich auf einen Link klicke, der Link nicht aufgerufen wird. (Weil ich nur die Funktion dahinter aufrufen will.


```
<a href="schreibe.php?param1=value1&param2=value2">Link</a>
```


----------



## Sempervivum (11. Dezember 2021)

Das wäre schon möglich aber wenn der Link nicht aufgerufen werden soll, soll ja stattdessen das PHP-Skript aufgerufen werden. Und dafür brauchst Du dann Ajax, womit wir wieder am Anfang wären.


----------



## Dragosius (14. Dezember 2021)

Sempervivum hat gesagt.:


> Das wäre schon möglich aber wenn der Link nicht aufgerufen werden soll, soll ja stattdessen das PHP-Skript aufgerufen werden. Und dafür brauchst Du dann Ajax, womit wir wieder am Anfang wären.


Könntest du mir da eventuell (nochmal) etwas helfen?
Wir sind hier ja bisher nur die Möglichkeit über ein Formular durchgegangen oder habe ich was überlesen?


----------



## Sempervivum (14. Dezember 2021)

Heißt das, Du hast irgend wie diesen Link zur Verfügung und möchtest, anstatt ihn direkt aufzurufen, mit Ajax das PHP-Skript aufrufen? In welcher Form hast Du denn den Link vorliegen? In einer Variablen? In einem a-href-Tag? Oder ...?


----------



## Sempervivum (14. Dezember 2021)

PS: Ich hätte gleich genauer lesen sollen: Du hast den Link als a-Element. In dem Fall ist es ganz einfach wenn Du die Parameter einfach mit der get-Methode überträgst:

```
<a href="testget.php?param1=value1&param2=value2">Link</a>
    <span id="out"></span>
    <script>
        document.querySelector('a').addEventListener('click', event => {
            // Default-Aktion für Klick auf den Link,
            // d. h. direktes Aufrufen der Seite,
            // verhindern, da wir das Linkziel mit Ajax aufrufen wollen:
            event.preventDefault();
            // Link aus dem href-Attribut holen:
            const link = event.target.href;
            fetch(link, {
                method: 'get'
            }).then(res => {
                return res.text();
            }).then(res => {
                console.log(res);
                document.getElementById('out').innerHTML = res;
            });
        })
    </script>
```


----------



## Dragosius (16. Dezember 2021)

Hallo,

also irgendwie wird die Seite trotzdem aufgerufen.

Ich habe es momentan folgendermaßen eingebunden:

```
$trow = "<a href=\"schreibe.php?text=gag&nickname=$v[u_nick]\">G</a>&nbsp;";
$trow .= "<a href=\"schreibe.php?text=kick&nickname=$v[u_nick]\">K</a>&nbsp;";

$trow .= "<span id=\"out\"></span>\n";
$trow .= "<script>
document.querySelector('a').addEventListener('click', event => {
    // Default-Aktion für Klick auf den Link,
    // d. h. direktes Aufrufen der Seite,
    // verhindern, da wir das Linkziel mit Ajax aufrufen wollen:
    event.preventDefault();
    // Link aus dem href-Attribut holen:
    const link = event.target.href;
    fetch(link, {
        method: 'get'
    }).then(res => {
        return res.text();
    }).then(res => {
        console.log(res);
        document.getElementById('out').innerHTML = res;
    });
})
</script>";

echo $trow;
```

Kann der Link dann eventuell noch mit einer Klasse versehen werden, da dort auch noch andere Links eingebunden sind, welche normal aufgerufen werden.


----------



## Sempervivum (16. Dezember 2021)

Dieses `document.querySelector('a')` wirkt nur auf das *erste *a-Tag auf der Seite, alle anderen werden normal aufgerufen.
Selbstverständlich kannst Du das mit einer Klasse eingrenzen. Wenn es nur ein einziger Link ist, kannst Du bei querySelector bleiben, dann müsste das JS so aussehen:
`document.querySelector('a.deine-klasse')`


----------



## Dragosius (16. Dezember 2021)

Danke, das sieht gut aus.

Wie kann ich das denn auf mehrere Links mit der Klasse ausweiten?


----------



## Sempervivum (16. Dezember 2021)

Auch kein Problem:

```
<script>
document.querySelectorAll('a.deine-klasse').forEach(item => {
    item.addEventListener('click', event => {
        // Default-Aktion für Klick auf den Link,
        // d. h. direktes Aufrufen der Seite,
        // verhindern, da wir das Linkziel mit Ajax aufrufen wollen:
        event.preventDefault();
        // Link aus dem href-Attribut holen:
        const link = event.target.href;
        fetch(link, {
            method: 'get'
        }).then(res => {
            return res.text();
        }).then(res => {
            console.log(res);
            document.getElementById('out').innerHTML = res;
        });
    });
})
</script>";
```


----------



## Dragosius (23. Januar 2022)

Danke, die Antwort ist irgendwie völlig unter gegangen.
ich werde es demnächst testen.


----------



## Dragosius (4. Februar 2022)

Ich wollte kurz Bescheid geben, dass ich es soeben erfolgreich getestet habe.
Somit kann ich bei der Software wieder einen Frame einsparen.


----------



## Jan-Frederik Stieler (4. Februar 2022)

Hi, 
ich bin der Meinung das man bei js entweder mit Klassen oder noch besser mit IDs arbeiten sollte.
Aber nicht in Kombination mit HTML-Elementen. 
Den so trennt man Struktur und Logik nicht. Und mit Klassen zu arbeiten ist z.B. bei cuting Edge CSS-Frameworks wie Tailwind oder dem aktuellen Bootstrap gar nicht mehr möglich, außer man baut eigene Klassen ein.
Und ich hab auch irgendwo gelesen das getElementById eine bessere Performance haben soll als queryselektor, auch wenn sich das bei den wenigsten bemerkbar macht.

Aber wo ich echt Augenkrebs bekomme ist Dein HTML im PHP.
beende doch einfach vor dem HTML das php und starte es später wieder. Dann sparst Du Dir nervtötendes Escapen und musst auch kein Echo machen oder Variablen miteinander kombinieren.

Grüße


----------

