How to prevent page reload on form input with FastAPI

Question:

I have a simple program using FastAPI that multiplies a float value by 2 and displays it in HTML; this value is inputted through a HTML form. I’m wondering how I can get the value to display dynamically, without the page reloading when you press enter or press the submit button.

Here are the scripts (main.py and double.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello World</title>
</head>
<body>
    <h1>Hello World!</h1>
    <form method="post">
        <input type="number" step="0.00000001" name="num"/>
        <input type="submit"/>
    </form>
    <p>Result: {{ result }}</p>
</body>
</html>
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
import uvicorn

app = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get("/", response_class=HTMLResponse)
async def double_num(request: Request):
    result = "Type a number"
    return templates.TemplateResponse('double.html', context={'request': request, 'result': result})

@app.post("/", response_class=HTMLResponse)
async def double_num(request: Request, num: float = Form(...)):
    result = num*2
    return templates.TemplateResponse('double.html', context={'request': request, 'result': result})

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

I realize similar questions have been asked but they seem to involve jquery/javascript and don’t work for me due to the FastAPI/python backend.

Asked By: ossy

||

Answers:

As described in this answer, to keep the page from reloading/redirecting when submitting an HTML <form>, you would need to use a Javascript interface/library, such as Fetch API, to make an asynchronous HTTP request. If you would like to prevent the page from reloading when the user hits the enter key as well, you could use a similar approach to this answer that provides a solution on how to handle the <form> submission on the submit event (using the Event.preventDefault() method). Example below:

app.py

from fastapi import FastAPI, Request, Form
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get("/")
async def double_num(request: Request):
    return templates.TemplateResponse('double.html', context={'request': request})
 
@app.post("/")
async def double_num(num: float = Form(...)):
    return num * 2

templates/double.html

<!DOCTYPE html>
<html>
   <head>
      <title>Hello World</title>
      <script>
        document.addEventListener("DOMContentLoaded", (event) => {
          document.getElementById("myForm").addEventListener("submit", function (e) {
            e.preventDefault(); // Cancel the default action
            submitForm();
          });
        });
      </script>
   </head>
   <body>
      <h1>Hello World!</h1>
      <form id="myForm">
         <input type="number" name="num">
         <input class="submit" type="submit" value="Submit">
      </form>
      <div id="responseArea">Type a number</div>
      <script>         
         function submitForm() {
            var formElement = document.getElementById('myForm');
            var data = new FormData(formElement);
            fetch('/', {
                    method: 'POST',
                    body: data,
                })
                .then(response => response.text())
                .then(data => {
                    document.getElementById("responseArea").innerHTML = data;
                })
                .catch(error => {
                    console.error(error);
                });
         }
      </script>
   </body>
</html>
Answered By: Chris
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.