'Generate dynamic div containers on submit in Flask app

I am new in Flask. My goal is to generate dynamic div containers every time I upload a dxf file and next submit happens. For example: one file uploaded- one div shown; two files uploaded- two divs shown and so on. I can convert uploaded dxf files to .png images and I would like to show these images in div elements displayed after every upload. I use input tag to upload files (type='file') and Java Script to generate dynamic elements (divs and their child tags). The problem is that every time I upload file, the template is loading again and no new content is shown except the image of the last uploaded dxf. Please, give me a piece of advice to solve it.

HTML

...
<form enctype="multipart/form-data"  id="uploadForm" action="/upload_files" name="uploadForm"  method="post">
   DXF file: <input type="file" id="dxfUpload" onchange="form.submit(); createConfigure();"   name="dxfUpload" />

    <div id="calcHolder" name="calcHolder">
        
            <script type="text/javascript">
    
                
                function createConfigure() {
        
                    var div = document.createElement("div");
                    div.id = "dxf-"+Math.random() * 100000000000000000 + "-"  
                    + window.performance.now() * 100000000000000000;
                    id_div=div.id;
                    div.className = 'border pad';
                    div.style.width = "640px";
                    div.style.height = "200px";
                    document.getElementById("calcHolder").appendChild(div);
                    
    
                   
    
                    var img = document.createElement("img");
                    img.setAttribute("src", "{{url_for('static', filename=dxfName+'.png')}}");
                    img.setAttribute("alt", "no image");
                    img.setAttribute("height", "120px");
                    img.setAttribute("width", "120px");
                    document.getElementById(id_div).appendChild(img);
        
                    var array = ["Carbon Steel","Stainless Steel","Aluminium"];
        
                    var selectMaterial = document.createElement("select");
                    document.getElementById(id_div).appendChild(selectMaterial);
        
                    
                    for (var i = 0; i < array.length; i++) {
                       var option = document.createElement("option");
                       option.value = array[i];
                       option.text = array[i];
                       selectMaterial.appendChild(option);
                    }
        
                    
                    var selectThickness = document.createElement("select");
                    document.getElementById(id_div).appendChild(selectThickness);
        
                    for (i = 1; i <= 16; i++) {
                        var opt = document.createElement('option');
                        //opt.value = i;
                        opt.innerHTML = i + ' mm';
                        selectThickness.appendChild(opt);
                    }
                    
                    var quantity = document.createElement("input")
                    quantity.type="number";
                    quantity.value="1";
                    quantity.name="quantity";
                    quantity.min="1";
                    quantity.max="50";
                    quantity.onkeyup= function maxReach(){if(quantity.value > 50) quantity.value=50;}; 
                    document.getElementById(id_div).appendChild(quantity);
        
        
                    var btn = document.createElement("button");
                    btn.innerHTML = "Delete";
                    btn.type = "button";
                    document.getElementById(id_div).appendChild(btn);
        
                    btn.onclick = function() {div.remove();};
        
                    
        
                }
                </script> 
                    {{ html | safe }}
        </div>

</form>
...

Python

@app.route('/upload_files', methods=['POST'])
def upload_files():
     try: 
       if request.method == 'POST':
        dxf_file = request.files['dxfUpload']
        full_filename = os.path.join(app.config['UPLOAD_FOLDER'],dxf_file.filename)
        dxf_file.save(full_filename)
        first =  DXF2IMG()
        first.convert_dxf2img([full_filename],img_format='.png')
        
        html="<img src="+url_for('static', filename=dxf_file.filename+'.png' )+" width='120' height='120' />"
        
        return render_template('upload_files.html',dxfName=dxf_file.filename, html=html)
     except:
        ... 
        #something happens

The result now

Desired result



Solution 1:[1]

Once the form.submit() function is executed, the form will be sent as a regular post request. For this reason, the following function is no longer executed and the entire page is reloaded.

In order to submit the form and change the content of the existing page, it is necessary to use AJAX.

This example shows you how to submit the form to the server and receive a JSON response containing the URLs of the received file and the generated image.
As soon as the submit button is pressed, the form data is packed into a FormData object and sent via AJAX using the fetch function. The browser's default behavior for a submit event is suppressed and the form is reset. The received file is processed by the server and the associated URLs are sent back to the client in JSON format. Now the document can be changed with the received data.

Remember this is just a minimal example to help you achieve your goals and implement your concept.

Flask (app.py)

import os
import ezdxf
from ezdxf.addons.drawing import matplotlib
from flask import Flask
from flask import (
    jsonify,
    make_response,
    render_template,
    url_for
)
from werkzeug.utils import secure_filename


app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

def dxf2png(source, target):
    doc = ezdxf.readfile(source)
    msp = doc.modelspace()
    auditor = doc.audit()
    if auditor.has_errors:
        raise Exception('Conversion failed.')
    matplotlib.qsave(doc.modelspace(), target)

@app.route('/upload', methods=['POST'])
def upload():
    if 'dxf-file' in request.files:
        file = request.files['dxf-file']
        if file.filename != '':
            filename = secure_filename(file.filename)
            filepath = os.path.join(app.static_folder, filename)
            destname, _ = os.path.splitext(filename)
            destname = f'{destname}.png'
            destpath = os.path.join(app.static_folder, destname)
            file.save(filepath)
            try:
                dxf2png(filepath, destpath)
            except:
                os.remove(filepath)
                return make_response('', 400)
            return make_response(
                jsonify(
                    target=url_for('static', filename=filename),
                    preview=url_for('static', filename=destname)
                ),
                200
            )
    return make_response('', 400)

HTML (templates/index.html)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Index</title>
    <style media="screen">
      .preview {
        width: 120px;
        height: auto;
      }
    </style>
  </head>
  <body>
    <form name="dxf-upload" method="post" enctype="multipart/form-data">
      <input type="file" name="dxf-file" />
      <input type="submit" />
    </form>

    <div id="dxf-files"></div>

    <script type="text/javascript">
      ((uri) => {
        function createPreview(target, preview) {
          const divElem = document.createElement('div');
          divElem.innerHTML = `<a href="${target}"><img src="${preview}" class="preview" /></a>`;
          const outElem = document.getElementById('dxf-files');
          outElem.append(divElem);
        }

        const form = document.querySelector('form[name="dxf-upload"]');
        form.addEventListener('submit', evt => {
          evt.preventDefault();
          const formData = new FormData(evt.target);
          fetch(uri, {
            method: 'POST',
            body: formData
          }).then(resp => resp.json())
            .then(data => {
              const { target, preview } = data;
              createPreview(target, preview);
            });
          evt.target.reset();
        });
      })({{ url_for('.upload') | tojson }});
    </script>
  </body>
</html>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1