Welcome to the third lesson in our course on building an image generation web application with Fiber! In our previous lessons, we've built a solid foundation for our application by creating the HTML structure and styling it with CSS. We now have a visually appealing interface with tabs, form elements, and containers for displaying generated images.
However, our application is still static — clicking buttons doesn't do anything, and there's no way to actually generate images or switch between tabs. This is where JavaScript comes in. JavaScript is the programming language that brings web pages to life by adding interactivity and dynamic behavior.
In this lesson, we'll focus on implementing the client-side functionality that will allow users to interact with our application. We'll write JavaScript code to handle tab navigation, capture user input, send requests to our backend API, and display the generated images.
The JavaScript file we'll be creating will serve as the bridge between our user interface and the backend Fiber application. It will handle all the client-side logic, from validating user input to making API calls and updating the DOM based on the responses.
Let's get started by implementing the tab navigation functionality, which will allow users to switch between the "Generate Image" and "View History" tabs.
Our application has two main tabs: "Generate Image" and "View History." We need to implement a function that will show the selected tab and hide the others when a user clicks on a tab button.
Let's create a file named script.js in the static folder of our Fiber application. This is the same folder where we placed our style.css file in the previous lesson.
Now, let's implement the openTab() function that will handle the tab switching:
This function does two main things:
- First, it selects all elements with the class
tab-contentusingdocument.querySelectorAll()and hides them by setting theirdisplaystyle property to'none'. - Then, it selects the specific tab content element with the ID matching the
tabNameparameter usingdocument.getElementById()and shows it by setting itsdisplaystyle property to'block'.
The core functionality of our application is generating images based on user input. We need to implement a function that will capture the user's input, validate it, and send it to our backend API.
Let's add the generateImage() function to our script.js file:
Let's break down this function step by step.
First, we need to retrieve the values from the input fields where the user enters a prompt and selects an aspect ratio:
These values will be included in the request to our backend API.
Next, we get references to the key elements in the UI that we'll need to interact with:
These elements will be used to show a loading state, hide the button, and display the generated image.
Before proceeding, we check that the user has entered a prompt:
This prevents the user from submitting an empty prompt and ensures meaningful input is sent to the backend.
To indicate that the image is being generated, we update the UI accordingly:
This gives the user feedback and prepares the page to display a new image. We'll use the imageContainer to populate the image we receive.
We use the Fetch API to send the user's input to our Fiber backend:
This makes a GET request to the /generate-image endpoint with the prompt and aspect ratio as query parameters. Note that we use encodeURI(URL) to ensure the query parameters are encoded properly. URLs cannot contain special characters; they need to be encoded with encodeURI.
For example, a URL that contains spaces in the prompt might look like this:
After it has been encoded with encodeURI(), it becomes:
Once we receive a response from the backend, we parse the JSON and update the UI:
This code resets the UI, checks for errors, and displays the generated image if the request was successful. The fetch() API returns a response promise which includes the body of the request in a stream. In order to convert it to JSON data, you must call .then(response => response.json()) to extract the full response of the body stream and then receive the promise with the actual body in JSON form.
From there, we can construct a new <IMG> element and apply the Base64 data from the API directly to the image and append it to the imageContainer.
Finally, we handle any unexpected issues that may occur during the request:
This ensures the user is informed and the UI returns to a usable state if something goes wrong.
Now, we're ready to send the request to our backend API. We'll explore this in more detail in the next section.
Congratulations! In this lesson, we've implemented the client-side functionality for our image generation web application. Let's review what we've accomplished:
- We created a JavaScript file to handle the client-side logic of our application.
- We implemented the
openTab()function to allow users to switch between tabs. - We built the
generateImage()function to capture user input, validate it, and send it to our backend API. - We used the Fetch API to make asynchronous requests to our server.
- We processed the API responses and updated the UI to display the generated images.
Our application now has a functional user interface that allows users to generate images based on their input. However, there's still room for improvement. In the next lesson, we'll enhance our application by adding more robust loading states and error handling, as well as implementing the functionality to view previously generated images in the history tab.
In the practice exercises that follow this lesson, you'll have the opportunity to experiment with the JavaScript code we've written. You might try modifying the validation logic, adding additional features, or improving the error handling. These exercises will help reinforce your understanding of the concepts we've covered and give you hands-on experience with client-side JavaScript development.
Remember, JavaScript is a powerful language that can greatly enhance the user experience of your web applications. The skills you're learning in this course will be valuable not only for this specific project but for many other web development tasks you might encounter in the future.
