├── .gitignore ├── CHANGELOG.md ├── README.md ├── ch01 └── welcome-msg-app │ ├── index.html │ └── package.json ├── ch02 └── hello-angular │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── ch03 └── ng-welcome-msg-app │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── i18n-support.service.spec.ts │ │ ├── i18n-support.service.ts │ │ ├── lang-metadata.ts │ │ ├── lang-selector │ │ │ ├── lang-selector-btn.pipe.spec.ts │ │ │ ├── lang-selector-btn.pipe.ts │ │ │ ├── lang-selector.component.css │ │ │ ├── lang-selector.component.html │ │ │ ├── lang-selector.component.spec.ts │ │ │ └── lang-selector.component.ts │ │ └── welcome-msg │ │ │ ├── welcome-msg.component.css │ │ │ ├── welcome-msg.component.html │ │ │ ├── welcome-msg.component.spec.ts │ │ │ └── welcome-msg.component.ts │ ├── assets │ │ ├── .gitkeep │ │ └── img │ │ │ ├── China.png │ │ │ ├── France.png │ │ │ ├── Japan.png │ │ │ ├── South_Korea.png │ │ │ └── United_States.png │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── ch04 └── simple-counter │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── ch05 └── mouse-pos-logger │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── another-logger.service.spec.ts │ │ ├── another-logger.service.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── app.tokens.ts │ │ ├── log-level.enum.ts │ │ ├── logger-service.ts │ │ ├── mouse-track-zone │ │ │ ├── mouse-track-zone.component.css │ │ │ ├── mouse-track-zone.component.html │ │ │ ├── mouse-track-zone.component.spec.ts │ │ │ └── mouse-track-zone.component.ts │ │ ├── my-special-logger.service.spec.ts │ │ └── my-special-logger.service.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── ch06 ├── comp-comm │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ │ ├── app.e2e-spec.ts │ │ ├── app.po.ts │ │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ └── check-list │ │ │ │ ├── check-item.ts │ │ │ │ ├── check-list-data.service.spec.ts │ │ │ │ ├── check-list-data.service.ts │ │ │ │ ├── check-list-result │ │ │ │ ├── check-list-result.component.css │ │ │ │ ├── check-list-result.component.html │ │ │ │ ├── check-list-result.component.spec.ts │ │ │ │ ├── check-list-result.component.ts │ │ │ │ └── result-graph │ │ │ │ │ ├── result-graph.component.css │ │ │ │ │ ├── result-graph.component.html │ │ │ │ │ ├── result-graph.component.spec.ts │ │ │ │ │ └── result-graph.component.ts │ │ │ │ ├── check-list.component.css │ │ │ │ ├── check-list.component.html │ │ │ │ ├── check-list.component.spec.ts │ │ │ │ └── check-list.component.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json └── mouse-pos-logger │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── another-logger.service.spec.ts │ │ ├── another-logger.service.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── app.tokens.ts │ │ ├── log-level.enum.ts │ │ ├── logger-service.ts │ │ ├── mouse-track-zone │ │ │ ├── mouse-track-zone.component.css │ │ │ ├── mouse-track-zone.component.html │ │ │ ├── mouse-track-zone.component.spec.ts │ │ │ └── mouse-track-zone.component.ts │ │ ├── my-special-logger.service.spec.ts │ │ └── my-special-logger.service.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── ch07 ├── contacts-manager-v2 │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ │ ├── app.e2e-spec.ts │ │ ├── app.po.ts │ │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── proxy.conf.json │ ├── server │ │ └── app.js │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── app.tokens.ts │ │ │ ├── my-api-gateway.service.spec.ts │ │ │ ├── my-api-gateway.service.ts │ │ │ └── user-list │ │ │ │ ├── index.ts │ │ │ │ ├── user-detail │ │ │ │ ├── index.ts │ │ │ │ ├── user-detail.component.css │ │ │ │ ├── user-detail.component.html │ │ │ │ ├── user-detail.component.spec.ts │ │ │ │ ├── user-detail.component.ts │ │ │ │ ├── user-detail.service.spec.ts │ │ │ │ ├── user-detail.service.ts │ │ │ │ └── user.model.ts │ │ │ │ ├── user-list.component.css │ │ │ │ ├── user-list.component.html │ │ │ │ ├── user-list.component.spec.ts │ │ │ │ ├── user-list.component.ts │ │ │ │ ├── user-list.service.spec.ts │ │ │ │ └── user-list.service.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── material-theme.scss │ │ ├── polyfills.ts │ │ ├── styles.css │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json └── contacts-manager │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── in-memory-user.service.spec.ts │ │ ├── in-memory-user.service.ts │ │ └── user │ │ │ ├── user.model.ts │ │ │ ├── user.service.spec.ts │ │ │ └── user.service.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── ch08 └── product-manager │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package.json │ ├── protractor.conf.js │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── custom-validators.ts │ │ └── manager-info │ │ │ ├── manager-info.component.css │ │ │ ├── manager-info.component.html │ │ │ ├── manager-info.component.spec.ts │ │ │ └── manager-info.component.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── resources ├── angular_first_cover.jpg └── img.zip ├── simple-commerce-manager ├── .angular-cli.json ├── .editorconfig ├── .firebaserc ├── .gitignore ├── README.md ├── database.rules.json ├── e2e │ ├── app.e2e-spec.ts │ ├── app.po.ts │ └── tsconfig.e2e.json ├── firebase.json ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── category │ │ │ ├── category-detail │ │ │ │ ├── category-detail-resolver.service.spec.ts │ │ │ │ ├── category-detail-resolver.service.ts │ │ │ │ ├── category-detail.component.css │ │ │ │ ├── category-detail.component.html │ │ │ │ ├── category-detail.component.spec.ts │ │ │ │ └── category-detail.component.ts │ │ │ ├── category-management │ │ │ │ ├── category-item │ │ │ │ │ ├── category-item.component.css │ │ │ │ │ ├── category-item.component.html │ │ │ │ │ ├── category-item.component.spec.ts │ │ │ │ │ └── category-item.component.ts │ │ │ │ ├── category-list-resolver.service.spec.ts │ │ │ │ ├── category-list-resolver.service.ts │ │ │ │ ├── category-management.component.css │ │ │ │ ├── category-management.component.html │ │ │ │ ├── category-management.component.spec.ts │ │ │ │ └── category-management.component.ts │ │ │ ├── category-routing.module.ts │ │ │ ├── category.model.ts │ │ │ ├── category.module.ts │ │ │ └── category.tokens.ts │ │ ├── custom-toast-options.ts │ │ ├── product │ │ │ ├── product-detail │ │ │ │ ├── product-detail-resolver.service.spec.ts │ │ │ │ ├── product-detail-resolver.service.ts │ │ │ │ ├── product-detail.component.css │ │ │ │ ├── product-detail.component.html │ │ │ │ ├── product-detail.component.spec.ts │ │ │ │ └── product-detail.component.ts │ │ │ ├── product-management │ │ │ │ ├── button-group │ │ │ │ │ ├── button-group.component.css │ │ │ │ │ ├── button-group.component.html │ │ │ │ │ ├── button-group.component.spec.ts │ │ │ │ │ └── button-group.component.ts │ │ │ │ ├── checked-product-set.service.spec.ts │ │ │ │ ├── checked-product-set.service.ts │ │ │ │ ├── product-bulk-updater.service.spec.ts │ │ │ │ ├── product-bulk-updater.service.ts │ │ │ │ ├── product-list │ │ │ │ │ ├── product-list-resolver.service.spec.ts │ │ │ │ │ ├── product-list-resolver.service.ts │ │ │ │ │ ├── product-list.component.css │ │ │ │ │ ├── product-list.component.html │ │ │ │ │ ├── product-list.component.spec.ts │ │ │ │ │ └── product-list.component.ts │ │ │ │ ├── product-management.component.css │ │ │ │ ├── product-management.component.html │ │ │ │ ├── product-management.component.spec.ts │ │ │ │ └── product-management.component.ts │ │ │ ├── product-routing.module.ts │ │ │ ├── product-status.pipe.spec.ts │ │ │ ├── product-status.pipe.ts │ │ │ ├── product.model.ts │ │ │ ├── product.module.ts │ │ │ └── product.tokens.ts │ │ ├── scm-main │ │ │ ├── footer │ │ │ │ ├── footer.component.css │ │ │ │ ├── footer.component.html │ │ │ │ ├── footer.component.spec.ts │ │ │ │ └── footer.component.ts │ │ │ ├── main-dashboard │ │ │ │ ├── main-dashboard.component.css │ │ │ │ ├── main-dashboard.component.html │ │ │ │ ├── main-dashboard.component.spec.ts │ │ │ │ └── main-dashboard.component.ts │ │ │ ├── navbar │ │ │ │ ├── navbar.component.css │ │ │ │ ├── navbar.component.html │ │ │ │ ├── navbar.component.spec.ts │ │ │ │ └── navbar.component.ts │ │ │ ├── page-not-found │ │ │ │ ├── page-not-found.component.css │ │ │ │ ├── page-not-found.component.html │ │ │ │ ├── page-not-found.component.spec.ts │ │ │ │ └── page-not-found.component.ts │ │ │ ├── scm-main.module.ts │ │ │ └── sidebar │ │ │ │ ├── sidebar.component.css │ │ │ │ ├── sidebar.component.html │ │ │ │ ├── sidebar.component.spec.ts │ │ │ │ └── sidebar.component.ts │ │ └── shared │ │ │ ├── can-deactivate-guard.service.spec.ts │ │ │ ├── can-deactivate-guard.service.ts │ │ │ ├── custom-validators.ts │ │ │ ├── data-store.service.spec.ts │ │ │ ├── data-store.service.ts │ │ │ ├── loading-spinner │ │ │ ├── loading-spinner.component.css │ │ │ ├── loading-spinner.component.html │ │ │ ├── loading-spinner.component.spec.ts │ │ │ ├── loading-spinner.component.ts │ │ │ ├── spinner.service.spec.ts │ │ │ └── spinner.service.ts │ │ │ ├── no-counter.service.spec.ts │ │ │ ├── no-counter.service.ts │ │ │ ├── scm-base.model.ts │ │ │ ├── scm-shared-util.ts │ │ │ ├── session-auth-guard.service.spec.ts │ │ │ ├── session-auth-guard.service.ts │ │ │ └── shared.module.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── tsconfig.json └── tslint.json └── spring-boot-starter ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── frontend │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ │ ├── app.e2e-spec.ts │ │ ├── app.po.ts │ │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── protractor.conf.js │ ├── proxy.conf.json │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ └── app.module.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── java │ └── kr │ │ └── notforme │ │ └── starter │ │ └── SpringBootAngularStarterApplication.java └── resources │ └── application.properties └── test └── java └── kr └── notforme └── starter └── SpringBootAngularStarterApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | /**/node_modules 2 | /**/.vscode 3 | /**/yarn.lock -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 주요 변경사항 2 | 3 | ## (2017-12-07) 버전 최신화 4 | * Angular를 포함 대부분의 dependency 버전을 최신화하였습니다. 5 | 6 | ## (2017-07-24) Material2 버전 호환성 반영 7 | * Material2 의 beta.8에 cdk 패키지가 의존성으로 추가됨 [링크](https://github.com/angular/material2/blob/master/CHANGELOG.md) 8 | * 3장, 7장 예제의 material 버전 변경 및 Angular CLI 버전도 명시적으로 최신화 9 | 10 | ## (2017-07-19) 70쪽 양방향 데이터 바인딩 맛보기 11 | 12 | * Angular CLI가 1.1 이후에 변경된 내용이 발생하여 70쪽 예제를 실습을 위해 추가 작업이 필요합니다. 13 | * src/app/app.module.ts 파일에 다음 링크와 같이 코드를 수정해야 합니다. [코드 링크](https://github.com/not-for-me/hb-angular-first/blob/17f66ce3129f1f948881d8553f3b024f184dba31/ch03/ng-welcome-msg-app/src/app/app.module.ts) 14 | -------------------------------------------------------------------------------- /ch01/welcome-msg-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Welcome Msg App 7 | 8 | 9 | 10 | 11 | 12 |

13 | 님 환영합니다. 14 |

15 |
16 | 17 | 18 | 19 |
20 | 21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ch01/welcome-msg-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "welcome-msg-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "http-server": "^0.9.0", 8 | "jquery": "^1.12.4" 9 | }, 10 | "devDependencies": {}, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "author": "", 15 | "license": "ISC" 16 | } 17 | -------------------------------------------------------------------------------- /ch02/hello-angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch02/hello-angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch02/hello-angular/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { HelloAngularPage } from './app.po'; 2 | 3 | describe('hello-angular App', () => { 4 | let page: HelloAngularPage; 5 | 6 | beforeEach(() => { 7 | page = new HelloAngularPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch02/hello-angular/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class HelloAngularPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch02/hello-angular/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch02/hello-angular/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch02/hello-angular/src/app/app.component.css -------------------------------------------------------------------------------- /ch02/hello-angular/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

2 | {{title}} 3 |

4 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'Hello, Angular!'; 10 | } 11 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | imports: [ 13 | BrowserModule, 14 | FormsModule, 15 | HttpModule 16 | ], 17 | providers: [], 18 | bootstrap: [AppComponent] 19 | }) 20 | export class AppModule { } 21 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch02/hello-angular/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch02/hello-angular/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch02/hello-angular/src/favicon.ico -------------------------------------------------------------------------------- /ch02/hello-angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HelloAngular 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch02/hello-angular/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch02/hello-angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { NgWelcomeMsgAppPage } from './app.po'; 2 | 3 | describe('ng-welcome-msg-app App', () => { 4 | let page: NgWelcomeMsgAppPage; 5 | 6 | beforeEach(() => { 7 | page = new NgWelcomeMsgAppPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class NgWelcomeMsgAppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/app/app.component.css -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 다국어 환영 인사 서비스 2 | 3 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'app works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('app works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('app works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { } 9 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/i18n-support.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { I18nSupportService } from './i18n-support.service'; 4 | 5 | describe('I18nSupportService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [I18nSupportService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([I18nSupportService], (service: I18nSupportService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/i18n-support.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { LANG_METADATA } from './lang-metadata'; 3 | 4 | @Injectable() 5 | export class I18nSupportService { 6 | langCode = 'ko'; 7 | private welcomeMsg; 8 | 9 | constructor() { 10 | this.welcomeMsg = { 11 | 'ko': '안녕하세요', 12 | 'en': 'Hello', 13 | 'jp': '初めまして', 14 | 'fr': 'Bonjour' 15 | }; 16 | } 17 | 18 | getWelcomeMsg(userName: string) { 19 | const langData = LANG_METADATA.find(lang => lang.code === this.langCode); 20 | return `${langData.msg}, ${userName}!`; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-metadata.ts: -------------------------------------------------------------------------------- 1 | export const LANG_METADATA = [ 2 | { 3 | code: 'ko', 4 | name: '한국어', 5 | flagImgName: 'South_Korea.png', 6 | msg: '안녕하세요' 7 | }, 8 | { 9 | code: 'en', 10 | name: '영어', 11 | flagImgName: 'United_States.png', 12 | msg: 'Hello' 13 | }, 14 | { 15 | code: 'jp', 16 | name: '일본어', 17 | flagImgName: 'Japan.png', 18 | msg: '初めまして' 19 | }, 20 | { 21 | code: 'fr', 22 | name: '불어', 23 | flagImgName: 'France.png', 24 | msg: 'Bonjour' 25 | }, 26 | { 27 | code: 'cn', 28 | name: '중국어', 29 | flagImgName: 'China.png', 30 | msg: '您好' 31 | } 32 | ]; 33 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-selector/lang-selector-btn.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { LangSelectorBtnPipe } from './lang-selector-btn.pipe'; 2 | 3 | describe('LangSelectorBtnPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new LangSelectorBtnPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-selector/lang-selector-btn.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'langSelectorBtn' 5 | }) 6 | export class LangSelectorBtnPipe implements PipeTransform { 7 | 8 | transform(lang): any { 9 | return `${lang.name} (${lang.code})`; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-selector/lang-selector.component.css: -------------------------------------------------------------------------------- 1 | .mat-radio-button { 2 | margin: 10px 15px; 3 | } 4 | 5 | img { 6 | width: 18px; 7 | border: 1px solid darkblue; 8 | } 9 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-selector/lang-selector.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{lang | langSelectorBtn}} 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-selector/lang-selector.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LangSelectorComponent } from './lang-selector.component'; 4 | 5 | describe('LangSelectorComponent', () => { 6 | let component: LangSelectorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LangSelectorComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LangSelectorComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/lang-selector/lang-selector.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { I18nSupportService } from '../i18n-support.service'; 3 | import { LANG_METADATA } from '../lang-metadata'; 4 | 5 | 6 | @Component({ 7 | selector: 'app-lang-selector', 8 | templateUrl: './lang-selector.component.html', 9 | styleUrls: ['./lang-selector.component.css'] 10 | }) 11 | export class LangSelectorComponent implements OnInit { 12 | langMetadata = LANG_METADATA; 13 | langCode: string; 14 | 15 | constructor(public i18nSupporter: I18nSupportService) { 16 | this.langCode = i18nSupporter.langCode; 17 | } 18 | 19 | ngOnInit() { 20 | } 21 | 22 | syncToService(code) { 23 | this.i18nSupporter.langCode = code; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/welcome-msg/welcome-msg.component.css: -------------------------------------------------------------------------------- 1 | .welcome-msg { 2 | margin-left: 10px; 3 | color: deepskyblue; 4 | } -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/welcome-msg/welcome-msg.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | {{welcomeMsg}} 8 |
9 |
-------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/welcome-msg/welcome-msg.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { WelcomeMsgComponent } from './welcome-msg.component'; 4 | 5 | describe('WelcomeMsgComponent', () => { 6 | let component: WelcomeMsgComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ WelcomeMsgComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(WelcomeMsgComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/app/welcome-msg/welcome-msg.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, AfterViewInit } from '@angular/core'; 2 | import { I18nSupportService } from '../i18n-support.service'; 3 | import { MatSnackBar } from '@angular/material'; 4 | 5 | @Component({ 6 | selector: 'app-welcome-msg', 7 | templateUrl: './welcome-msg.component.html', 8 | styleUrls: ['./welcome-msg.component.css'] 9 | }) 10 | export class WelcomeMsgComponent implements AfterViewInit { 11 | welcomeMsg = ''; 12 | userName = ''; 13 | private valid = false; 14 | private static CHK_KEYUP_WAIT_SEC = 5000; 15 | 16 | constructor(public i18nSupporter: I18nSupportService, private snackbar: MatSnackBar) { } 17 | 18 | ngAfterViewInit() { 19 | const checkTouchedFn = () => { 20 | if (this.valid) return; 21 | this.snackbar.open('이름을 입력해 주세요', '확인', { duration: 3000 }); 22 | }; 23 | 24 | setTimeout(checkTouchedFn, WelcomeMsgComponent.CHK_KEYUP_WAIT_SEC); 25 | } 26 | 27 | onChange() { 28 | this.valid = this.userName.length > 0; 29 | } 30 | 31 | showWelcomeMsg() { 32 | this.welcomeMsg = this.i18nSupporter.getWelcomeMsg(this.userName); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/assets/img/China.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/assets/img/China.png -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/assets/img/France.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/assets/img/France.png -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/assets/img/Japan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/assets/img/Japan.png -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/assets/img/South_Korea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/assets/img/South_Korea.png -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/assets/img/United_States.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/assets/img/United_States.png -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch03/ng-welcome-msg-app/src/favicon.ico -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NgWelcomeMsgApp 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | /*@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';*/ 3 | @import '~@angular/material/prebuilt-themes/indigo-pink.css'; 4 | /*@import '~@angular/material/prebuilt-themes/pink-bluegrey.css';*/ 5 | /*@import '~@angular/material/prebuilt-themes/purple-green.css';*/ -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch03/ng-welcome-msg-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch04/simple-counter/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch04/simple-counter/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch04/simple-counter/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { SimpleCounterPage } from './app.po'; 2 | 3 | describe('simple-counter App', () => { 4 | let page: SimpleCounterPage; 5 | 6 | beforeEach(() => { 7 | page = new SimpleCounterPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch04/simple-counter/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class SimpleCounterPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch04/simple-counter/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch04/simple-counter/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .counter { 2 | width: 120px; 3 | height: 120px; 4 | line-height: 120px; 5 | text-align: center; 6 | vertical-align: middle; 7 | background-color: grey; 8 | font-size: 80px; 9 | border: 1px solid #000 10 | } 11 | .buttons { 12 | width: 100px; 13 | text-align: center; 14 | } -------------------------------------------------------------------------------- /ch04/simple-counter/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
{{curVal}}
2 |
3 | 4 | 5 |
6 |
7 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /ch04/simple-counter/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'app works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('app works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('app works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | imports: [ 13 | BrowserModule, 14 | FormsModule, 15 | HttpModule 16 | ], 17 | providers: [], 18 | bootstrap: [AppComponent] 19 | }) 20 | export class AppModule { } 21 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch04/simple-counter/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch04/simple-counter/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch04/simple-counter/src/favicon.ico -------------------------------------------------------------------------------- /ch04/simple-counter/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SimpleCounter 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch04/simple-counter/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch04/simple-counter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { MousePosLoggerPage } from './app.po'; 2 | 3 | describe('mouse-pos-logger App', () => { 4 | let page: MousePosLoggerPage; 5 | 6 | beforeEach(() => { 7 | page = new MousePosLoggerPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('mpl works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class MousePosLoggerPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('mpl-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/another-logger.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AnotherLoggerService } from './another-logger.service'; 4 | import { LogLevel } from './log-level.enum' 5 | import { LOG_LEVEL_TOKEN } from './app.tokens'; 6 | 7 | describe('AnotherLoggerService', () => { 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | providers: [AnotherLoggerService, { provide: LOG_LEVEL_TOKEN, useValue: LogLevel.INFO }] 11 | }); 12 | }); 13 | 14 | it('should ...', inject([AnotherLoggerService], (service: AnotherLoggerService) => { 15 | expect(service).toBeTruthy(); 16 | })); 17 | 18 | it('최초 로그 레벨은 LOG_LEVEL_TOKEN에서 선언한 값이어야 한다.', inject([AnotherLoggerService], (service: AnotherLoggerService) => { 19 | expect(service).toBeTruthy(); 20 | expect(service.logLevel).toEqual(LogLevel.INFO); 21 | })); 22 | 23 | it('level을 변경한 것이 정상적으로 반영되어야 한다.', inject([AnotherLoggerService], (service: AnotherLoggerService) => { 24 | service.logLevel = LogLevel.DEBUG; 25 | expect(service.logLevel).toEqual(LogLevel.DEBUG); 26 | })); 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/another-logger.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { LogLevel } from './log-level.enum'; 3 | import { LOG_LEVEL_TOKEN } from './app.tokens' 4 | import { LoggerService } from './logger-service'; 5 | 6 | @Injectable() 7 | export class AnotherLoggerService extends LoggerService { 8 | constructor( @Inject(LOG_LEVEL_TOKEN) logLevel: LogLevel) { 9 | super(logLevel); 10 | } 11 | 12 | log(logLevel: LogLevel, msg: string) { 13 | const logMsg = this.getFormattedLogMsg(logLevel, msg); 14 | if (this.isProperLogLevel(logLevel)) { 15 | console.log(logMsg); 16 | } 17 | } 18 | 19 | private getFormattedLogMsg(logLevel: LogLevel, msg: string) { 20 | return `[${LogLevel[logLevel]}] - ${msg}`; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch05/mouse-pos-logger/src/app/app.component.css -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

{{title}}

2 | 3 | 4 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { MySpecialLoggerService } from './my-special-logger.service'; 3 | import { LogLevel } from './log-level.enum'; 4 | 5 | 6 | @Component({ 7 | selector: 'mpl-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.css'] 10 | }) 11 | export class AppComponent { 12 | title = 'mpl works!'; 13 | 14 | constructor(private logger: MySpecialLoggerService) { } 15 | 16 | printDebugLog() { 17 | this.logger.debug("test depenency injector tree!"); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { MouseTrackZoneComponent } from './mouse-track-zone/mouse-track-zone.component'; 8 | 9 | import { MySpecialLoggerService } from './my-special-logger.service'; 10 | import { AnotherLoggerService } from './another-logger.service'; 11 | 12 | import { LogLevel } from './log-level.enum'; 13 | import { LOG_LEVEL_TOKEN } from './app.tokens'; 14 | 15 | 16 | @NgModule({ 17 | declarations: [ 18 | AppComponent, 19 | MouseTrackZoneComponent 20 | ], 21 | imports: [ 22 | BrowserModule, 23 | FormsModule, 24 | HttpModule 25 | ], 26 | providers: [ 27 | MySpecialLoggerService, 28 | AnotherLoggerService, 29 | { provide: LOG_LEVEL_TOKEN, useValue: LogLevel.INFO } 30 | ], 31 | bootstrap: [AppComponent] 32 | }) 33 | export class AppModule { } 34 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/app.tokens.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { LogLevel } from './log-level.enum'; 3 | export const LOG_LEVEL_TOKEN = new InjectionToken('logLevel'); -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/log-level.enum.ts: -------------------------------------------------------------------------------- 1 | export enum LogLevel { DEBUG, INFO, WARN, ERROR } -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/logger-service.ts: -------------------------------------------------------------------------------- 1 | import { LogLevel } from './log-level.enum'; 2 | 3 | export abstract class LoggerService { 4 | logLevel: LogLevel; 5 | 6 | constructor(logLevel: LogLevel) { 7 | this.logLevel = logLevel; 8 | } 9 | 10 | debug(msg: string) { 11 | this.log(LogLevel.DEBUG, msg); 12 | } 13 | 14 | info(msg: string) { 15 | this.log(LogLevel.INFO, msg); 16 | } 17 | 18 | warn(msg: string) { 19 | this.log(LogLevel.WARN, msg); 20 | } 21 | 22 | error(msg: string) { 23 | this.log(LogLevel.ERROR, msg); 24 | } 25 | 26 | abstract log(logLevel: LogLevel, msg: string); 27 | 28 | protected isProperLogLevel(logLevel: LogLevel): boolean { 29 | if (this.logLevel === LogLevel.DEBUG) return true; 30 | return logLevel >= this.logLevel; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/mouse-track-zone/mouse-track-zone.component.css: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | padding: 5px; 4 | border: 1px solid darkslategrey; 5 | } 6 | 7 | .track-zone { 8 | width: 200px; 9 | height: 200px; 10 | vertical-align: top; 11 | background-color: lightblue; 12 | border: 1px solid grey; 13 | display: inline-block; 14 | } 15 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/app/mouse-track-zone/mouse-track-zone.component.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch05/mouse-pos-logger/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch05/mouse-pos-logger/src/favicon.ico -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MousePosLogger 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch05/mouse-pos-logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch06/comp-comm/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch06/comp-comm/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch06/comp-comm/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { CompCommPage } from './app.po'; 2 | 3 | describe('comp-comm App', () => { 4 | let page: CompCommPage; 5 | 6 | beforeEach(() => { 7 | page = new CompCommPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch06/comp-comm/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class CompCommPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch06/comp-comm/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch06/comp-comm/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch06/comp-comm/src/app/app.component.css -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

2 | {{title}} 3 |

4 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'cc works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('cc works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('cc works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'cc-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = '컴포넌트 통신 실습'; 10 | } 11 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { CheckListComponent } from './check-list/check-list.component'; 8 | import { CheckListResultComponent } from './check-list/check-list-result/check-list-result.component'; 9 | import { ResultGraphComponent } from './check-list/check-list-result/result-graph/result-graph.component'; 10 | 11 | import { CheckListDataService } from './check-list/check-list-data.service'; 12 | 13 | @NgModule({ 14 | declarations: [ 15 | AppComponent, 16 | CheckListComponent, 17 | CheckListResultComponent, 18 | ResultGraphComponent 19 | ], 20 | imports: [ 21 | BrowserModule, 22 | FormsModule, 23 | HttpModule 24 | ], 25 | providers: [CheckListDataService], 26 | bootstrap: [AppComponent] 27 | }) 28 | export class AppModule { } 29 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-item.ts: -------------------------------------------------------------------------------- 1 | export interface CheckItem { 2 | idx: number; 3 | content: string; 4 | isChecked: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { CheckListDataService } from './check-list-data.service'; 4 | 5 | describe('CheckListDataService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [CheckListDataService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([CheckListDataService], (service: CheckListDataService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/check-list-result.component.css: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | border: 1px solid dimgray; 4 | width: 380px; 5 | margin: 10px; 6 | padding: 10px; 7 | } 8 | 9 | ul { 10 | margin-top: 5px; 11 | } 12 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/check-list-result.component.html: -------------------------------------------------------------------------------- 1 |

체크한 항목 수: {{checkedCnt}}

2 |

체크한 항목:

3 |
    4 |
  • 5 | {{item.content}} 6 |
  • 7 |
8 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/check-list-result.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CheckListResultComponent } from './check-list-result.component'; 4 | 5 | describe('CheckListResultComponent', () => { 6 | let component: CheckListResultComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CheckListResultComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CheckListResultComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/result-graph/result-graph.component.css: -------------------------------------------------------------------------------- 1 | /* 막대그래프의 CSS 애니매이션을 아래 소스를 사용하였습니다. */ 2 | /* https://codepen.io/Victa/pen/xDqbf */ 3 | 4 | .chart { 5 | border: 1px solid rgba(0, 0, 0, 0.1); 6 | display: table; 7 | table-layout: fixed; 8 | width: 60%; 9 | max-width: 700px; 10 | height: 200px; 11 | margin: 0 auto; 12 | background-image: linear-gradient(to top, rgba(0, 0, 0, 0.1) 2%, rgba(0, 0, 0, 0) 2%); 13 | background-size: 100% 50px; 14 | background-position: left top; 15 | } 16 | 17 | .chart .grid { 18 | position: relative; 19 | display: table-cell; 20 | vertical-align: bottom; 21 | height: 200px; 22 | } 23 | 24 | .chart span { 25 | margin: 0 1em; 26 | display: block; 27 | background: rgba(209, 236, 250, 0.75); 28 | animation: draw 1s ease-in-out; 29 | } 30 | 31 | .chart span:before { 32 | position: absolute; 33 | left: 0; 34 | right: 0; 35 | top: 95%; 36 | padding: 5px 1em 0; 37 | display: block; 38 | text-align: center; 39 | content: attr(title); 40 | word-wrap: break-word; 41 | } 42 | 43 | @keyframes draw { 44 | 0% { 45 | height: 0; 46 | } 47 | } -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/result-graph/result-graph.component.html: -------------------------------------------------------------------------------- 1 |

체크항목 통계 리포트

2 |
3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/result-graph/result-graph.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResultGraphComponent } from './result-graph.component'; 4 | 5 | describe('ResultGraphComponent', () => { 6 | let component: ResultGraphComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ResultGraphComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ResultGraphComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list-result/result-graph/result-graph.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CheckListDataService } from '../../check-list-data.service'; 3 | 4 | @Component({ 5 | selector: 'cc-result-graph', 6 | templateUrl: './result-graph.component.html', 7 | styleUrls: ['./result-graph.component.css'] 8 | }) 9 | export class ResultGraphComponent implements OnInit { 10 | checkedRatio: string = '0%'; 11 | graphToggle = true; 12 | 13 | constructor(public checkListDataService: CheckListDataService) { } 14 | 15 | ngOnInit() { 16 | this.checkListDataService.changedCntState.subscribe(() => this.printGraph()); 17 | } 18 | 19 | printGraph() { 20 | this.graphToggle = false; 21 | this.checkedRatio = this.checkListDataService.getCheckedItemRatioText(); 22 | setTimeout(() => this.graphToggle = true, 1); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list.component.css: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | border: 1px solid dimgray; 4 | width: 580px; 5 | margin: 10px; 6 | padding: 10px; 7 | } 8 | 9 | span { 10 | margin-right: 20px; 11 | display: inline-block; 12 | } 13 | 14 | .row { 15 | margin: 10px 0; 16 | } 17 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list.component.html: -------------------------------------------------------------------------------- 1 |

항목 체크

2 |
3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CheckListComponent } from './check-list.component'; 4 | 5 | describe('CheckListComponent', () => { 6 | let component: CheckListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CheckListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CheckListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/app/check-list/check-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CheckListDataService } from './check-list-data.service'; 3 | import { CheckItem } from './check-item'; 4 | 5 | @Component({ 6 | selector: 'cc-check-list', 7 | templateUrl: './check-list.component.html', 8 | styleUrls: ['./check-list.component.css'] 9 | }) 10 | export class CheckListComponent implements OnInit { 11 | INIT_TOTAL_CNT: number = 4; 12 | checkList: CheckItem[] = []; 13 | curCheckedItem: CheckItem; 14 | 15 | constructor(public checkListDataService: CheckListDataService) { 16 | this.checkList = this.checkListDataService.initList(this.INIT_TOTAL_CNT); 17 | } 18 | 19 | ngOnInit() { } 20 | 21 | onChangeCnt(op: string) { 22 | this.checkListDataService.changeTotalCntByOp(op); 23 | } 24 | 25 | onChecked(isChecked, checkedItem: CheckItem) { 26 | checkedItem.isChecked = isChecked 27 | this.curCheckedItem = JSON.parse(JSON.stringify(checkedItem)); 28 | this.checkListDataService.checkItem(checkedItem); 29 | } 30 | 31 | unCheckedItem(idx) { 32 | this.checkListDataService.unCheckItem(idx); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch06/comp-comm/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch06/comp-comm/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch06/comp-comm/src/favicon.ico -------------------------------------------------------------------------------- /ch06/comp-comm/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CompComm 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch06/comp-comm/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch06/comp-comm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { MousePosLoggerPage } from './app.po'; 2 | 3 | describe('mouse-pos-logger App', () => { 4 | let page: MousePosLoggerPage; 5 | 6 | beforeEach(() => { 7 | page = new MousePosLoggerPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('mpl works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class MousePosLoggerPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('mpl-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/another-logger.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AnotherLoggerService } from './another-logger.service'; 4 | import { LogLevel } from './log-level.enum' 5 | import { LOG_LEVEL_TOKEN } from './app.tokens'; 6 | 7 | describe('AnotherLoggerService', () => { 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | providers: [AnotherLoggerService, { provide: LOG_LEVEL_TOKEN, useValue: LogLevel.INFO }] 11 | }); 12 | }); 13 | 14 | it('should ...', inject([AnotherLoggerService], (service: AnotherLoggerService) => { 15 | expect(service).toBeTruthy(); 16 | })); 17 | 18 | it('최초 로그 레벨은 LOG_LEVEL_TOKEN에서 선언한 값이어야 한다.', inject([AnotherLoggerService], (service: AnotherLoggerService) => { 19 | expect(service).toBeTruthy(); 20 | expect(service.logLevel).toEqual(LogLevel.INFO); 21 | })); 22 | 23 | it('level을 변경한 것이 정상적으로 반영되어야 한다.', inject([AnotherLoggerService], (service: AnotherLoggerService) => { 24 | service.logLevel = LogLevel.DEBUG; 25 | expect(service.logLevel).toEqual(LogLevel.DEBUG); 26 | })); 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/another-logger.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { LogLevel } from './log-level.enum'; 3 | import { LOG_LEVEL_TOKEN } from './app.tokens' 4 | import { LoggerService } from './logger-service'; 5 | 6 | @Injectable() 7 | export class AnotherLoggerService extends LoggerService { 8 | constructor( @Inject(LOG_LEVEL_TOKEN) logLevel: LogLevel) { 9 | super(logLevel); 10 | } 11 | 12 | log(logLevel: LogLevel, msg: string) { 13 | const logMsg = this.getFormattedLogMsg(logLevel, msg); 14 | if (this.isProperLogLevel(logLevel)) { 15 | console.log(logMsg); 16 | } 17 | } 18 | 19 | private getFormattedLogMsg(logLevel: LogLevel, msg: string) { 20 | return `[${LogLevel[logLevel]}] - ${msg}`; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch06/mouse-pos-logger/src/app/app.component.css -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

{{title}}

2 | 3 | 4 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { MySpecialLoggerService } from './my-special-logger.service'; 3 | import { LogLevel } from './log-level.enum'; 4 | 5 | 6 | @Component({ 7 | selector: 'mpl-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.css'] 10 | }) 11 | export class AppComponent { 12 | title = 'mpl works!'; 13 | 14 | constructor(private logger: MySpecialLoggerService) { } 15 | 16 | printDebugLog() { 17 | this.logger.debug("test depenency injector tree!"); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { MouseTrackZoneComponent } from './mouse-track-zone/mouse-track-zone.component'; 8 | 9 | import { MySpecialLoggerService } from './my-special-logger.service'; 10 | import { AnotherLoggerService } from './another-logger.service'; 11 | 12 | import { LogLevel } from './log-level.enum'; 13 | import { LOG_LEVEL_TOKEN } from './app.tokens'; 14 | 15 | 16 | @NgModule({ 17 | declarations: [ 18 | AppComponent, 19 | MouseTrackZoneComponent 20 | ], 21 | imports: [ 22 | BrowserModule, 23 | FormsModule, 24 | HttpModule 25 | ], 26 | providers: [ 27 | MySpecialLoggerService, 28 | AnotherLoggerService, 29 | { provide: LOG_LEVEL_TOKEN, useValue: LogLevel.INFO } 30 | ], 31 | bootstrap: [AppComponent] 32 | }) 33 | export class AppModule { } 34 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/app.tokens.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | import { LogLevel } from './log-level.enum'; 3 | export const LOG_LEVEL_TOKEN = new InjectionToken('logLevel'); -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/log-level.enum.ts: -------------------------------------------------------------------------------- 1 | export enum LogLevel { DEBUG, INFO, WARN, ERROR } -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/logger-service.ts: -------------------------------------------------------------------------------- 1 | import { LogLevel } from './log-level.enum'; 2 | 3 | export abstract class LoggerService { 4 | logLevel: LogLevel; 5 | 6 | constructor(logLevel: LogLevel) { 7 | this.logLevel = logLevel; 8 | } 9 | 10 | debug(msg: string) { 11 | this.log(LogLevel.DEBUG, msg); 12 | } 13 | 14 | info(msg: string) { 15 | this.log(LogLevel.INFO, msg); 16 | } 17 | 18 | warn(msg: string) { 19 | this.log(LogLevel.WARN, msg); 20 | } 21 | 22 | error(msg: string) { 23 | this.log(LogLevel.ERROR, msg); 24 | } 25 | 26 | abstract log(logLevel: LogLevel, msg: string); 27 | 28 | protected isProperLogLevel(logLevel: LogLevel): boolean { 29 | if (this.logLevel === LogLevel.DEBUG) return true; 30 | return logLevel >= this.logLevel; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/mouse-track-zone/mouse-track-zone.component.css: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | padding: 5px; 4 | border: 1px solid darkslategrey; 5 | } 6 | 7 | .track-zone { 8 | width: 200px; 9 | height: 200px; 10 | vertical-align: top; 11 | background-color: lightblue; 12 | border: 1px solid grey; 13 | display: inline-block; 14 | } 15 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/app/mouse-track-zone/mouse-track-zone.component.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch06/mouse-pos-logger/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch06/mouse-pos-logger/src/favicon.ico -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MousePosLogger 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch06/mouse-pos-logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { ContactsManagerV2Page } from './app.po'; 2 | 3 | describe('contacts-manager-v2 App', () => { 4 | let page: ContactsManagerV2Page; 5 | 6 | beforeEach(() => { 7 | page = new ContactsManagerV2Page(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('cm2 works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class ContactsManagerV2Page { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('cm2-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api/*": { 3 | "target": "http://localhost:3000", 4 | "seruce": false, 5 | "logLevel": "debug" 6 | } 7 | } -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch07/contacts-manager-v2/src/app/app.component.css -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 사용자 관리 3 | 4 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'cm2-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'cm2 works!'; 10 | } 11 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/app.tokens.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from '@angular/core'; 2 | 3 | export const API_URL_TOKEN = new InjectionToken('API_URL'); 4 | export const API_VER_TOKEN = new InjectionToken('API_VER'); -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/my-api-gateway.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { MyApiGatewayService } from './my-api-gateway.service'; 4 | 5 | describe('MyApiGatewayService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [MyApiGatewayService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([MyApiGatewayService], (service: MyApiGatewayService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/index.ts: -------------------------------------------------------------------------------- 1 | export { User, UserDetailService, UserDetailComponent } from './user-detail'; 2 | export { UserListComponent } from './user-list.component'; 3 | export { UserListService } from './user-list.service'; -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-detail/index.ts: -------------------------------------------------------------------------------- 1 | export { UserDetailComponent } from './user-detail.component'; 2 | export { UserDetailService } from './user-detail.service'; 3 | export { User } from './user.model'; -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-detail/user-detail.component.css: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 50%; 3 | } -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-detail/user-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserDetailComponent } from './user-detail.component'; 4 | 5 | describe('UserDetailComponent', () => { 6 | let component: UserDetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserDetailComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserDetailComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-detail/user-detail.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { UserDetailService } from './user-detail.service'; 4 | 5 | describe('UserDetailService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [UserDetailService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([UserDetailService], (service: UserDetailService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-detail/user-detail.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http, Headers } from '@angular/http'; 3 | import { User } from './user.model'; 4 | import { MyApiGatewayService } from '../../my-api-gateway.service'; 5 | 6 | @Injectable() 7 | export class UserDetailService { 8 | headerInfo: Headers 9 | constructor(public apiGateway: MyApiGatewayService) { } 10 | 11 | findUser(no: number) { 12 | return this.apiGateway.get(`users/${no}`).map(res => res.json()); 13 | } 14 | 15 | addUser(user: any) { 16 | return this.apiGateway.post('users', user).map(res => res.json()); 17 | } 18 | 19 | modifyUser(user: User) { 20 | return this.apiGateway.put(`users/${user.no}`, user).map(res => res.json()); 21 | } 22 | 23 | removeUser(userNo: any) { 24 | return this.apiGateway.delete(`users/${userNo}`); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-detail/user.model.ts: -------------------------------------------------------------------------------- 1 | export type Sex = "F" | "M" | ""; 2 | 3 | export class User { 4 | no: number; 5 | id: number; 6 | name: string; 7 | phoneNum: string; 8 | mail: string; 9 | birthDate: string; 10 | sex: Sex; 11 | 12 | constructor() { 13 | this.no = 0; 14 | this.name = ''; 15 | this.phoneNum = ''; 16 | this.mail = ''; 17 | this.birthDate = ''; 18 | this.sex = ""; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-list.component.css: -------------------------------------------------------------------------------- 1 | div.container { 2 | height: 100%; 3 | margin-top: 20px; 4 | } 5 | 6 | .user-list { 7 | width: 80%; 8 | } 9 | 10 | mat-list-item { 11 | border: 1px solid lightslategrey; 12 | background: white; 13 | } 14 | 15 | .inner-content { 16 | display: inline-block; 17 | width: 30%; 18 | } 19 | 20 | a:hover { 21 | text-decoration: underline; 22 | } 23 | 24 | .hover-add-btn { 25 | display: inline-block; 26 | position: fixed; 27 | bottom: 50px; 28 | right: 50px; 29 | } 30 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-list.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

사용자 목록

4 | 5 |
6 | {{user.name}} 7 | {{user.phoneNum}} 8 | {{user.mail}} 9 | 12 |
13 | 14 | 15 | 16 |
17 |
18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserListComponent } from './user-list.component'; 4 | 5 | describe('UserListComponent', () => { 6 | let component: UserListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-list.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { UserListService } from './user-list.service'; 4 | 5 | describe('UserListService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [UserListService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([UserListService], (service: UserListService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/app/user-list/user-list.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { User } from './user-detail'; 3 | import { MyApiGatewayService } from '../my-api-gateway.service'; 4 | 5 | 6 | @Injectable() 7 | export class UserListService { 8 | 9 | constructor(public apiGateway: MyApiGatewayService) { } 10 | 11 | findAllUserSummary() { 12 | return this.apiGateway.get('users'); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch07/contacts-manager-v2/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch07/contacts-manager-v2/src/favicon.ico -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ContactsManagerV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Loading... 14 | 15 | 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/material-theme.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | 3 | @include mat-core(); 4 | 5 | $app-primary: mat-palette($mat-cyan); 6 | $app-warn: mat-palette($mat-red); 7 | 8 | $app-theme: mat-light-theme($app-primary, $app-primary, $app-warn); 9 | 10 | @include angular-material-theme($app-theme); 11 | 12 | html, body { 13 | height: 100%; 14 | margin: 0; 15 | background: lightslategrey; 16 | } -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch07/contacts-manager-v2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch07/contacts-manager/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch07/contacts-manager/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch07/contacts-manager/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { ContactsManagerPage } from './app.po'; 2 | 3 | describe('contacts-manager App', () => { 4 | let page: ContactsManagerPage; 5 | 6 | beforeEach(() => { 7 | page = new ContactsManagerPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('cm works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch07/contacts-manager/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class ContactsManagerPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('cm-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch07/contacts-manager/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch07/contacts-manager/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch07/contacts-manager/src/app/app.component.css -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

Contact Manager : Http 실습

2 |
3 |

사용자 조회 / 삭제

4 | 5 | 6 | 7 |
{{searchedUser | json}}
8 |
9 |
10 |

사용자 등록 / 수정

11 |
12 |
13 | 14 | 15 |
-------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'cm works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('cm works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('cm works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; 6 | 7 | import { AppComponent } from './app.component'; 8 | import { InMemoryUserService } from './in-memory-user.service'; 9 | import { UserService } from './user/user.service'; 10 | 11 | @NgModule({ 12 | declarations: [ 13 | AppComponent 14 | ], 15 | imports: [ 16 | BrowserModule, 17 | FormsModule, 18 | HttpModule, 19 | InMemoryWebApiModule.forRoot(InMemoryUserService, { delay: 500, put204: false }) 20 | ], 21 | providers: [UserService], 22 | bootstrap: [AppComponent] 23 | }) 24 | export class AppModule { } 25 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/in-memory-user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { InMemoryUserService } from './in-memory-user.service'; 4 | 5 | describe('InMemoryUserService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [InMemoryUserService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([InMemoryUserService], (service: InMemoryUserService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/in-memory-user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { InMemoryDbService } from 'angular-in-memory-web-api'; 3 | import { User } from './user/user.model'; 4 | 5 | @Injectable() 6 | export class InMemoryUserService implements InMemoryDbService { 7 | private _database: any; 8 | constructor() { } 9 | 10 | createDb() { 11 | this._database = {}; 12 | this.makeUserTableAndDummyData(); 13 | return this._database; 14 | } 15 | 16 | private createTable(tableName: string, initialData: any[]) { 17 | this._database[tableName] = initialData; 18 | } 19 | 20 | private makeUserTableAndDummyData() { 21 | const dummyUserData: User[] = [ 22 | { id: 1, name: 'woojin', age: 33 }, 23 | { id: 2, name: 'yunhye', age: 31 }, 24 | { id: 3, name: 'sunhye', age: 29 }, 25 | ]; 26 | 27 | this.createTable('users', dummyUserData); 28 | } 29 | } -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/user/user.model.ts: -------------------------------------------------------------------------------- 1 | export class User { 2 | id: number; 3 | name: string; 4 | age: number; 5 | 6 | constructor() { 7 | this.id = 0; 8 | this.name = ''; 9 | this.age = 0; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/user/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { UserService } from './user.service'; 4 | 5 | describe('UserService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [UserService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([UserService], (service: UserService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/app/user/user.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Http } from '@angular/http'; 3 | 4 | @Injectable() 5 | export class UserService { 6 | constructor(public http: Http) { } 7 | 8 | getUser(id: number, callback) { 9 | this.http.get(`/api/users/${id}`).map(res => res.json()).subscribe(callback); 10 | } 11 | 12 | addUser(user: any, callback) { 13 | this.http.post('/api/users', user).map(res => res.json()).subscribe(callback); 14 | } 15 | 16 | modifyUser(user: any, callback) { 17 | this.http.put(`/api/users/${user.id}`, user).map(res => res.json()).subscribe(callback); 18 | } 19 | 20 | removeUser(user: any, callback) { 21 | this.http.delete(`/api/users/${user.id}`).subscribe(callback); 22 | } 23 | } -------------------------------------------------------------------------------- /ch07/contacts-manager/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch07/contacts-manager/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch07/contacts-manager/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch07/contacts-manager/src/favicon.ico -------------------------------------------------------------------------------- /ch07/contacts-manager/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ContactsManager 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch07/contacts-manager/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch07/contacts-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch08/product-manager/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ch08/product-manager/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /ch08/product-manager/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { ProductManagerPage } from './app.po'; 2 | 3 | describe('product-manager App', () => { 4 | let page: ProductManagerPage; 5 | 6 | beforeEach(() => { 7 | page = new ProductManagerPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('pm works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ch08/product-manager/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class ProductManagerPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('pm-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ch08/product-manager/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch08/product-manager/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /ch08/product-manager/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | fieldset { 2 | border: 1px solid lightblue; 3 | } 4 | 5 | input.ng-valid, textarea.ng-valid { 6 | border-bottom: 2px solid lightgreen; 7 | } 8 | 9 | input.ng-invalid:not(form), textarea.ng-invalid:not(form) { 10 | border-bottom: 2px solid lightsalmon; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /ch08/product-manager/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'pm works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('pm works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('pm works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /ch08/product-manager/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { MinNumValueValidator, MaxNumValueValidator } from './custom-validators'; 8 | import { ManagerInfoComponent } from './manager-info/manager-info.component'; 9 | 10 | @NgModule({ 11 | declarations: [ 12 | AppComponent, 13 | MinNumValueValidator, 14 | MaxNumValueValidator, 15 | ManagerInfoComponent 16 | ], 17 | imports: [ 18 | BrowserModule, 19 | FormsModule, 20 | ReactiveFormsModule, 21 | HttpModule 22 | ], 23 | providers: [], 24 | bootstrap: [AppComponent] 25 | }) 26 | export class AppModule { } 27 | -------------------------------------------------------------------------------- /ch08/product-manager/src/app/manager-info/manager-info.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch08/product-manager/src/app/manager-info/manager-info.component.css -------------------------------------------------------------------------------- /ch08/product-manager/src/app/manager-info/manager-info.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 이름 7 | 8 |
9 |
10 |
11 |
12 | 연락처 13 | 14 |
15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /ch08/product-manager/src/app/manager-info/manager-info.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ManagerInfoComponent } from './manager-info.component'; 4 | 5 | describe('ManagerInfoComponent', () => { 6 | let component: ManagerInfoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ManagerInfoComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ManagerInfoComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ch08/product-manager/src/app/manager-info/manager-info.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'pm-manager-info', 5 | templateUrl: './manager-info.component.html', 6 | styleUrls: ['./manager-info.component.css'] 7 | }) 8 | export class ManagerInfoComponent implements OnInit { 9 | @Input() idx: number; 10 | @Input() manager; 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ch08/product-manager/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch08/product-manager/src/assets/.gitkeep -------------------------------------------------------------------------------- /ch08/product-manager/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ch08/product-manager/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ch08/product-manager/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/ch08/product-manager/src/favicon.ico -------------------------------------------------------------------------------- /ch08/product-manager/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ProductManager 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch08/product-manager/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /ch08/product-manager/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | fieldset { 3 | border: 1px solid lightblue; 4 | } 5 | 6 | input.ng-valid, textarea.ng-valid { 7 | border-bottom: 2px solid lightgreen; 8 | } 9 | 10 | input.ng-invalid:not(form), textarea.ng-invalid:not(form) { 11 | border-bottom: 2px solid lightsalmon; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /ch08/product-manager/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ch08/product-manager/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ch08/product-manager/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ch08/product-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/angular_first_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/resources/angular_first_cover.jpg -------------------------------------------------------------------------------- /resources/img.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/resources/img.zip -------------------------------------------------------------------------------- /simple-commerce-manager/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /simple-commerce-manager/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "hanbit-angular-first" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /simple-commerce-manager/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /simple-commerce-manager/database.rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | ".read": true, 4 | ".write": "auth != null", 5 | "product": { 6 | ".indexOn": ["no", "status", "catNo"] 7 | }, 8 | "category": { 9 | ".indexOn": ["no", "isUse"] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /simple-commerce-manager/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { SimpleCommerceManagerPage } from './app.po'; 2 | 3 | describe('simple-commerce-manager App', () => { 4 | let page: SimpleCommerceManagerPage; 5 | 6 | beforeEach(() => { 7 | page = new SimpleCommerceManagerPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('scm works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /simple-commerce-manager/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class SimpleCommerceManagerPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('scm-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /simple-commerce-manager/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /simple-commerce-manager/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "rules": "database.rules.json" 4 | }, 5 | "hosting": { 6 | "public": "dist", 7 | "rewrites": [ 8 | { 9 | "source": "**", 10 | "destination": "/index.html" 11 | } 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /simple-commerce-manager/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { MainDashboardComponent } from './scm-main/main-dashboard/main-dashboard.component'; 5 | import { PageNotFoundComponent } from './scm-main/page-not-found/page-not-found.component'; 6 | 7 | const routes: Routes = [ 8 | { path: 'total-summary', component: MainDashboardComponent }, 9 | { path: '', redirectTo: 'total-summary', pathMatch: 'full' }, 10 | { path: '**', component: PageNotFoundComponent } 11 | ]; 12 | 13 | @NgModule({ 14 | imports: [RouterModule.forRoot(routes)], 15 | exports: [RouterModule], 16 | }) 17 | export class AppRoutingModule { } 18 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .container-fluid { 2 | padding-top: 55px; 3 | padding-bottom: 57px; 4 | } 5 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 |
7 | 8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-detail/category-detail-resolver.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { CategoryDetailResolverService } from './category-detail-resolver.service'; 4 | 5 | describe('CategoryDetailResolverService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [CategoryDetailResolverService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([CategoryDetailResolverService], (service: CategoryDetailResolverService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-detail/category-detail.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/category/category-detail/category-detail.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-detail/category-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CategoryDetailComponent } from './category-detail.component'; 4 | 5 | describe('CategoryDetailComponent', () => { 6 | let component: CategoryDetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CategoryDetailComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CategoryDetailComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-item/category-item.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/category/category-management/category-item/category-item.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-item/category-item.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CategoryItemComponent } from './category-item.component'; 4 | 5 | describe('CategoryItemComponent', () => { 6 | let component: CategoryItemComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CategoryItemComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CategoryItemComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-item/category-item.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { Category } from "../../category.model"; 3 | 4 | @Component({ 5 | selector: 'scm-category-item', 6 | templateUrl: 'category-item.component.html', 7 | styleUrls: ['category-item.component.css'] 8 | }) 9 | export class CategoryItemComponent implements OnInit { 10 | @Input() category: Category; 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-list-resolver.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { CategoryListResolverService } from './category-list-resolver.service'; 4 | 5 | describe('CategoryListResolverService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [CategoryListResolverService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([CategoryListResolverService], (service: CategoryListResolverService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-list-resolver.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router"; 3 | import { CAT_LIST_PAGE_SIZE } from "../category.tokens"; 4 | import { Category, Categories } from "../category.model"; 5 | import { DataStoreService } from "../../shared/data-store.service"; 6 | import { Observable } from 'rxjs/Observable'; 7 | 8 | @Injectable() 9 | export class CategoryListResolverService implements Resolve { 10 | 11 | constructor(private database: DataStoreService, 12 | @Inject(CAT_LIST_PAGE_SIZE) private pageSize: number) { 13 | } 14 | 15 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 16 | return this.database.count('category') 17 | .switchMap(cnt => this.database.findList$ByPage('category', 1, this.pageSize, cnt)) 18 | .take(1) 19 | .map(actions => actions.map(action => action.payload.val())) 20 | .do((list: Categories) => list.sort((p1, p2) => p2.no - p1.no)) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-management.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/category/category-management/category-management.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-management.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 6 |
7 |
8 |
9 |
10 |

카테고리 목록

11 |
12 |
13 | 전체 카테고리: {{totalItemCnt}} 14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 | 23 |
24 |
-------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category-management/category-management.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CategoryManagementComponent } from './category-management.component'; 4 | 5 | describe('CategoryManagementComponent', () => { 6 | let component: CategoryManagementComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CategoryManagementComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CategoryManagementComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category.model.ts: -------------------------------------------------------------------------------- 1 | import { ScmBase } from "../shared/scm-base.model"; 2 | import { ScmSharedUtil } from "../shared/scm-shared-util"; 3 | 4 | export declare type Categories = Category[]; 5 | 6 | export class Category extends ScmBase { 7 | no: number; 8 | name: string; 9 | desc: string; 10 | 11 | constructor(no: number) { 12 | super(true, ScmSharedUtil.getCurrentDateTime(), ''); 13 | this.no = no; 14 | } 15 | } -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import { CategoryManagementComponent } from './category-management/category-management.component'; 6 | import { CategoryDetailComponent } from './category-detail/category-detail.component'; 7 | import { ReactiveFormsModule } from "@angular/forms"; 8 | import { CategoryRoutingModule } from "./category-routing.module"; 9 | import { CategoryItemComponent } from './category-management/category-item/category-item.component'; 10 | import { CAT_LIST_PAGE_SIZE } from './category.tokens'; 11 | 12 | @NgModule({ 13 | imports: [ 14 | CommonModule, 15 | ReactiveFormsModule, 16 | CategoryRoutingModule, 17 | NgbPaginationModule 18 | ], 19 | declarations: [CategoryManagementComponent, CategoryDetailComponent, CategoryItemComponent], 20 | providers: [{ provide: CAT_LIST_PAGE_SIZE, useValue: 3 }] 21 | }) 22 | export class CategoryModule { } 23 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/category/category.tokens.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from "@angular/core"; 2 | 3 | export const CAT_LIST_PAGE_SIZE = new InjectionToken('CAT_LIST_PAGE_SIZE'); 4 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/custom-toast-options.ts: -------------------------------------------------------------------------------- 1 | import { ToastOptions } from "ng2-toastr"; 2 | 3 | export class CustomToastOptions extends ToastOptions { 4 | enableHTML: true; 5 | positionClass: 'toast-top-center'; 6 | } -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-detail/product-detail-resolver.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ProductDetailResolverService } from './product-detail-resolver.service'; 4 | 5 | describe('ProductDetailResolverService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ProductDetailResolverService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([ProductDetailResolverService], (service: ProductDetailResolverService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-detail/product-detail.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/product/product-detail/product-detail.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-detail/product-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProductDetailComponent } from './product-detail.component'; 4 | 5 | describe('ProductDetailComponent', () => { 6 | let component: ProductDetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProductDetailComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProductDetailComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/button-group/button-group.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/product/product-management/button-group/button-group.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/button-group/button-group.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/button-group/button-group.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ButtonGroupComponent } from './button-group.component'; 4 | 5 | describe('ButtonGroupComponent', () => { 6 | let component: ButtonGroupComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ButtonGroupComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ButtonGroupComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/button-group/button-group.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, EventEmitter, Output } from '@angular/core'; 2 | import { Router } from "@angular/router"; 3 | import { Observable } from 'rxjs/Observable'; 4 | import { CheckedProductSetService } from "../checked-product-set.service"; 5 | 6 | @Component({ 7 | selector: 'scm-button-group', 8 | templateUrl: './button-group.component.html', 9 | styleUrls: ['./button-group.component.css'] 10 | }) 11 | export class ButtonGroupComponent implements OnInit { 12 | noneNo$: Observable; 13 | @Output() onClicked: EventEmitter = new EventEmitter(); 14 | 15 | constructor(private router: Router, private prodSet: CheckedProductSetService) { 16 | } 17 | 18 | ngOnInit() { 19 | this.mapNoneKeyObservable(); 20 | } 21 | 22 | private mapNoneKeyObservable() { 23 | this.noneNo$ = this.prodSet.hasNo$.map(hasNo => !hasNo); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/checked-product-set.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { CheckedProductSetService } from './checked-product-set.service'; 4 | 5 | describe('CheckedProductSetService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [CheckedProductSetService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([CheckedProductSetService], (service: CheckedProductSetService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/checked-product-set.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs/Observable'; 3 | import { Subject } from 'rxjs/Subject'; 4 | import { BehaviorSubject } from "rxjs/BehaviorSubject"; 5 | 6 | @Injectable() 7 | export class CheckedProductSetService { 8 | prodNoSet = new Set(); 9 | hasNo$: Observable; 10 | private hasNoSubject: Subject = new BehaviorSubject(false); 11 | 12 | constructor() { 13 | this.hasNo$ = this.hasNoSubject.asObservable(); 14 | } 15 | 16 | initProdNos() { 17 | this.prodNoSet = new Set(); 18 | this._notifyExistence(); 19 | } 20 | 21 | addNo(no: number) { 22 | this.prodNoSet.add(no); 23 | this._notifyExistence(); 24 | } 25 | 26 | removeNo(no: number) { 27 | this.prodNoSet.delete(no); 28 | this._notifyExistence(); 29 | } 30 | 31 | nos$() { 32 | return Observable.from(Array.from(this.prodNoSet)); 33 | } 34 | 35 | private _notifyExistence() { 36 | const hasNo = this.prodNoSet.size > 0; 37 | this.hasNoSubject.next(hasNo); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-bulk-updater.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ProductBulkUpdaterService } from './product-bulk-updater.service'; 4 | 5 | describe('ProductBulkUpdaterService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ProductBulkUpdaterService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([ProductBulkUpdaterService], (service: ProductBulkUpdaterService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-list/product-list-resolver.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ProductListResolverService } from './product-list-resolver.service'; 4 | 5 | describe('ProductListResolverService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ProductListResolverService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([ProductListResolverService], (service: ProductListResolverService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-list/product-list-resolver.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Inject } from '@angular/core'; 2 | import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router"; 3 | import { Product, Products } from "../../product.model"; 4 | import { PROD_LIST_PAGE_SIZE } from "../../product.tokens"; 5 | import { DataStoreService } from "../../../shared/data-store.service"; 6 | 7 | @Injectable() 8 | export class ProductListResolverService implements Resolve { 9 | 10 | constructor(private database: DataStoreService, 11 | @Inject(PROD_LIST_PAGE_SIZE) private pageSize: number) { 12 | } 13 | 14 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 15 | return this.database.count('product') 16 | .switchMap(cnt => this.database.findList$ByPage('product', 1, this.pageSize, cnt)) 17 | .take(1) 18 | .map(actions => actions.map(action => action.payload.val())) 19 | .do((list: Products) => list.sort((p1, p2) => p2.no - p1.no)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-list/product-list.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/product/product-management/product-list/product-list.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-list/product-list.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
5 | 7 | #상품명상품가격상품 상태
{{prod.no}}{{prod.name}}{{prod.listPrice}}{{prod.status | productStatus}}
25 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-list/product-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProductListComponent } from './product-list.component'; 4 | 5 | describe('ProductListComponent', () => { 6 | let component: ProductListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProductListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProductListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-management.component.css: -------------------------------------------------------------------------------- 1 | #cur-page-size { 2 | width: 60px; 3 | } 4 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-management/product-management.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProductManagementComponent } from './product-management.component'; 4 | 5 | describe('ProductManagementComponent', () => { 6 | let component: ProductManagementComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProductManagementComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProductManagementComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-status.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ProductStatusPipe } from './product-status.pipe'; 2 | 3 | describe('ProductStatusPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ProductStatusPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product-status.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { ProdStatus } from "./product.model"; 3 | 4 | @Pipe({ 5 | name: 'productStatus' 6 | }) 7 | export class ProductStatusPipe implements PipeTransform { 8 | private labelMap; 9 | 10 | constructor() { 11 | this.labelMap = {}; 12 | this.labelMap[ProdStatus.WAIT_FOR_SALE] = '판매 대기'; 13 | this.labelMap[ProdStatus.ON_SALE] = '판매 중'; 14 | this.labelMap[ProdStatus.NOT_FOR_SALE] = '판매 중지'; 15 | } 16 | 17 | transform(value: ProdStatus, args?: any): any { 18 | if (value !== undefined && this.labelMap.hasOwnProperty(value)) { 19 | return this.labelMap[value]; 20 | } 21 | 22 | return '-'; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product.model.ts: -------------------------------------------------------------------------------- 1 | import { ScmBase } from "../shared/scm-base.model"; 2 | import { ScmSharedUtil } from "../shared/scm-shared-util"; 3 | 4 | export enum ProdStatus { WAIT_FOR_SALE, ON_SALE, NOT_FOR_SALE } 5 | export declare type Products = Product[]; 6 | 7 | export class Product extends ScmBase { 8 | no: number; 9 | name: string; 10 | listPrice: number; 11 | status: ProdStatus; 12 | qty: number; 13 | desc?: string; 14 | catNo?: number; 15 | 16 | constructor(no: number, status: ProdStatus) { 17 | super(true, ScmSharedUtil.getCurrentDateTime(), ''); 18 | this.no = no; 19 | this.name = ''; 20 | this.listPrice = 0; 21 | this.status = status; 22 | this.qty = 0; 23 | this.desc = ''; 24 | this.catNo = 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/product/product.tokens.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken } from "@angular/core"; 2 | export const PROD_LIST_PAGE_SIZE = new InjectionToken('PROD_LIST_PAGE_SIZE'); 3 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/footer/footer.component.css: -------------------------------------------------------------------------------- 1 | .scm-footer { 2 | padding: 1rem; 3 | text-align: center; 4 | z-index: 1000; 5 | border-top: 1px solid darkgray; 6 | } 7 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/footer/footer.component.html: -------------------------------------------------------------------------------- 1 |
2 | © {{thisYear}} Simple Commerce Manager in 한빛미디어 앵귤러 첫걸음 3 |
4 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FooterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'scm-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.css'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | thisYear: number = new Date().getFullYear(); 10 | 11 | constructor() {} 12 | ngOnInit() {} 13 | } 14 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/main-dashboard/main-dashboard.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/scm-main/main-dashboard/main-dashboard.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/main-dashboard/main-dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |

상품 상태 현황

3 |
4 |
5 | 6 |
7 |
8 |

카테고리 별 상품 현황

9 |
10 |
11 | 12 |
13 |
14 |
-------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/main-dashboard/main-dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MainDashboardComponent } from './main-dashboard.component'; 4 | 5 | describe('MainDashboardComponent', () => { 6 | let component: MainDashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MainDashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MainDashboardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/navbar/navbar.component.css: -------------------------------------------------------------------------------- 1 | .scm-navbar { 2 | border-bottom: 1px solid darkgray; 3 | background-color: #3d4752; 4 | } 5 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/navbar/navbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavbarComponent } from './navbar.component'; 4 | 5 | describe('NavbarComponent', () => { 6 | let component: NavbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NavbarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NavbarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/page-not-found/page-not-found.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/app/scm-main/page-not-found/page-not-found.component.css -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/page-not-found/page-not-found.component.html: -------------------------------------------------------------------------------- 1 |

2 | page-not-found works! 3 |

4 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/page-not-found/page-not-found.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageNotFoundComponent } from './page-not-found.component'; 4 | 5 | describe('PageNotFoundComponent', () => { 6 | let component: PageNotFoundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PageNotFoundComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageNotFoundComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/page-not-found/page-not-found.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'scm-page-not-found', 5 | templateUrl: './page-not-found.component.html', 6 | styleUrls: ['./page-not-found.component.css'] 7 | }) 8 | export class PageNotFoundComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/scm-main.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule } from '@angular/router' 4 | import { ChartsModule } from 'ng2-charts'; 5 | 6 | import { NavbarComponent } from './navbar/navbar.component'; 7 | import { SidebarComponent } from './sidebar/sidebar.component'; 8 | import { FooterComponent } from './footer/footer.component'; 9 | import { MainDashboardComponent } from './main-dashboard/main-dashboard.component'; 10 | import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; 11 | 12 | const CORE_COMPONENTS = [NavbarComponent, SidebarComponent, FooterComponent, 13 | MainDashboardComponent, PageNotFoundComponent]; 14 | 15 | @NgModule({ 16 | imports: [CommonModule, RouterModule, ChartsModule], 17 | declarations: CORE_COMPONENTS, 18 | exports: CORE_COMPONENTS 19 | }) 20 | export class ScmMainModule { } 21 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/sidebar/sidebar.component.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | position: fixed; 3 | top: 51px; 4 | bottom: 0; 5 | left: 0; 6 | z-index: 10; 7 | padding: 20px; 8 | overflow-x: hidden; 9 | overflow-y: auto; 10 | border-right: 1px solid #eee; 11 | } 12 | 13 | .sidebar { 14 | padding-left: 0; 15 | padding-right: 0; 16 | } 17 | 18 | .sidebar .nav { 19 | margin-bottom: 20px; 20 | } 21 | 22 | .sidebar .nav-item { 23 | width: 100%; 24 | } 25 | 26 | .sidebar .nav-item + .nav-item { 27 | margin-left: 0; 28 | } 29 | 30 | .sidebar .nav-link { 31 | border-radius: 0; 32 | } 33 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/sidebar/sidebar.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/sidebar/sidebar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SidebarComponent } from './sidebar.component'; 4 | 5 | describe('SidebarComponent', () => { 6 | let component: SidebarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SidebarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SidebarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/scm-main/sidebar/sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | export declare type SidebarMenu = 'not_selected' | 'product' | 'category'; 3 | 4 | @Component({ 5 | selector: 'scm-sidebar', 6 | templateUrl: './sidebar.component.html', 7 | styleUrls: ['./sidebar.component.css'] 8 | }) 9 | export class SidebarComponent { } 10 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/can-deactivate-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { CanDeactivateGuardService } from './can-deactivate-guard.service'; 4 | 5 | describe('CanDeactivateGuardService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [CanDeactivateGuardService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([CanDeactivateGuardService], (service: CanDeactivateGuardService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/can-deactivate-guard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CanDeactivate } from "@angular/router"; 3 | import { Observable } from 'rxjs/Observable'; 4 | 5 | export interface CanComponentDeactivate { 6 | canDeactivate: () => Observable | Promise | boolean; 7 | } 8 | 9 | @Injectable() 10 | export class CanDeactivateGuardService implements CanDeactivate { 11 | canDeactivate(component: CanComponentDeactivate) { 12 | return component.canDeactivate ? component.canDeactivate() : true; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/custom-validators.ts: -------------------------------------------------------------------------------- 1 | import { AbstractControl } from '@angular/forms'; 2 | 3 | 4 | export class NumberRangeValidator { 5 | static min(min: number) { 6 | return (control: AbstractControl): {[key: string]: any} => { 7 | return control.value >= min ? null : {'min': `${min} 이상의 값을 입력하세요`}; 8 | }; 9 | } 10 | 11 | static max(max: number) { 12 | return (control: AbstractControl): {[key: string]: any} => { 13 | return control.value <= max ? null : {'max': `${max} 이하의 값을 입력하세요`}; 14 | } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/data-store.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { DataStoreService } from './data-store.service'; 4 | 5 | describe('DataStoreService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [DataStoreService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([DataStoreService], (service: DataStoreService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/loading-spinner/loading-spinner.component.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/loading-spinner/loading-spinner.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadingSpinnerComponent } from './loading-spinner.component'; 4 | 5 | describe('LoadingSpinnerComponent', () => { 6 | let component: LoadingSpinnerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoadingSpinnerComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoadingSpinnerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/loading-spinner/loading-spinner.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { SpinnerService } from "./spinner.service"; 3 | 4 | @Component({ 5 | selector: 'scm-loading-spinner', 6 | templateUrl: './loading-spinner.component.html', 7 | styleUrls: ['./loading-spinner.component.css'] 8 | }) 9 | export class LoadingSpinnerComponent implements OnInit { 10 | loading: boolean; 11 | 12 | constructor(spinner: SpinnerService) { 13 | spinner.getLoading$() 14 | .do(l => console.log(`current spinner status: ${l}`)) 15 | .subscribe(l => this.loading = l); 16 | } 17 | 18 | ngOnInit() {} 19 | } 20 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/loading-spinner/spinner.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { SpinnerService } from './spinner.service'; 4 | 5 | describe('SpinnerService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [SpinnerService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([SpinnerService], (service: SpinnerService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/loading-spinner/spinner.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, EventEmitter } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class SpinnerService { 5 | private _asyncCounter: number = 0; 6 | private _loading$: EventEmitter = new EventEmitter(); 7 | 8 | constructor() { 9 | this._loading$.emit(false); 10 | } 11 | 12 | getLoading$() { 13 | return this._loading$; 14 | } 15 | 16 | start() { 17 | console.log('request loading spinner start'); 18 | if(this._asyncCounter === 0) this._loading$.emit(true); 19 | this._asyncCounter++; 20 | } 21 | 22 | stop() { 23 | console.log('request loading spinner stop'); 24 | this._asyncCounter--; 25 | if(this._asyncCounter === 0) this._loading$.emit(false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/no-counter.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { NoCounterService } from './no-counter.service'; 4 | 5 | describe('NoCounterService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [NoCounterService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([NoCounterService], (service: NoCounterService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/scm-base.model.ts: -------------------------------------------------------------------------------- 1 | export class ScmBase { 2 | isUse: boolean; 3 | createdTime: string; 4 | updatedTime: string; 5 | 6 | constructor(isUse: boolean, createdTime: string, updatedTime: string) { 7 | this.isUse = isUse; 8 | this.createdTime = createdTime; 9 | this.updatedTime = updatedTime; 10 | } 11 | } -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/scm-shared-util.ts: -------------------------------------------------------------------------------- 1 | import * as format from 'date-fns/format'; 2 | 3 | export declare type ScmDomain = 'product' | 'category'; 4 | export declare type ActionMode = 'create' | 'read' | 'edit'; 5 | 6 | export class ScmSharedUtil { 7 | 8 | constructor() { } 9 | 10 | static getCurrentDate() { 11 | return format(new Date(), 'YYYY-MM-DD'); 12 | } 13 | 14 | static getCurrentDateTime() { 15 | return format(new Date(), 'YYYY-MM-DD HH:mm:ss'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/session-auth-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { SessionAuthGuardService } from './session-auth-guard.service'; 4 | 5 | describe('SessionAuthGuardService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [SessionAuthGuardService] 9 | }); 10 | }); 11 | 12 | it('should ...', inject([SessionAuthGuardService], (service: SessionAuthGuardService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/session-auth-guard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router"; 3 | import { ToastsManager } from "ng2-toastr"; 4 | import { AngularFireAuth } from 'angularfire2/auth'; 5 | 6 | @Injectable() 7 | export class SessionAuthGuardService { 8 | constructor( 9 | private router: Router, 10 | private toastr: ToastsManager, 11 | private afAuth: AngularFireAuth) { } 12 | 13 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 14 | return this.afAuth.authState 15 | .take(1) 16 | .map(user => !!user) 17 | .do(authenticated => { 18 | if (!authenticated) { 19 | this.toastr.error('로그인 해주세요', '[오류]'); 20 | this.router.navigate(['/']); 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/app/shared/shared.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { NoCounterService } from './no-counter.service'; 4 | import { DataStoreService } from './data-store.service'; 5 | import { LoadingSpinnerComponent } from './loading-spinner/loading-spinner.component'; 6 | import { SpinnerService } from './loading-spinner/spinner.service'; 7 | import { CanDeactivateGuardService } from './can-deactivate-guard.service'; 8 | import { SessionAuthGuardService } from './session-auth-guard.service'; 9 | 10 | @NgModule({ 11 | imports: [CommonModule], 12 | providers: [NoCounterService, DataStoreService, SpinnerService, CanDeactivateGuardService, SessionAuthGuardService], 13 | declarations: [LoadingSpinnerComponent], 14 | exports: [LoadingSpinnerComponent] 15 | }) 16 | export class SharedModule { } 17 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/assets/.gitkeep -------------------------------------------------------------------------------- /simple-commerce-manager/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | firebase: { 4 | apiKey: "AIzaSyAyIdgL5mQTJY9pW1P14OmLVzw3chw41tU", 5 | authDomain: "hanbit-angular-first.firebaseapp.com", 6 | databaseURL: "https://hanbit-angular-first.firebaseio.com", 7 | projectId: "hanbit-angular-first", 8 | storageBucket: "hanbit-angular-first.appspot.com", 9 | messagingSenderId: "721541388016" 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | firebase: { 9 | apiKey: "AIzaSyAyIdgL5mQTJY9pW1P14OmLVzw3chw41tU", 10 | authDomain: "hanbit-angular-first.firebaseapp.com", 11 | databaseURL: "https://hanbit-angular-first.firebaseio.com", 12 | projectId: "hanbit-angular-first", 13 | storageBucket: "hanbit-angular-first.appspot.com", 14 | messagingSenderId: "721541388016" 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/simple-commerce-manager/src/favicon.ico -------------------------------------------------------------------------------- /simple-commerce-manager/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SimpleCommerceManager 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | input.ng-valid:not([readonly]), textarea.ng-valid:not([readonly]), select.ng-valid:not([readonly]) { 3 | border-bottom: 2px solid lightgreen; 4 | } 5 | 6 | input.ng-invalid:not(form), textarea.ng-invalid:not(form), select.ng-invalid:not(form) { 7 | border-bottom: 2px solid lightsalmon; 8 | } 9 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /simple-commerce-manager/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /simple-commerce-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /spring-boot-starter/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ 25 | 26 | src/main/resources/static -------------------------------------------------------------------------------- /spring-boot-starter/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/spring-boot-starter/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-boot-starter/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip 2 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppWithBootPage } from './app.po'; 2 | 3 | describe('app-with-boot App', () => { 4 | let page: AppWithBootPage; 5 | 6 | beforeEach(() => { 7 | page = new AppWithBootPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppWithBootPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/": { 3 | "target": "http://localhost:8080", 4 | "secure": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/spring-boot-starter/src/main/frontend/src/app/app.component.css -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'app'; 10 | } 11 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppComponent } from './app.component'; 5 | 6 | @NgModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | imports: [ 11 | BrowserModule 12 | ], 13 | providers: [], 14 | bootstrap: [AppComponent] 15 | }) 16 | export class AppModule { } 17 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/spring-boot-starter/src/main/frontend/src/assets/.gitkeep -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/not-for-me/hb-angular-first/dffb49f412fc97ba9fcf5999e251cf2daff4d5b1/spring-boot-starter/src/main/frontend/src/favicon.ico -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppWithBoot 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2016", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/java/kr/notforme/starter/SpringBootAngularStarterApplication.java: -------------------------------------------------------------------------------- 1 | package kr.notforme.starter; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringBootAngularStarterApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringBootAngularStarterApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-boot-starter/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.devtools.restart.exclude=META-INF/maven/**,META-INF/resources/**,resources/**,public/**,templates/**,**/*Test.class,**/*Tests.class,git.properties,META-INF/build-info.properties" 2 | -------------------------------------------------------------------------------- /spring-boot-starter/src/test/java/kr/notforme/starter/SpringBootAngularStarterApplicationTests.java: -------------------------------------------------------------------------------- 1 | package kr.notforme.starter; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootAngularStarterApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------