WEB🔨/자바스크립트

[JavaScript] MyBookList App with Vanila JavaScript

최문경 블로그 2020. 3. 4. 19:30

https://www.youtube.com/watch?v=JaMCxVWtW58&t=100s

 

위의 영상을 보고 정리한 내용입니다.

 

마크업

css는 bootstrap과 fontawesome을 사용해줍니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="bootstrap.min.css">
  <script src="https://kit.fontawesome.com/d7f530ec10.js" crossorigin="anonymous"></script>
  <title>My BookList App</title>
</head>
<body>
  <div class="container mt-4">
    <h1 class="display-4 text-center">
      <i class="fas fa-book-open text-primary"></i> My<span class="text-primary">Book</span>List
    </h1>
    <form id="book-form">
      <div class="form-group">
        <label for="title">Title</label>
        <input type="text" id="title" class="form-control">
      </div>
      <div class="form-group">
        <label for="author">Author</label>
        <input type="text" id="author" class="form-control">
      </div>
      <div class="form-group">
        <label for="isbn">ISBN#</label>
        <input type="text" id="isbn" class="form-control">
      </div>
      <input type="submit" value="Add Book" class="btn btn-primary btn-block">
    </form>
    <table class="table table-striped mt-5">
      <thead>
        <tr>
          <th>Title</th>
          <th>Author</th>
          <th>ISBN#</th>
          <th></th>
        </tr>
      </thead>
      <tbody id="book-list"></tbody>
    </table>
  </div>
  <script src="app.js"></script>
</body>
</html>

 

 

 


JavaScript

위의 영상에서는 객체 지향으로 자바스크립트 코드를 짰다.

먼저, 여러 개의 Book을 만들 수 있도록 Book class를 만든다.

// Book Class: Represents a Book
class Book {
  constructor(title, author, isbn) {
    this.title = title;
    this.author = author;
    this.isbn = isbn;
  }
}

 

 

 

그리고 UI에 변화를 주는 메소드들을 가지고 있는 UI class를 만든다.

// UI class: Handle UI Tasks
class UI {
  static displayBooks() {
    const books = Store.getBooks();
    books.forEach((book) => UI.addBookToList(book));
  }

  static addBookToList(book) {
    const list = document.querySelector('#book-list');
    const row = document.createElement('tr');

    row.innerHTML = `
      <td>${book.title}</td>
      <td>${book.author}</td>
      <td>${book.isbn}</td>
      <td><a href="#" class="btn btn-danger btn-sm delete">X</a></td>
    `

    list.appendChild(row);
  }

  static deleteBook(el) {
    if(el.classList.contains('delete')) {
      el.parentElement.parentElement.remove();
      // Show success message
      UI.showAlert('Book Deleted', 'success');
    }
  }

  static showAlert(message, className) {
    const div = document.createElement('div');
    div.className = `alert alert-${className}`;
    div.appendChild(document.createTextNode(message));
    const container = document.querySelector('.container');
    const form = document.querySelector('#book-form');
    container.insertBefore(div, form);

    // Vanish in 3 seconds
    setTimeout(() => document.querySelector('.alert').remove(), 3000);
  }

  static clearFields() {
    document.querySelector('#title').value = '';
    document.querySelector('#author').value = '';
    document.querySelector('#isbn').value = '';
  }
}

 

 

 

 

새로고침을 해도 정보가 사라지지 않도록 하는 Store class

// Store Class: Handles Storage
class Store {
  static getBooks() {
    let books;
    if(localStorage.getItem('books') === null) {
      books = [];
    } else {
      books = JSON.parse(localStorage.getItem('books'));
    }

    return books;
  }

  static addBook(book) {
    const books = Store.getBooks();
    books.push(book);
    localStorage.setItem('books', JSON.stringify(books));
  }

  static removeBook(isbn) {
    const books = Store.getBooks();

    books.forEach((book, index) => {
      if(book.isbn === isbn) {
        books.splice(index, 1);
      }
    });

    localStorage.setItem('books', JSON.stringify(books));
  }
}

 

 

 

이벤트 추가 (submit, click)

submit: 사용자가 정보를 입력한 후 submit

click: 사용자가 delete버튼을 클릭했을 때

// Event: Add a Book
document.querySelector('#book-form').addEventListener('submit', (e) => {
  // Prevent actual submit
  e.preventDefault();

  // Get form values;
  const title = document.querySelector('#title').value;
  const author = document.querySelector('#author').value;
  const isbn = document.querySelector('#isbn').value;

  // Validate
  if (title === '' || author === '' || isbn === '') {
    UI.showAlert('Please fill in all fields', 'danger');
  } else {
    // Instatiate book
    const book = new Book(title, author, isbn);

    // Add Book to UI
    UI.addBookToList(book);

    // Add book to store
    Store.addBook(book);

    // Show success message
    UI.showAlert('Book Added', 'success');

    // Clear fields
    UI.clearFields();
  }
})

// Event: Remove a Book
document.querySelector('#book-list').addEventListener('click', (e) => {
  // Remove book from UI
  UI.deleteBook(e.target);

  // Remove book from store
  Store.removeBook(e.target.parentElement.previousElementSibling.textContent);
})