简体   繁体   English

如何将HTML字符串从flask应用程序传递到HTML模板作为DOM元素,然后是appendChild

[英]How to pass HTML string from flask app to HTML template as a DOM element and then appendChild

CONTEXT CONTEXT

I've created a Flask web app that has a form on the webpage, and then I want the user to see the results of that form immediately to the right of the form. 我创建了一个Flask Web应用程序,在网页上有一个表单,然后我希望用户立即在表单右侧看到该表单的结果。 When the form is submitted, a python script is activated on the backend, and this produces an HTML result file ( authorList.html ) - which is what I want to display next to the form. 提交表单时,会在后端激活python脚本,这会生成一个HTML结果文件( authorList.html ) - 这是我想要在表单旁边显示的内容。

PROBLEM 问题

From what I understand, this requires me to use Ajax, so I can get results without refreshing the page, but I'm not as familiar with how to pass that HTML result file from the flask app.py to the HTML template and then append that as a node to the DOM tree. 根据我的理解,这需要我使用Ajax,所以我可以在不刷新页面的情况下获得结果,但是我不熟悉如何将HTML结果文件从flask app.py传递到HTML模板然后追加作为DOM树的节点。

1) I have my code set up so far such that the upload route is invoked, which then renders index.html , and then the JS code in there refers back to the results route, which then renders index.html again, passing in the HTML result file as a string. 1)我的代码设置到目前为止,以便调用upload路径,然后呈现index.html ,然后其中的JS代码返回results路由,然后再次呈现index.html ,传入HTML结果文件作为字符串。 I've partially set up the HTML-string-to-DOM-element conversion step in index.html under where it says <p>Results should display here.</p> (as this is the part of the page where I want the HTML result file to display) but am not sure if I'm on the right track and how to proceed with doing appendchild. 我已经在index.html部分设置了HTML-string-to-DOM-element转换步骤,其中<p>Results should display here.</p> (因为这是我想要的页面的一部分)要显示的HTML结果文件)但我不确定我是否在正确的轨道上以及如何继续做appendchild。

2) Also, when I try running this code below the way it is, I get a JS error of Uncaught SyntaxError: Unexpected token ; 2)此外,当我尝试以下方式运行此代码时,我得到了Uncaught SyntaxError: Unexpected token ;的JS错误Uncaught SyntaxError: Unexpected token ; pointing to this line of index.html : var d = document.createElement('div'); d.innerHTML = ; return d.firstChild; 指向index.html这一行: var d = document.createElement('div'); d.innerHTML = ; return d.firstChild; var d = document.createElement('div'); d.innerHTML = ; return d.firstChild; ...is it because I'm not passing in the data variable correctly on the Flask app side? ...是因为我没有在Flask应用程序端正确传递data变量? (RESOLVED AND UPDATED IN CODE ACCORDINGLY) (根据代码解决和更新)

(note: I am not familiar with JS, so if this seems simple, I apologize in advance!) (注意:我不熟悉JS,所以如果这看起来很简单,我会提前道歉!)

SOURCE CODE 源代码

app.py: app.py:

@app.route("/", methods=['GET', 'POST'])
def upload():
    return render_template('index.html', template_file=app.config['TEMPLATE_FILE'])


@app.route("/results", methods=['POST'])
def results():
    data = []
    if request.method == 'POST':
            if request.form['affiliation'] == "letter":
                affiliation = "let"
            elif request.form['affiliation'] == "number":
                affiliation = "num"

            proc = subprocess.Popen('python author_script.py {} -p {} -s {} -m {}'.format(file.filename, period, space, affiliation), shell=True, stdout=subprocess.PIPE)
            while proc.poll() is None:
                time.sleep(0.5)

            # Convert resulting HTML file to a string and pass to index.html
            with open('authorList.html') as f:
                data.append("".join(f.readlines()))
    return render_template('index.html', data=''.join(data))

index.html: index.html的:

<html>

<head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
 <script>
    $(document).ready(function() {
        $('form').submit(function (e) {
            var url = "{{ url_for('results') }}"; 
            $.ajax({
                type: "POST",
                url: url,
                data: $('form').serialize(), 
                success: function (data) {
                    console.log(data) 
                }
            });
            e.preventDefault(); 
        });
    });
</script>

</head>

<body>

