1

I am building a small web application that allows the user to enter a transaction through a couple form input fields (such as date, transaction amount, description, etc.). Each time the user clicks a "submit" button a new table row will be created with one column for each input field. In addition to building this table, I want the input data to be sent to my Flask app.

The problem I have is that when the user clicks "submit", the page refreshes and all the table rows are gone. The solution I tried for this is to just have a <button type="button"></button> tag with an id, and when the user clicks it my Javascript code adds a table row without refreshing the page. However, this doesn't work because it doesn't send the data to my Flask app. I also tried using sessionStorage.setItem in Javascript but I don't know how to make that work with my specific code, as the user could click the button 3 times for 3 different transactions and each time the page would refresh.

So my question is, how can I create and display the table rows on the page while ALSO sending the form input data to my Flask app?

For simplification, I have only included 2 input fields here, but there are 8.

HTML:

<form method="POST">
  <div class="list-group-item">
    <label>Date</label>
    <input class="form-control" id="datepicker" type="text" name=expDate value="">
  </div>
  <div class="list-group-item">
    <label>Amount Withdrawn</label>
    <input class="form-control" id="withAmount" type="text" name=expAmountWith value="">
  </div>
  <button id="submit-btn" type="submit" class="btn btn-light submit-btn">Submit</button>
</form>

Javascript:

d3.selectAll('#submit-btn').on('click', buildTable);

function buildTable() {
    var dateInput = d3.select('#datepicker').property('value');
    var withAmount = d3.select('#withAmount').property('value');

    var tableArray = []
    tableArray.push(dateInput, withAmount)

    var row = d3.select('tbody').append('tr');

    tableArray.forEach(function(x) {

        var cell = row.append('td');
        cell.text(x);
    });

};

Python:

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def record_transaction():

    form = request.form

    if request.method == 'POST':
        expDate = request.form['expDate']
        expAmountWith = request.form['expAmountWith']

    return render_template('index.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)
Remco Mooij
  • 43
  • 1
  • 1
  • 7
  • Use ajax that's all and just appeand the data. If this is what you mean tell me and I can upload an answer – Patch May 28 '20 at 22:17
  • Yes, I'm just not very familiar yet with ajax. Would be extremely helpful if you could show how to solve my problem with ajax. – Remco Mooij May 28 '20 at 22:55
  • Take a look at this, https://stackoverflow.com/questions/62027285/auto-refresh-div-with-dataframe-every-n-seconds/62028552#62028552 . – Akib Rhast May 28 '20 at 22:56

2 Answers2

8

You can start by getting the form element in your JavaScript code, by assigning an id and using getElementById, or in a way more consistent with the rest of your code (seeing as you are using jQuery, but I prefer vanilla JS). Then, instead of using <button type="button">, you can attach the event listener to the form's submit event, then preventDefault so the page doesn't refresh, and send the data to your backend inside the callback. Here is an example:

form.addEventListener('submit', function(event) {
    event.preventDefault();    // prevent page from refreshing
    const formData = new FormData(form);  // grab the data inside the form fields
    fetch('/', {   // assuming the backend is hosted on the same server
        method: 'POST',
        body: formData,
    }).then(function(response) {
        // do something with the response if needed.
        // If you want the table to be built only after the backend handles the request and replies, call buildTable() here.
    });
});

And I suggest using the same formData object in your buildTable() function so that you don't have to assign an ID to each element and retrieve the value that way, but instead use formData.get(name).

Also, change your Python function to return something at the end of the if request.method == 'POST' branch so it doesn't return the HTML to the AJAX request. Perhaps a "204 - No content" is appriopriate in your simple case.

I trust you know how to replace the plain JS here with jQuery

-2

So in order to do that, you'll need to use an ajax request

d3.selectAll('#submit-btn').on('click', buildTable);
$.post( "/your-url", function( data ) { // data is the variable that the URL returns (that means you can't return render_template you have to return some raw data e.g string, json, int, etc)
     buildTable.append(data);
  });

I don't know exactly what you need to append so I improvised. What you need to do is to append whatever you sent in data to your table it seems like you know how to do it in JQuery already. I'd suggest that data will be JSON or a list. For more information on how to use the ajax post request visit the documentary

Patch
  • 694
  • 1
  • 10
  • 29
  • Please explain how this works and how this would help remeco. – Spacehold Feb 18 '21 at 19:30
  • @Spacehold besides the fact that he already accepted an answer, what is there to explain? My answer seems pretty good to me. There is a link in the answer that explains more about "ajax.post". – Patch Feb 18 '21 at 19:47
  • This was answered before he accepted your answer @Patch – Spacehold Oct 11 '21 at 11:50