OpenJS Architect로 풀 스택 서버리스 영화 추적기를 구축하는 방법 - 2부

27402 단어

점진적 향상 및 클라이언트 측 JS 제공



기본 기능이 완료되었습니다. 이제 JavaScript로 이 양식을 개선하여 체크박스를 클릭할 때 양식을 제출함으로써 감시된 체크박스를 실시간으로 저장하도록 할 차례입니다.

// public/index.js
let forms = document.querySelectorAll("form[action='/watched']")

for (let f of forms) {
  f.querySelector('button').style.display = 'none'
  let check = f.querySelector('input[type="checkbox"]')  
  check.addEventListener('change', function (e) {
    f.submit() 
  }, false)
}


이것은 우리가 만들 수 있는 가장 간단한 점진적 향상 버전입니다. 클라이언트 측 JavavScript는 양식을 선택하고 '저장' 버튼을 숨기고 체크박스에 이벤트 리스너를 추가합니다. 확인란이 변경될 때마다 사용자를 위해 양식을 제출합니다.

별점 및 댓글 추가



우리는 계속해서 응용 프로그램을 더 복잡하게 만들 것입니다. 다음 몇 섹션에서는 "별점 평가"기능과 댓글 시스템을 추가할 것입니다.



먼저 get-index 경로에서 마크업을 변경해 보겠습니다.

// src/http/get-index/index.js

const arc = require('@architect/functions')
const data = require('@begin/data')

exports.handler = arc.http.async(http)

function authControl(account) {
  if (account && account.name) {
    return `
    Welcome back ${account.name}
    <form action=/logout method="post">
    <button>Logout</button>
    </form>`
  } else {
    let clientID = process.env.GITHUB_CLIENT_ID
    let redirectURL = process.env.GITHUB_REDIRECT
    let href = `https://github.com/login/oauth/authorize?client_id=${clientID}&redirect_url=${redirectURL}`
    return `
    <a href='${href}'>Login with GitHub to see a list of movies</a>
    `
  }
}

function movie({ key, watched, title, rating, review }) {

  return `
<form action="/watched" method="post">
  <input type="hidden" name="movieId" value="${key}">
  <input type="checkbox" data-movieid="${key}" name=watched ${watched ? 'checked' : ''}>
  ${title}
  <input type="text" data-movieid="${key}" name="review" placeholder="leave a review here" value="${review || ''}">

  <input type="radio" name="rating" data-movieid="${key}" value="1" ${rating === '1' ? 'checked' : ''}>
  <input type="radio" name="rating" data-movieid="${key}" value="2" ${rating === '2' ? 'checked' : ''}>
  <input type="radio" name="rating" data-movieid="${key}" value="3" ${rating === '3' ? 'checked' : ''}>

  <button class=cage>Save</button>
  </form>`
}

async function getMovies(account) {
  let movies = [
    { key: '001', title: 'Raising Arizona' },
    { key: '002', title: 'Con Air' },
    { key: '003', title: 'National Treasure' },
  ]
  if (account) {
    let accountMovies = await data.get({
      table: `${account.id}-movies`
    })

    let result = ''
    for (let mov of movies) {
      let found = (accountMovies.find(m => m.key === mov.key))
      result += movie({
        key: mov.key,
        title: mov.title,
        watched: !!found,
        rating: found ? found.rating : '',
        review: found ? found.review : ''
      })
    }
    return result
  }
  return ''
}

async function http(req) {

  return {
    html: `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="/_static/index.css">
  <link rel="shortcut icon" href="#">
  <title>Praise Cage</title>
</head>
<body>
<h1>Praise Cage</h1>

${authControl(req.session.account)}
${await getMovies(req.session.account)}

<script src=/_static/index.js type=module></script>
</body>
</html>
`
  }
}


다음으로 post-watched 끝점을 수정할 수 있습니다. 이제 데이터베이스에 저장할 reviewrating 속성을 포함하려고 합니다.

// src/http/post-watched/index.js

const arc = require('@architect/functions')
const data = require('@begin/data')

exports.handler = arc.http.async(route)

async function route(req) {

  console.log('post-watched req.body:', req.body )

  let account = req.session.account.id

  if (req.body.watched) {
    await data.set({
      table: `${account}-movies`,
      key: req.body.movieId,
      review: req.body.review,
      rating: req.body.rating
    })
  } else {
    await data.destroy({
      table: `${account}-movies`,
      key: req.body.movieId
    })
  }

  return {
    location: '/'
  }
}


마지막으로 클라이언트 측 JS를 다음과 같이 업데이트할 수 있습니다.

// public/index.js

let forms = document.querySelectorAll("form[action='/watched']")

console.log(forms)

for (let f of forms) {

  // hide all submit buttons
  f.querySelector('button').style.display = 'none'

  // get a ref to the form checkbox
  let check = f.querySelector('input[type="checkbox"]')

  // get a ref to the form radios
  let radios = f.querySelectorAll('input[type="radio"]')

  // get a ref to the form text
  let text = f.querySelector('input[type="text"]')

  // mutates state
  function changed (e) {

    let movieId = e.target.dataset.movieid
    let payload = { movieId }
    payload.watched = f.querySelector('input[name="watched"]').checked
    payload.review = f.querySelectorAll('input[name="review"]')[0].value

    let rating = f.querySelectorAll('input[name="rating"]:checked')
    payload.rating = rating.length === 1 ? rating[0].value : ''

   //make an HTTP post with fetch

    fetch('/watched', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        'x-nick-cage': 'fetch'
      },
      body: JSON.stringify(payload)
    }).catch(function fail(err) {
      console.log('failed', err)
    })
  }

  // listen to checkbox changes
  check.addEventListener('change', changed, false)

  // listen to radio buttons getting hit
  for (let r of radios) {
    r.addEventListener('input', changed, false)
  }

  // listen to changes to review text
  text.addEventListener('input', changed, false)
}


전체 소스 코드는 여기에서 찾을 수 있습니다: https://github.com/pchinjr/movie-tracker

좋은 웹페이지 즐겨찾기