python and javascript interfering with each other

Question:

(Question edited for clarity and updates). I am building a flask app game in which the user inputs a guess in the web browser, the guess is checked on the back end (with python), and then the user is told if the guess is correct or incorrect. I also have some JavaScript running to display the previous guesses on the page, using local storage. These two code snippets are interfering with each other. In my play.html, I have:

<form action="/play" method ="POST">
      <div class = "form-group">
       <label>This is the input</label>
          <label>
         <input class ="form control" type="text" name="guess" placeholder="Type guess!">
            </label></div>

       <div class="container>"><button type="submit" id="submit">Check Answer</button></div>

Then, in app.py, I have:

    # gets guess and checks against answers, flashes appropriate message
    if request.method == "POST":

        req = request.form

        guess = req.get("guess")

        if guess == ans.next():
            flash("Correct", "success")
            return redirect(request.url)

        flash("Incorrect", "secondary")
        return redirect(request.url)

Then, in my display_guesses.js, I have (along with a lot of other stuff for storing and displaying, which has no problems):

const input = document.getElementsByName('guess');

form.addEventListener('submit', function () {
  displayGuesses.push(input[0].value);
  localStorage.setItem('my_guesses', JSON.stringify(displayGuesses));
  liMaker(input[0].value);
  input[0].value = "";
  form.submit();
});

In theory, this should display the guesses after they are submitted (and it does under certain conditions, see below).

The problem is that only one of these things can work at a time. If I run the code as-is, then the guesses get displayed on the page, but the answer-checking mechanism fails. If I remove the code for displaying guesses, then the answer-checking mechanism works.

It appears that there is some kind of conflict between having JavaScript and Python both trying to do something with the user’s guess on the form. Any ideas on how to solve? I am very new to coding and building the plane as I fly it.

Asked By: daebird

||

Answers:

As already mentioned, python delivers the page and the browser receives and displays it. From then on, JavaScript runs and executes your instructions.

The problem arises in my opinion in your event listener for the submit event. You catch this event, but don’t pay attention to the fact that the form is still submitted by default to the server. Now the browser tries to execute your code on the one hand and to send the form on the other hand. Take a look at the preventDefault() command to prevent the default behavior and run your code.

form.addEventListener('submit', function (event) {
    event.preventDefault();
    // ...
});

The second problem is that you try to change the content of the page and then submit the form, which results in a complete reload of the page, causing the post-injected JavaScript content to disappear. Don’t add the saved guesses until the page reloads.
A possible solution could look like this.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Play</title>
</head>
<body>
    <form method="post">
        <div>
            <label for="guess">This is the input</label>
            <input type="text" name="guess" id="guess" placeholder="Type guess!" />
        </div>
        <button type="submit">Check Answer</button>
    </form>

    <ul id="guesses"></ul>

    <script type="text/javascript" src="{{ url_for('static', filename='display_guesses.js') }}" defer></script>
</body>
</html>
(function() {
    let elem, guesses = JSON.parse(localStorage.getItem('my_guesses')) || [];
    elem = document.getElementById('guesses');
    elem.innerHTML = guesses.map(guess => `<li>${guess}</li>`).join('');

    elem = document.querySelector('form');
    elem.addEventListener('submit', function(evt) {
        evt.preventDefault();
        const guess = this['guess'].value.trim();
        if (guess != '') {
            guesses.push(guess);
            localStorage.setItem('my_guesses', JSON.stringify(guesses));
            this.submit();
        }
    });
})();

At some point you will wonder how to remove the saved data from memory and probably run into another problem. You store your guesses inside the client. The server is the one who decides whether the assumption was correct. So at some point the server has to tell the client when to move on to a new round and discard the previous guesses. In order to solve this problem, you have to rethink your application structure and consider, for example, whether the page really needs to be reloaded or whether the storage location is the right one.

Answered By: Detlef

Detlef’s solution above seems to work, but so does just making sure that what is inputted in the form is actually being caught; solution below

const form = document.querySelector('form');
const ul = document.getElementById('show_guesses');
const input = document.getElementsByName('guess');
let displayGuesses = localStorage.getItem('my_guesses') ? JSON.parse(localStorage.getItem('my_guesses')) : [];

const liMaker = (text) => {
  const li = document.createElement('li');
  li.textContent = text;
  ul.appendChild(li);
}

form.addEventListener('submit', function () {
  displayGuesses.push(input[0].value);
  localStorage.setItem('my_guesses', JSON.stringify(displayGuesses));
  liMaker(input[0].value);
});

data.forEach(guess => {
  liMaker(guess);
});

button.addEventListener('click', function () {
  localStorage.removeItem('my_guesses');
  while (ul.firstChild) {
    ul.removeChild(ul.firstChild);
  }
  displayGuesses = [];
});

The main thing was deleting the input[0].value=" "; which was passing an answer consisting of nothing to be checked agains what’s on the backend.

Play.html, not including a bunch of other code that currently has a "clear guesses" button:

 <div class="container">
    <form action="/play" method ="POST">
       <div class = "form-group">
        <label><b>What's on your Bookshelf today?</b></label>
         <label>
        <input class ="form control" type="text" name="guess" placeholder="Type your guess here!"></label></div>

     <div class="container>"><button type="submit" class="btn btn-secondary" id="submit">Check Answer</button></div>

<div class="container">
        <p><b>Your Guesses So Far</b></p>
    <ul id="show_guesses"></ul>
    </div>

(Edited to remove some irrelevant code that is related to other things going on in the app, but not to the question at hand).

Answered By: daebird
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.