<div class="container">
  <div class="row">
    <div class="col-sm-6">
          <div>
            <br>
            <p>Download the template file below and re-upload with your custom author information:</p>
            <a href="static/ExampleAuthorList.txt" download="Authors_Template.txt"><button type="button">Download</button></a><br><br>
            <form action="" id="myform" method=post enctype=multipart/form-data>
            <div id="buttonDiv">
              <p><input type=file name=file value="Choose File">
              <p>Mark affiliations with:</p>
              <input type="radio" name="affiliation" value="number" id="number" class="form-radio" checked><label for="number">Number</label><br>
              <input type="radio" name="affiliation" value="letter" id="letter" class="form-radio"><label for="letter">Letter</label>
              <br><br>
            </div>
            <input type=submit value=Upload></p>
            </form>
          </div>
    </div>
    <div class="col-sm-6">
        <div>
          <p>Results should display here.</p>
          <script>
            var d = document.createElement('div'); d.innerHTML = "{{ data }}"; return d.firstChild;
            # Need code for appending child
          </script>
        </div>
    </div>
  </div>
</div>

</body>

</html>

UPDATE UPDATE

I tried the following change in my JS code (in index.html ) but am still not seeing any results appear on the homepage. 我在我的JS代码中尝试了以下更改(在index.html ),但仍未看到主页上显示任何结果。

  <script>
    var data 
    $(document).ready(function() {
        $('form').submit(function (e) {
            var url = "{{ url_for('results') }}"; // send the form data here.
            $.ajax({
              type: "POST",
              url: url,
              data: $('form').serialize(), 
              success: function (data) {
                var d = document.createElement('div');
                d.innerHTML = data;
                $(".my-results").html(data);
              }
            });
            e.preventDefault(); // block the traditional submission of the form.
        });
    });
</script>

.
.
.
.
        <div>
          <br>
          <p class="my-results">Results should display here.</p>
        </div>
    </div>

UPDATE 2: full app.py 更新2:完整app.py

@app.route("/", methods=['GET', 'POST'])
def upload():
    return render_template('index.html', template_file=app.config['TEMPLATE_FILE'])

@app.route("/results", methods=['GET', 'POST'])
def results():
    if 'file' not in request.files:
        flash('No file chosen', 'danger')
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        flash('No selected file', 'danger')
        return redirect(request.url)
    filename = secure_filename(file.filename)
    if not allowed_file(file.filename):
        flash('Incorrect file extension. Must be .TXT!', 'danger')
    if places_exist(os.path.join(app.config['UPLOAD_FOLDER'], filename)) == False:
        flash('There is an affiliation missing from your Place list. Please re-try.', 'danger')
        return redirect(request.url)
    else:
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

        os.chdir('/Users/cdastmalchi/Desktop/author_script/')

        if request.form['affiliation'] == "letter":
            affiliation = "let"
        elif request.form['affiliation'] == "number":
            affiliation = "num"

        if "Yes sep period" in request.form.getlist('period'):
            period = "y"
        else:
            period = "n"
        if "Yes sep space" in request.form.getlist('space'):
            space = "y"
        else:
            space = "n"

        proc = subprocess.Popen('python author_script.py {} -p {} -s {} -m {}'.format(file.filename, period, space, affiliation), shell=True, stdout=subprocess.PIPE)
        # Wait until process terminates
        while proc.poll() is None:
            time.sleep(0.5)

        with open("authorList.html") as f:
            data = ''.join(f.readlines())
            print(data)
        return data

To fix your syntax error put quotes around {{ data }} . 要修复语法错误,请在{{ data }}周围加上引号。

d.innerHTML = "{{ data }}";

Without the quotes the result is 如果没有引号,结果就是

d.innerHTML = ;

But don't worry because you need to move that code anyway. 但不要担心,因为无论如何你需要移动该代码。

The JavaScript in the second <script> tag doesn't know about the data because it is out of scope. 第二个<script>标记中的JavaScript不知道data因为它超出了范围。 You need to move that code into your $.ajax success method. 您需要将该代码移动到$.ajax成功方法中。 This should work better: 这应该更好:

$.ajax({
  type: "POST",
  url: url,
  data: $('form').serialize(), 
  success: function (data) {
    var d = document.createElement('div');
    d.innerHTML = data;
  }
});

To upload a file dynamically, you need to use the FormData object in Javascript with a POST request. 要动态上载文件,您需要在Javascript中使用带有POST请求的FormData对象。 This solution sends two separate requests: the POST request with the file data, and a GET request with the additional values. 此解决方案发送两个单独的请求:带有文件数据的POST请求和带有GET请求。 The filename is stored in flask.session to be used in the context of the GET request when the final data is computed: 文件名存储在flask.session ,以便在计算最终数据时在GET请求的上下文中使用:

First, in your app.py , you need three routes: a route to render index.html , a route to handle the file data, and lastly, a route to return the html: 首先,在你的app.py ,你需要三个路径:一个呈现index.html的路由,一个处理文件数据的路由,最后一个返回html的路由:

