├── .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 |
--------------------------------------------------------------------------------
/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 |
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 |
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 |
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 |
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 |
8 |
카테고리 별 상품 현황
9 |
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 |
--------------------------------------------------------------------------------