AngularJS를 이용한

Todo app 만들기

Day 1

Conceptual Overview

Dev Environment

  • Angular v1.5
  • Nodejs v6.x
    • node, npm
  • Atom editor
  • Chrome browser
  • Git

Hello world

  • View와 Controller의 관계
  • Data binding
  • Expression
  • ngApp, ngInit
    • git checkout ngInit
  • ngController
    • angular.module()
    • controller()
    • $scope
    • git checkout helloWorld

ECMAScript 6

  • Block scope (let, const)
  • Arrow function
  • Template string
  • Class (getter, setter)
  • Promise

Block Scope

  • var: function scope
  • let: block scope, 가변
  • const: block scope, 불변
function foo() {
  if (false) {
    var a = 1;
  }
  console.log(a);
}

foo(); // undefined
function bar() {
  if (false) {
    let a = 1;
  }
  console.log(a);
}

bar(); // Reference Error
function foo() {
  var a;    
  if (false) {
    a = 1;
  }
  console.log(a);
}

foo(); // undefeind
function bar() {
  if (false) {
    let a;
    a = 1;
  }
  console.log(a);
}

bar(); // Reference Error
const a = 1;

a = 2; 
// TypeError: 
// Assignment to constant variable.

const b; 
// SyntaxError: 
// Missing initializer in const declaration

Arrow Function

 

var foo = function(param) {
  return true;
}
const foo = (param) => {
  return true;
}
const foo = param => true;

let arr = [1,2,3,4,5];
arr.map(m = n * n)
   .filter(n => n % 2 === 0)
   .reduce((r, n) => r + n); // [4, 16]

Template String

  • 코드 가독성 
  • 성능?
const protocol = 'http';
const ip = '127.0.0.1';
const port= 3000;
const resource = 'user';
const id = '402';

let url;
url = protocol + '://' + ip + ':' + port + '/' + resource + '/' + id;
url = `${protocol}://${ip}:${port}/${resource}/${id}`

Class

  • class
  • getter, setter

Promise

  • bluebird
  • q
  • Promise
const async1 = r => {
  return new Promise(rev => {
    setTimeout(() => {
      rev(r)
    }, 1000);
  });
};
const async2 = r  => Promise.resolve(r + 1);
const async3 = r  => Promise.resolve(r + 2);

Promise.resolve(1)
  .then(async1)
  .then(async2)
  .then(async3)
  .then(console.log); // 4

Promise.all([
  async1(1),
  async2(1),
  async3(1),
]).then(console.log); // [1, 2, 3]

Directives ...

  • ngRepeat
  • ngClick
  • Data binding (1way, 2way)
  • Function Components

ngRepeat

ngClick

ngModel

  • Data binding
    • 1 way: ngBind, {{ }}
    • 2 way: ngModel

Function Components

git checkout directives

Make Directives!

  • directive()
  • <todo-item>
  • <todo-form>
  • <todo-filters>
  • <todo-list>

directive()

  • directive('todoItem', ()=> {
      return {
        restrict: 'EA',
        scope: { ... },
        template: `<div></div>`,
        compile: (tElement, tAttrs) => { ... }
        link: (scope, iElement, iAttrs) => { ... },
      }; });
  • git checkout todoItem
  • git checkout todoForm
  • git checkout todoFilters

Make Filters!

  • filter()
  • dateKo
  • timeKo

filter()

  • filter('capitalize', () => {
      return v => {
        if (!v) return '';

        return v.charAt(0).toUpperCase() + v.slice(1);
      };
    });

  • $filter

  • git checkout filters

Day 2

Form

  • style
  • validate
  • custom validator
    • todo-text-validator

Validation

  • 폼 객체의 $error 
  • todo-form directive 개선하기
    • button
    • warning messages
  • git checkout ngForm

Style

  • ngForm
  • ng-minlength, ng-maxlength
  • ng-pristine, ng-dirty, ng-valid, ng-invalid ...
  • 클래스 오버라이딩

Custom Validator

  • 검증자도 일종의 directive
  • require: 'ngModel'
  • modelCtrl
  • git checkout todoTextValidator
directive('todoTextValidator', () => {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: (scope, elem, attrs, modelCtrl) => {
      modelCtrl.$validators.todoText = (modelValue, viewValue) => {
        if (viewValue) return /^(:\w+\s)/.test(viewValue);
      }
    }
  };
});