app.py : app.py

import flask, string, random
import json
app = flask.Flask(__name__)
app.secret_key = ''.join(random.choice(string.ascii_letters) for _ in range(20)) #needed to use flask.session
@app.route('/', methods=['GET'])
def home():
   return flask.render_template('index.html')

@app.route('/process_file', methods=['POST'])
def process_file():
  #here, you can run all the checks as before, but instead of flash, you can return jsonified results to read in the front-end
  if 'file' not in flask.request.files or not flask.request.files['file'].filename:
     return flask.jsonify({'result':'False', 'message':'no files selected'})
  file = flask.request.files['file']
  filename = secure_filename(file.filename)
  if not allowed_file(file.filename):
     return flask.jsonify({'result':'False', 'message':'Must be TXT file!'})
  if not places_exist(os.path.join(app.config['UPLOAD_FOLDER'], filename)):
     return flask.jsonify({'result':'False', 'message':'There is an affiliation missing from your Place list. Please re-try.'})
  file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
  flask.session['filename'] = filename
  return flask.jsonify({'result':'True'})

@app.route('/upload_vals')
def upload_vals():
  payload = json.loads(flask.request.args.get('payload'))
  #do something with payload
  #payload will now be in the form:
  #{'affiliation':'Number', 'period':'no', 'space':'yes'}
  proc = subprocess.Popen('python author_script.py {} -p {} -s {} -m {}'.format(flask.session['filename'], 'y' if _checked['period'] else 'n', 'y' if _checked['space'] else 'n', aff[:3]), shell=True, stdout=subprocess.PIPE)
  while proc.poll() is None:
     time.sleep(0.5)
  with open("authorList.html") as f:
    data = ''.join(f.readlines())
  return flask.jsonify({'data':data})

index.html : index.html

<html>
 <head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  </head>
  <body>
  </body>
    <div class='wrapper'>
      <p>Download the template file below and re-upload with your custom author information:</p>
      <a href="static/ExampleAuthorList.txt" download="Authors_Template.txt"><button type="button">Download</button></a><br><br>
        <form action="" id="myform" method=post enctype=multipart/form-data>
        <input type=file name=file value="Choose File">
           <p class='error_message'></p>
        </form>
         <div id="buttonDiv"> 
            <p>Mark affiliations with:</p> 
            <input type="radio" name="affiliation" value="number" data-key='affiliation' data-value='number' class="form-radio main_checkbox" checked><label for="number">Number</label><br> 
            <input type="radio" name="affiliation" value="letter" data-key='affiliation' data-value='letter' class="form-radio main_checkbox"><label for="letter">Letter</label><br> 
           <p>Separate initials with period:</p> 
           <input type="radio" name="period" value="separated" data-key='period' data-value='yes' class="form-radio period"><label for="period">Yes</label><br> 
           <input type="radio" name="period" data-key='period' data-value='no' value="separated" class="form-radio period" checked><label for="period">No</label> 
           <br> 
           <p>Separate initials with space:</p> 
           <input type="radio" name="space" value="separated" data-key='space' data-value='yes' class="form-radio spacing"><label for="space">Yes</label><br> 
           <input type="radio" name="space" data-key='space' data-value='no' value="separated" class="form-radio spacing" checked><label for="space">No</label><br> 
          <br><br> 
         </div> 
        <button class='submit_data'>Submit</button>
        <div>
         <br>
         <p class="my-results"></p>
        </div>
      </div>
    <script>
      $(document).ready(function(){
        $('.wrapper').on('click', '.submit_data', function(){
             var form_data = new FormData($('#myform')[0]);
             var flag = true;
             $.ajax({
               type: 'POST',
               url: '/process_file',
               data: form_data,
               contentType: false,
               cache: false,
               processData: false,
               success: function(data) {
                 if (data.result === 'False'){
                    $('.error_message').html(data.message)
                    flag = false;
                 }
              },
           });
           if (flag){
             var payload = {};
             $('.form-radio').each(function(){
                if ($(this).prop('checked')){
                  payload[$(this).data('key')] = $(this).data('value');
                }
             });
             $.ajax({
               url: "/upload_vals",
               type: "get",
               data: {'payload':JSON.stringify(payload)},
               success: function(response) {
                 $(".my-results").html(response.data);
               },
              });
           }
        });
      });
    </script>
</html>

It is slightly unclear in your updated app.py where the period and space form values originate from in the HTML, however, in the the index.html above, two additional checkboxes are provided to receive this value from the user. 在您更新的app.py中稍微不清楚,其中periodspace格式值来自HTML,但是,在上面的index.html ,提供了另外两个复选框以从用户接收此值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM