# Build a Banking App Part 1: HTML Templates and Routes in a Web App
# 은행 앱 제작하기 파트 1: 웹 앱의 HTML 템플릿과 라우터
## Pre-Lecture Quiz
## 강의 전 퀴즈
[Pre-lecture quiz](.github/pre-lecture-quiz.md)
### Introduction
### 소개
Since the advent of JavaScript in browsers, websites are becoming more interactive and complex than ever. Web technologies are now commonly used to create fully functional applications that runs directly into a browser that we call [web applications](https://en.wikipedia.org/wiki/Web_application). As Web apps are highly interactive, users do not want to wait for a full page reload every time an action is performed. That's why JavaScript is used to update the HTML directly using the DOM, to provide a smoother user experience.
In this lesson, we're going to lay out the foundations to create bank web app, using HTML templates to create multiple screens that can be displayed and updated without having to reload the entire HTML page.
### Prerequisite
### 준비물
You need a local web server to test the web app we'll build in this lesson. If don't have one, you can install [Node.js](https://nodejs.org) and use the command `npx lite-server` from your project folder. It will create a local web server and open your app in a browser.
### Preparation
### 준비
On your computer, create a folder named `bank` with a file named `index.html` inside it. We'll start from this HTML [boilerplate](https://en.wikipedia.org/wiki/Boilerplate_code):
@ -34,7 +34,7 @@ On your computer, create a folder named `bank` with a file named `index.html` in
---
## HTML templates
## HTML 템플릿
If you want to create multiples screens for a web page, one solution would be to create one HTML file for every screen you want to display. However, this solution comes with some inconvenience:
@ -43,7 +43,7 @@ If you want to create multiples screens for a web page, one solution would be to
Another approach is have only one HTML file, and define multiple [HTML templates](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) using the `<template>` element. A template is a reusable HTML block that is not displayed by the browser, and needs to be instantiated at runtime using JavaScript.
### Task
### 작업
We'll create a bank app with two screens: the login page and the dashboard. First, let's add in the HTML body a placeholder element that we'll use to instantiate the different screens of our app:
@ -101,7 +101,7 @@ Then we'll add another HTML template for the dashboard page. This page will cont
✅ Why do you think we use `id` attributes on the templates? Could we use something else like classes?
## Displaying templates with JavaScript
## JavaScript로 템플릿 출력하기
If you try your current HTML file in a browser, you'll see that it get stuck displaying `Loading...`. That's because we need to add some JavaScript code to instantiate and display the HTML templates.
@ -113,7 +113,7 @@ Instantiating a template is usually done in 3 steps:
✅ Why do we need to clone the template before attaching it to the DOM? What do you think would happen if we skipped this step?
### Task
### 작업
Create a new file named `app.js` in your project folder and import that file in the `<head>` section of your HTML:
@ -143,7 +143,7 @@ updateRoute('login');
✅ What's the purpose of this code `app.innerHTML = '';`? What happens without it?
## Creating routes
## 라우터 생성하기
When talking about a web app, we call *Routing* the intent to map **URLs** to specific screens that should be displayed. On a web site with multiple HTML files, this is done automatically as the file paths are reflected on the URL. For example, with these files in your project folder:
However, for our web app we are using a single HTML file containing all the screens so this default behavior won't help us. We have to create this map manually and perform update the displayed template using JavaScript.
### Task
### 작업
We'll use a simple object to implement a [map](https://en.wikipedia.org/wiki/Associative_array) between URL paths and our templates. Add this object at the top of your `app.js` file.
@ -193,7 +193,7 @@ Here we mapped the routes we declared to the corresponding template. You can try
✅ What happens if you enter an unknown path in the URL? How could we solve this?
## Adding navigation
## 네비게이션 추가하기
The next step for ou app is to add the possibility to navigate between pages without having to change the URL manually. This implies two things:
@ -206,7 +206,7 @@ While the HTML anchor element [`<a>`](https://developer.mozilla.org/en-US/docs/W
Instead we'll have to use JavaScript and more specifically the [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) that allows to update the URL and create a new entry in the browsing history, without reloading the HTML.
### Task
### 작업
Let's create a new function we can use to navigate in our app:
@ -249,7 +249,7 @@ Try clicking on these buttons, you should be now able to navigate between the di
✅ The `history.pushState` method is part of the HTML5 standard and implemented in [all modern browsers](https://caniuse.com/?search=pushState). If you're building a web app for older browsers, there's a trick you can use in place of this API: using a [hash (`#`)](https://en.wikipedia.org/wiki/URI_fragment) before the path you can implement routing that works with regular anchor navigation and does not reload the page, as it's purpose was to create internal links within a page.
## Handling the browser's back and forward buttons
## 브라우저의 뒤로가기와 앞으로가기 버튼 제어하기
Using the `history.pushState` creates new entries in the browser's navigation history. You can check that by holding the *back button* of your browser, it should display something like this:
@ -259,7 +259,7 @@ If you try clicking on the back button a few times, you'll see that the current
That's because don't know that we need to call `updateRoute()` every time the history changes. If you take a look at the [`history.pushState` documentation](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState), you can see that if the state changes - meaning that we moved to a different URL - the [`popstate`](https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event) event is triggered. We'll use that to fix that issue.
### Task
### 작업
To make sure the displayed template is updated when the browser history changes, we'll attach a new function that calls `updateRoute()`. We'll do that at the bottom of our `app.js` file:
@ -278,18 +278,18 @@ Now try to use the back and forward buttons of your browsers, and check that the
---
## 🚀 Challenge
## 🚀 도전
Add a new template and route for a third page that shows the credits for this app.
## Post-Lecture Quiz
## 강의 후 퀴즈
[Post-lecture quiz](.github/post-lecture-quiz.md)
## Review & Self Study
## 리뷰 & 자기주도 학습
Routing is one of the surprisingly tricky parts of web development, especially as the web moves from page refresh behaviors to Single Page Application page refreshes. Read a little about [how the Azure Static Web App service](https://docs.microsoft.com/en-us/azure/static-web-apps/routes) handles routing. Can you explain why some of the decisions described on that document are necessary?
# Build a Banking App Part 2: Build a Login and Registration Form
# 은행 앱 제작하기 파트 2: 로그인과 가입 폼 작성하기
## Pre-Lecture Quiz
## 강의 전 퀴즈
[Pre-lecture quiz](.github/pre-lecture-quiz.md)
### Introduction
### 소개
In almost all modern web apps, you can create an account to have your own private space. As multiple users can access a web app at the same time, you need a mechanism to store each user personal data separately and select which information to display information. We won't cover how to manage [user identity securely](https://en.wikipedia.org/wiki/Authentication) as it's an extensive topic on its own, but we'll make sure each user is able to create one (or more) bank account on our app.
In this part we'll use HTML forms to add login and registration to our web app. We'll see how to send the data to a server API programmatically, and ultimately how to define basic validation rules for user inputs.
### Prerequisite
### 준비물
You need to have completed the [HTML templates and routing](../1-template-route/README.md) of the web app for this lesson. You also need to install [Node.js](https://nodejs.org) and [run the server API](../api/README.md) locally so you can send data to create accounts.
@ -23,7 +23,7 @@ curl http://localhost:5000/api
---
## Form and controls
## 폼과 컨트롤
The `<form>` element encapsulates a section of an HTML document where the user can input and submit data with interactive controls. There are all sorts of user interface (UI) controls that can be used within a form, the most common one being the `<input>` and the `<button>` elements.
@ -45,7 +45,7 @@ The `<button>` element within a form is a bit special. If you do not specify its
- `reset`: The button resets all the form controls to their initial values.
- `button`: Do not assign a default behavior when the button is pressed. You can then assign custom actions to it using JavaScript.
### Task
### 작업
Let's start by adding a form to the `login` template. We'll need a *username* field and a *Login* button.
@ -93,7 +93,7 @@ Notice also that the input for `balance` has the `number` type. Does it look dif
✅ Can you navigate and interact with the forms using only a keyboard? How would you do that?
## Submitting data to the server
## 서버에 데이커 제출하기
Now that we have a functional UI, the next step is to send the data over to our server. Let's make a quick test using our current code: what happens if you click on the *Login* or *Register* button?
@ -111,7 +111,7 @@ That's why you can change it to use the [POST method](https://www.w3.org/Protoco
> While POST is the most commonly used method to send data over, [in some specific scenarios](https://www.w3.org/2001/tag/doc/whenToUseGet.html) it is preferable to use the GET method, when implementing a search field for example.
### Task
### 작업
Add `action` and `method` properties to the registration form:
@ -127,7 +127,7 @@ If everything goes well, the server should answer your request with a [JSON](htt
✅ Try registering again with the same name. What happens?
## Submitting data without reloading the page
## 페이지를 다시 불러오지 않고 데이터 제출하기
As you probably noticed, there's a slight issue with the approach we just used: when submitting the form, we get out of our app and the browser redirects to the server URL. We're trying to avoid all page reloads with our web app, as we're makng a [Single-page application (SPA)](https://en.wikipedia.org/wiki/Single-page_application).
@ -137,7 +137,7 @@ To send the form data to the server without forcing a page reload, we have to us
- Convert and encode the form data to a suitable format
- Create the HTTP request and send it to the server
### Task
### 작업
Replace the registration form `action` with:
@ -223,7 +223,7 @@ That was a bit long but we got there! If you open your [browser developer tools]
✅ Do you think the data is sent to the server securely? What if someone what was able to intercept the request? You can read about [HTTPS](https://en.wikipedia.org/wiki/HTTPS) to know more about secure data communication.
## Data validation
## Data 검증하기
If you try to register a new account without setting an username first, you can see that the server returns an error with status code [400 (Bad Request)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).).
@ -237,7 +237,7 @@ Before sending data to a server it's a good practice to [validate the form data]
> Tip: you can customize the look of your form controls depending if they're valid or not using the `:valid` and `:invalid` CSS pseudo-classes.
### Task
### 작업
There are 2 required fields to create a valid new account, the username and currency, the other fields being optional. Update the form in the HTML to reflect that:
@ -269,7 +269,7 @@ Usually both need to be implemented, and while using client-side validation impr
---
## 🚀 Challenge
## 🚀 도전
Show an error message in the HTML if the user already exists.
@ -277,14 +277,14 @@ Here's an example of what the final login page can look like after a bit of styl
![Screenshot of the login page after adding CSS styles](./images/result.png)
## Post-Lecture Quiz
## 강의 후 퀴즈
[Post-lecture quiz](.github/post-lecture-quiz.md)
## Review & Self Study
## 리뷰 & 자기주도 학습
Developers have gotten very creative about their form building efforts, especially regarding validation strategies. Learn about different form flows by looking through [CodePen](https://codepen.com); can you find some interesting and inspiring forms?
# Build a Banking App Part 3: Methods of Fetching and Using Data
# 은행 앱 제작하기 파트 3: 데이터를 가져오고 사용하는 방식
## Pre-Lecture Quiz
## 강의 전 퀴즈
[Pre-lecture quiz](.github/pre-lecture-quiz.md)
### Introduction
### 소개
At the core of every web application there's *data*. Data can take many forms, but its main purpose is always to display information to the user. With web apps becoming increasingly interactive and complex, how the user accesses and interacts with information is now a key part of web development.
In this lesson, we'll see how to fetch data from a server asynchronously, and use this data to display information on a web page without reloading the HTML.
### Prerequisite
### 준비물
You need to have built the [Login and Registration Form](../2-forms/README.md) part of the web app for this lesson. You also need to install [Node.js](https://nodejs.org) and [run the server API](../api/README.md) locally so you get account data.
@ -23,7 +23,7 @@ curl http://localhost:5000/api
---
## AJAX and data fetching
## AJAX와 데이터 가져오기
Traditional web sites update the content displayed when the user click on a link or submit data using a form, by reloading the full HTML page. Every time new data needs to be loaded, the web server returns a brand new HTML page that needs to be processed by the browser, interrupting the current user action and limiting interactions during the reload. This workflow is also called a *Multi-Page Application* or *MPA*.
@ -37,7 +37,7 @@ When AJAX was first introduced, the only API available to fetch data asynchronou
> While all modern browsers supports the `Fetch API`, if you want your web application to work on legacy or old browsers it's always a good idea to check the [compatibility table on caniuse.com](https://caniuse.com/fetch) first.
### Task
### 작업
In [the previous lesson](../2-forms/README.md) we implented the registration form to create an account. We'll now add code to login using an existing account, and fetch its data. Open the `app.js` file and add a new `login` function:
@ -111,7 +111,7 @@ navigate('/dashboard');
✅ Did you know that by default, you can only call server APIs from the *same domain and port* than the web page you are viewing? This is security mechanism enforced by browsers. But wait, our web app is running on `localhost:3000` whereas the server API is running on ` localhost:5000`, why does it work? By using a technique called [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) it is possible to perform cross-origin HTTP requests is the server add specials headers to the response, allowing exceptions for specific domains.
## Update HTML to display data
## 데이터를 보여주기 위해 HTML 갱신하기
Now that we have the user data, we have to update the existing HTML to display it. We already now how to retrieve element from the DOM using for example `document.getElementById()`. After you have a base element, here are some APIs you can use to modify it or add child elements to it:
@ -121,7 +121,7 @@ Now that we have the user data, we have to update the existing HTML to display i
✅ Using the [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) property of an element it's also possible to change its HTML contents, but this one should avoided as it's vulnerable to [cross-site scripting (XSS)](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) attacks.
### Task
### 작업
Before moving on to the dashboard screen, there's one more thing we should do on the *login* page. Currently, if you try to login with a username that does not exist, a message is shown in the console but for a normal user nothing changes and you don't know what's going on.
@ -159,7 +159,7 @@ Now if you try to login with an invalid account, you should see something like t
Implement the same behavior for the `register` function errors (don't forget to update the HTML).
## Display information on the dashboard
## 대시보드로 정보 출력하기
Using the same techniques we've just seen we'll also take care of displaying the account information on the the dashboard page.
@ -181,7 +181,7 @@ This is what an account object received from the server looks like:
> Note: to make your life easier, you can use the pre-existing `test` account that's already populated with data.
### Task
### 작업
Let's start by replacing the "Balance" section in the HTML to add placeholder elements:
@ -238,13 +238,13 @@ const routes = {
With this change, everytime the dashboard page is displayed then the function `updateDashboard()` is called. After a login, you should then be able to see the account balance, currency and description.
## Create table rows dynamically with HTML templates
## HTML 템플릿으로 동적 테이블 row 만들기
In the [first lesson](../1-template-route/README.md) we used HTML template along with the [`appendChild()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) method to implement the navigation in our app. Templates can also be smaller and used to dynamically populate repetitive parts of a page.
We'll use a similar approach to display the list of transactions in the HTML table.
### Task
### 작업
Add a new template in the HTML `<body>`:
@ -309,7 +309,7 @@ If you try using the `test` account to login, you should now see a transaction l
---
## 🚀 Challenge
## 🚀 도전
Work together to make the dashboard page look like a real banking app. If you already styled your app, try to use [media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries) to create a [responsive design](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Responsive/responsive_design_building_blocks) working nicely on both desktop and mobile devices.
@ -317,10 +317,10 @@ Here's an example of a styled dashboard page:
![Screenshot of an example result of the dashboard after styling](../images/screen2.png)
# Build a Banking App Part 4: Concepts of State Management
# 은행 앱 제작하기 파트 4: 상태 관리의 컨셉
## Pre-Lecture Quiz
## 강의 전 퀴즈
[Pre-lecture quiz](.github/pre-lecture-quiz.md)
### Introduction
### 소개
As a web application grows, it becomes a challenge to keep track of all data flows. Which code gets the data, what page consumes it, where and when does it need to be updated...it's easy to end up with messy code that's difficult to maintain. This is especially true when you need to share data among different pages of your app, for example user data. The concept of *state management* has always existed in all kinds of programs, but as web apps keep growing in complexity it's now a key point to think about during development.
In this final part, we'll look over the app we built to rethink how the state is managed, allowing support for browser refresh at any point, and persisting data across user sessions.
### Prerequisite
### 준비물
You need to have completed the [data fetching](../3-data/README.md) part of the web app for this lesson. You also need to install [Node.js](https://nodejs.org) and [run the server API](../api/README.md) locally so you can manage account data.
@ -23,7 +23,7 @@ curl http://localhost:5000/api
---
## Rethink state management
## 상태 관리에 대하여 다시 생각하기
In the [previous lesson](../3-data/README.md), we introduced a basic concept of state in our app with the global `account` variable which contains the bank data for the currently logged in user. However, our current implementation has some flaws. Try refreshing the page when you're on the dashboard. What happens?
@ -50,7 +50,7 @@ Once you've taken care of these, any other issues you might have may either be f
✅ There are a lot of libraries out there with different approaches to state management, [Redux](https://redux.js.org) being a popular option. Take a look at the concepts and patterns used as it's often a good way to learn what potential issues you may be facing in large web apps and how it can be solved.
### Task
### 작업
We'll start with a bit of refactoring. Replace the `account` declaration:
@ -78,7 +78,7 @@ const account = state.account;
This refactoring by itself did not bring much improvements, but the idea was to lay out the foundation for the next changes.
## Track data changes
## 데이터 변경 추적하기
Now that we have put in place the `state` object to store our data, the next step is centralize the updates. The goal is to make it easier to keep track of any changes and when they happen.
@ -88,7 +88,7 @@ In JavaScript, you can use [`Object.freeze()`](https://developer.mozilla.org/en-
✅ Do you know the difference between a *shallow* and a *deep* immutable object? You can read about it [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#What_is_shallow_freeze).
### Task
### 작업
Let's create a new `updateState()` function:
@ -140,7 +140,7 @@ Try registering a new account, logging out and in again to check that everything
> Tip: you can take a look at all state changes by adding `console.log(state)` at the bottom of `updateState()` and opening up the console in your browser's development tools.
## Persist the state
## 상태 유지하기
Most web apps needs to persist data to be able to work correctly. All the critical data is usually stored on a database and accessed via a server API, like as the user account data in our case. But sometimes, it's also interesting to persist some data on the client app that's running in your browser, for a better user experience or to improve loading performance.
@ -160,7 +160,7 @@ Note that both these APIs only allow to store [strings](https://developer.mozill
✅ If you want to create a web app that does not work with a server, it's also possible to create a database on the client using the [`IndexedDB` API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API). This one is reserved for advanced use cases or if you need to store significant amount of data, as it's more complex to use.
### Task
### 작업
We want our users stay logged in until they explicitly click on the *Logout* button, so we'll use `localStorage` to store the account data. First, let's define a key that we'll use to store our data.
@ -199,7 +199,7 @@ We can also make the *Dashboard* page our application default page, as we are no
Now login in the app and try refreshing the page, you should stay on the dashboard. With that update we've taken care of all our initial issues...
## Refresh the data
## 데이터 새로 고치기
...But we might also have a created a new one. Oops!
@ -218,7 +218,7 @@ The state is persisted indefinitely thanks to the `localStorage`, but that also
One possible strategy to fix that is to reload the account data every time the dashboard is loaded, to avoid stall data.
### Task
### 작업
Create a new function `updateAccountData`:
@ -262,17 +262,17 @@ Try reloading the dashboard now, it should display the updated account data.
---
## 🚀 Challenge
## 🚀 도전
Now that we reload the account data every time the dashboard is loaded, do you think we still need to persist *all the account* data?
Try working together to change what is saved and loaded from `localStorage` to only include what is absolutely required for the app to work.