SPA

  • hashbang, html5 mode
  • ngRoute
  • lite-server

ngRoute

  • ngRoute
    • ngView
    • $routeProvidor
    • $routeParams
    • $localtion.html5Mode()
  • git checkout ngRoute

Single Page App.

  • 브라우져는 하나의 html을 요청
  • 라우팅을 자바스크립트로 처리 (페이지 리프레시 불필요)
  • hashbang
    • https://twitter.com/#!/JeonghwanKim4
    • fragment identifier
  • html5 history api
    • window.pushState()
  • 단점: 자바스크립트 깨지면? 크롤러는?
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>

    <ul>
      <li><a href="africa">Africa</a></li>
      <li><a href="asia">Asia</a></li>
      <li><a href="europe">Europe</a></li>
      <li><a href="north-america">North America</a></li>
      <li><a href="oceania">Oceania</a></li>
      <li><a href="south-america">South America</a></li>
    </ul>

    <div id="content"></div>

    <script type="text/javascript" src="app.js"></script>
  </body>
</html>
const load = country => {
  document.getElementById('content').innerHTML = `${country} is loaded`
  document.title = country;
};

window.addEventListener('click', e => {
  e.preventDefault();
  const country = e.target.text;
  history.pushState({country: country}, `title: ${country}`, country);
  load(country);
});

window.addEventListener('popstate', evt => {
  var state = evt.state;
  if (state !== null) load(state.country)
});

lite-server

  • cors (in chrome)
  • broken links (in safari, firefox)
  • all request → index.html
  • git ckeckout lite-server

Service

  • 어플리케이션의 공유 로직, 싱글톤, DI
  • provider(), factory(), serivce()
  • todoStorage
  • localStorage

서비스 만드는 방법

factory('myService', function() {
  var intstant = {
    users: ['Alice', 'Bek', 'Chris']
  };
  return intstant;
});


factory('myService', function() {
  this.users = ['Alice', 'Bek', 'Chris'];
});

todoStorage

  • 컨트롤러에서 모델을 서비스로 분리
  • git checkout todoStorage

localStorage

  • localStoreage
  • 브라우져의 key/value 저장소
  • localStorage.setItem()
  • localSotrage.getItem()
  • 모두 문자열로 처리함
  • todoStorage와 localStorage 연동
  • update?
  • git checkout localStorage

Asynchronouse

  • Callback style
  • Promise
  • $q
  • $http

Callback

  • Callback style
  • Callback hell
  • 주도권이 없다

Promise

  • 비동기의 주도권을 획득
  • thanble
  • bluebird, q, Promise (es6)

$q

  • $q
  • $q.defer

Day 3

Backend

  • generator-weplajs
  • GET /todos
  • POST /todos
  • PUT /todos
  • DELETE /todos

Ajax

  • $http
  • todoService 개선

$http

$httpProvider.interceptors

$provide.factory('myHttpInterceptor', function() {
  return {
    'request': function(config) {return config;},
    'requestError': function(rejection) {
      return $q.reject(rejection);
    },
    'response': function(response) {return response;},
    'responseError': function(rejection) {
      return $q.reject(rejection);
    }
  };});

$httpProvider.interceptors.push('myHttpInterceptor');

todoService 개선

angular.module('todomvc')
.factory('todoStorage', ($http) => {
  const storage = {
    data: [],

    get() {
      $http.get('http://localhost:3002/v1/todos')
          .then(result => angular.copy(result.data, this.data))
          .catch(err => console.error(err));
      return this.data;
    },

    create(title) {
      $http.post('http://localhost:3002/v1/todos', {title: title, done: false})
          .then(result => this.data.push(result.data))
          .catch(err => console.error(err));
    },

    destory(todo) {
      $http.delete(`http://localhost:3002/v1/todos/${todo.id}`)
          .then(result => angular.copy(this.data.filter(t => t.id !== todo.id), this.data))
          .catch(err => console.error(err));
    },

    update(todo) {
      const reqBody = {title: todo.title, done: todo.done};
      $http.put(`http://localhost:3002/v1/todos/${todo.id}`, reqBody)
          .then(result => undefined)
          .catch(err => console.error(err));
    }
  };

  return storage;
});

Authentication

Login

Logout

  • template
  • MenuCtrl
  • auth.service

Register

  • template
  • RegisterCtrl
  • user.service

Angular2

Made with Slides.com