Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 31

Updating Web Content with JSON Data

Recommended resources

Hello! Let's get started on the next part of our journey.

In the last lesson, we built the essential communication link between the browser (client) and our Python code (server). You learned how to use the JavaScript fetch API to send the user's input from a textarea to a Flask endpoint. We confirmed it worked by seeing the data arrive in our server's terminal and by logging the server's JSON response to the browser's console.

Right now, that response just disappears into the console. The user never sees it. Today, we will complete the loop. You will learn how to take that successful JSON response from the server and use it to dynamically update the content of your webpage. This is the key to making your application feel fast and interactive, providing results without ever needing a full page reload.

From Raw Response to Usable Data

When fetch gets a response from the server, it doesn't immediately give you the JSON data. It gives you a Response object, which is a sort of package containing all the details about the response (like the status code we saw last time).

To get our data, we need to "unpack" it. We do this by calling the .json() method on the response object. This method reads the response, parses it as JSON, and returns it as a JavaScript object we can finally work with. Because this parsing can take a moment, .json() also returns a Promise, which is why we chain another .then() block.

Let's look at our script.js from last time:

fetch('/api/analyze', { /* ... options ... */ })
  .then(response => response.json()) // <-- This step unpacks the JSON
  .then(data => {                   // <-- Now 'data' is a usable JavaScript object
      console.log('Success:', data);
  })

The following video provides a clear, quick explanation of this process.

How to FETCH data from an API using JavaScript â†Šī¸

The video 'How to FETCH data from an API using JavaScript' by Bro Code clearly illustrates how to take the raw response from fetch, convert it into a usable JSON object with .json(), and then access the properties of that object.

Watch from 03:01 to 04:27. Pay close attention to the two-step process: first getting the response and then using response.json() to get the data.

Once you are inside that second .then() block, data is a JavaScript object. If our Flask server sent back {'word_count': 10, 'char_count': 52}, you can access these values in JavaScript using dot notation:

  • data.word_count would give you 10.
  • data.char_count would give you 52.

Updating the Webpage with Data

Now that we have the data, we need to display it. The general process is:

  1. Select the HTML element where you want to show the result.
  2. Change its content to include the data you received.

Let's add a place in our index.html to show the results. We can add a div for this purpose right after the form.

<!-- in templates/index.html -->
<form id="text-form">
    <textarea id="user-text" placeholder="Enter your text here..."></textarea>
    <button type="submit">Analyze Text</button>
</form>

<!-- Add this new div -->
<div id="result-container">
    <!-- Analysis results will appear here -->
</div>

Now, in our JavaScript, we can select this div and change its content. The simplest way is to update its textContent property.

The following article gives a perfect, concise example of this whole process.

JavaScript Fetch API For Beginners – Explained With Code ...

The article 'JavaScript Fetch API For Beginners' from freeCodeCamp provides a very clear, text-based example of fetching data and then using document.querySelector and .textContent to update elements on the page.

Read the section 'How to Send a GET Request Using the Fetch API'. Focus on the part after the JSON data is received, where the code uses document.querySelector('#user-name').textContent = data.name to update the HTML.


Building More Complex HTML

Sometimes, just setting text isn't enough. You might want to build a more structured output with multiple lines, headings, or other HTML tags. For this, you can use the .innerHTML property combined with template literals (strings enclosed in backticks `). This lets you construct an HTML string with your data embedded directly in it.

The video below shows an excellent example of this, where an entire table is built by looping through JSON data and creating a long string of HTML.

GET Data from API & Display in HTML | JavaScript Fetch API

This video, 'GET Data from API & Display in HTML' by Manoj Deshwal, is a fantastic demonstration of building complex HTML dynamically. It shows how to iterate over JSON data and use template literals to construct table rows.

Watch from 08:15 to 14:28. You don't need to worry about the forEach loop for now, but focus on how he builds the rows variable using backticks () and ${...}placeholders, and then sets theinnerHTML` of the table body.

Dynamic Table from JSON Data
This is the kind of dynamic content you can create by processing JSON data and updating the `innerHTML` of an element.

Putting It All Together in Our Project

Let's apply this to our AI Writing Assistant. We'll update our Flask app to perform a simple analysis (word and character count) and return that data. Then, we'll update our JavaScript to display it.

1. Update app.py

Modify your analyze_text function to calculate the counts and return them in the JSON response.

# in app.py

@app.route('/api/analyze', methods=['POST'])
def analyze_text():
    data = request.get_json()
    text_from_user = data.get('text', '')

    # Perform a simple analysis
    word_count = len(text_from_user.split())
    char_count = len(text_from_user)

    print(f"Analyzed text. Words: {word_count}, Chars: {char_count}")

    # Create the response object
    response_data = {
        'status': 'success',
        'word_count': word_count,
        'char_count': char_count
    }
    return jsonify(response_data)

Don't forget to restart your Flask server after making this change!

2. Update templates/index.html

Make sure you've added the result-container div as shown earlier.

3. Update static/js/script.js

Now, we'll modify the second .then() block to update the new div instead of just logging to the console.

// in static/js/script.js

document.addEventListener('DOMContentLoaded', () => {
    const textForm = document.getElementById('text-form');
    // Get a reference to our new result container
    const resultContainer = document.getElementById('result-container');

    textForm.addEventListener('submit', (event) => {
        event.preventDefault();
        const userText = document.getElementById('user-text').value;
        const data = { text: userText };

        fetch('/api/analyze', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
        })
        .then(response => response.json())
        .then(data => {
            // Instead of console.log, let's update the webpage!
            console.log('Success:', data); // Keep this for debugging

            // Use a template literal to create our result HTML
            const resultHTML = `
                <h3>Analysis Complete</h3>
                <p>Word Count: ${data.word_count}</p>
                <p>Character Count: ${data.char_count}</p>
            `;

            // Set the innerHTML of our result container
            resultContainer.innerHTML = resultHTML;
        })
        .catch((error) => {
            console.error('Error:', error);
            // We'll handle showing errors to the user in the next lesson
        });
    });
});

Now, run your app. Type some text and click "Analyze Text". You should see the word and character counts appear on the page right below the button!

Test your understanding!

Let's say our Flask app also returned the original text in its response, like this: {'status': 'success', 'word_count': 5, 'char_count': 23, 'original_text': 'This is the user text.'}.

How would you modify the resultHTML variable in your script.js to also display the original text in a blockquote?

Show answer

You would access data.original_text and add a <blockquote> tag to your template literal.

const resultHTML = `
    <h3>Analysis Complete</h3>
    <p>Word Count: ${data.word_count}</p>
    <p>Character Count: ${data.char_count}</p>
    <h4>Original Text:</h4>
    <blockquote>${data.original_text}</blockquote>
`;

Conclusion

Excellent work! You have now fully connected the dots between the frontend and the backend. The user can input data, your server can process it, and the results are shown back to the user instantly.

Key Takeaways:

  • The response.json() method is crucial for converting the server's raw response into a usable JavaScript object.
  • Once parsed, you can access data from the response using dot notation (e.g., data.word_count).
  • You can update the webpage by selecting an element (document.getElementById) and changing its content.
  • Use .textContent for simple text updates.
  • Use .innerHTML with template literals (backticks `) to construct and display more complex HTML.

You've mastered handling the "happy path"—when everything works correctly. But what happens if the user's internet disconnects, or our server has a problem? In the next lesson, we'll learn how to handle network and server errors gracefully during a fetch request.