├── README.md
├── week1
├── 1
│ ├── README.md
│ └── todoApp
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── .vscode
│ │ ├── launch.json
│ │ └── tasks.json
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── bs-config.e2e.json
│ │ ├── bs-config.json
│ │ ├── e2e
│ │ ├── app.e2e-spec.ts
│ │ └── tsconfig.json
│ │ ├── karma-test-shim.js
│ │ ├── karma.conf.js
│ │ ├── non-essential-files.txt
│ │ ├── package.json
│ │ ├── protractor.config.js
│ │ ├── src
│ │ ├── app
│ │ │ ├── add.component
│ │ │ │ ├── add.component.css
│ │ │ │ ├── add.component.html
│ │ │ │ └── add.component.ts
│ │ │ ├── app.component.spec.ts
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── enums
│ │ │ │ └── filter.ts
│ │ │ ├── filter.component
│ │ │ │ ├── filter.component.css
│ │ │ │ ├── filter.component.html
│ │ │ │ └── filter.component.ts
│ │ │ ├── list.component
│ │ │ │ ├── list.component.css
│ │ │ │ ├── list.component.html
│ │ │ │ └── list.component.ts
│ │ │ └── todo.model.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── styles.css
│ │ ├── systemjs.config.extras.js
│ │ ├── systemjs.config.js
│ │ └── tsconfig.json
│ │ └── tslint.json
└── 2
│ ├── README.md
│ └── solutionsApp
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .travis.yml
│ ├── .vscode
│ ├── launch.json
│ └── tasks.json
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── bs-config.e2e.json
│ ├── bs-config.json
│ ├── e2e
│ ├── app.e2e-spec.ts
│ └── tsconfig.json
│ ├── karma-test-shim.js
│ ├── karma.conf.js
│ ├── non-essential-files.txt
│ ├── package.json
│ ├── protractor.config.js
│ ├── src
│ ├── app
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── clock.component
│ │ │ └── clock.component.ts
│ │ └── rxjs.practice.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── styles.css
│ ├── systemjs.config.extras.js
│ ├── systemjs.config.js
│ └── tsconfig.json
│ └── tslint.json
├── week2
├── 1
│ ├── README.md
│ └── tasks
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ ├── .vscode
│ │ ├── settings.json
│ │ └── tasks.json
│ │ ├── README.md
│ │ ├── angular-cli.json
│ │ ├── e2e
│ │ ├── app.e2e-spec.ts
│ │ ├── app.po.ts
│ │ └── tsconfig.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
│ │ │ └── directives
│ │ │ │ ├── directives.module.ts
│ │ │ │ ├── grid
│ │ │ │ ├── grid.component.css
│ │ │ │ ├── grid.component.html
│ │ │ │ ├── grid.component.spec.ts
│ │ │ │ └── grid.component.ts
│ │ │ │ ├── pager.directive.spec.ts
│ │ │ │ └── pager.directive.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── styles.css
│ │ ├── test.ts
│ │ └── tsconfig.json
│ │ └── tslint.json
└── 2
│ └── README.md
├── week3
├── 1
│ ├── README.md
│ └── ngrxTodoApp
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ ├── .vscode
│ │ └── tasks.json
│ │ ├── README.md
│ │ ├── angular-cli.json
│ │ ├── e2e
│ │ ├── app.e2e-spec.ts
│ │ ├── app.po.ts
│ │ └── tsconfig.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
│ │ │ ├── filter-state.enum.ts
│ │ │ ├── store
│ │ │ │ ├── app.actions.ts
│ │ │ │ ├── app.model.ts
│ │ │ │ ├── app.reducer.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── reducer-factory.ts
│ │ │ ├── todo-edit
│ │ │ │ ├── todo-edit.component.css
│ │ │ │ ├── todo-edit.component.html
│ │ │ │ ├── todo-edit.component.spec.ts
│ │ │ │ └── todo-edit.component.ts
│ │ │ ├── todo-filter
│ │ │ │ ├── todo-filter.component.css
│ │ │ │ ├── todo-filter.component.html
│ │ │ │ ├── todo-filter.component.spec.ts
│ │ │ │ └── todo-filter.component.ts
│ │ │ ├── todo-list
│ │ │ │ ├── todo-list.component.css
│ │ │ │ ├── todo-list.component.html
│ │ │ │ ├── todo-list.component.spec.ts
│ │ │ │ └── todo-list.component.ts
│ │ │ └── todo.model.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── styles.css
│ │ ├── test.ts
│ │ └── tsconfig.json
│ │ └── tslint.json
└── 2
│ └── README.md
├── week4
├── 1
│ └── README.md
└── 2
│ └── README.md
└── week5
├── 1
└── README.md
└── 2
└── README.md
/README.md:
--------------------------------------------------------------------------------
1 | # Angular 2 Course, Volume 2.0
2 |
3 | ### The second edition of the Angular 2 course in HackBulgaria.
4 |
5 | This course is NOT for beginners - JavaScript experience is required.
6 |
7 | Throughout the course we'll be learning Angular 2 fundamentals - setup, components, services, routes, deployment, etc.
8 |
9 | TypeScript will be the language of choice when we're building our applications.
10 |
11 | ## Course Program
12 |
13 | The duration of the course is 5 weeks including 10 lectures:
14 |
15 | 01. Introduction: Concepts of Angular 2. Introduction to TypeScript, Component Basics and Build-in Directives.
16 | 02. Advanced Components: Inputs, Outputs, Content Projection, ViewChildren, ContentChildren.
17 | 03. Deep dive into Directives: Dependency Injection (Providers and Injectors), TemplateRef, ViewContainerRef.
18 | 04. Change Detection and Component / Directive Lifecycle.
19 | 05. Functional Programming, Reactive Extensions for JS. Optimizing Anglar Change Detection using RxJS.
20 | 06. The Controlled State Container: ngrx/store (Reactive Redux implementation for Angular 2) and ngrx/effects. Optimizing Change Detection using ngrx.
21 | 07. Forms and validations.
22 | 08. Multi-providers. Template driven custom validators and Custom Controls.
23 | 09. Routing and Navigation.
24 | 10. Protecting Routes. Lazy Loading. Pipes. Angular 4 and beyond.
25 |
26 | You can apply here: https://hackbulgaria.com/courses/angular2-volume2/
27 |
--------------------------------------------------------------------------------
/week1/1/README.md:
--------------------------------------------------------------------------------
1 | # Week 1.1
2 | ### Lecture
3 | [Click here](https://speakerdeck.com/iliaidakiev/1-ng-introduction)
4 | ### Tasks
5 | 1. Install node & npm
6 | 2. Install git
7 | 3. Install Visual Stuido Code, TSLint & Trailing Space Plugins (Optional)
8 | 4. Clone [quickstart repo](http://github.com/angular/quickstart)
9 | 5. Todos app: Create at least two (presentational) components - one for listing the todos and another for adding them. Use angular bindings to share state between the components. Create functionality for completing and deleting a todo. By default list component should show only the uncompleted todos. Create a filter that provides a way to manipulate the list by showing only the completed and showing all - completed and uncompleted (use styling to show the active filter state). Don't forget to separate code into different files and make good use of TypeScript.
--------------------------------------------------------------------------------
/week1/1/todoApp/.editorconfig:
--------------------------------------------------------------------------------
1 | # 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 |
12 | [*.md]
13 | max_line_length = 0
14 | trim_trailing_whitespace = false
15 |
16 | # Indentation override
17 | #[lib/**.js]
18 | #[{package.json,.travis.yml}]
19 | #[**/**.js]
20 |
--------------------------------------------------------------------------------
/week1/1/todoApp/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | jspm_packages
4 | npm-debug.log
5 | debug.log
6 | src/**/*.js
7 | !src/systemjs.config.extras.js
8 | !src/systemjs.config.js
9 | *.js.map
10 | e2e/**/*.js
11 | e2e/**/*.js.map
12 | _test-output
13 | _temp
14 |
--------------------------------------------------------------------------------
/week1/1/todoApp/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: required
3 | language: node_js
4 | node_js:
5 | - "5"
6 | os:
7 | - linux
8 | env:
9 | global:
10 | - DBUS_SESSION_BUS_ADDRESS=/dev/null
11 | - DISPLAY=:99.0
12 | - CHROME_BIN=chromium-browser
13 | before_script:
14 | - sh -e /etc/init.d/xvfb start
15 | install:
16 | - npm install
17 | script:
18 | - npm run lint
19 | - npm run test:once
20 | - npm run e2e
21 |
--------------------------------------------------------------------------------
/week1/1/todoApp/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible Node.js debug attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "program": "${workspaceRoot}/serve\"",
12 | "cwd": "${workspaceRoot}",
13 | "outFiles": []
14 | },
15 | {
16 | "type": "node",
17 | "request": "attach",
18 | "name": "Attach to Process",
19 | "port": 5858,
20 | "outFiles": []
21 | }
22 | ]
23 | }
--------------------------------------------------------------------------------
/week1/1/todoApp/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "0.1.0",
5 | "command": "echo",
6 | "isShellCommand": true,
7 | "args": ["Hello World"],
8 | "showOutput": "never"
9 | }
--------------------------------------------------------------------------------
/week1/1/todoApp/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Angular Documentation QuickStart Changelog
2 | Upgraders: for a fresh start, consider running these commands
3 | * `git clean -xdf`
4 | * `npm install`
5 |
6 |
7 | # 0.2.22 (2017-01-05)
8 | * Add `non-essential-files.txt` and instructions to use it to README
9 |
10 |
11 | # 0.2.21 (2016-12-14)
12 | * Update to in-memory-web-api v.0.2.1
13 |
14 |
15 | # 0.2.20 (2016-12-07)
16 | * Update to Angular 2.3.0
17 |
18 |
19 | # 0.2.19 (2016-11-30)
20 | * remove upgrade mappings from `systemjs.config.js` PR #301
21 |
22 |
23 | # 0.2.18 (2016-11-30)
24 | * remove `exclude` clause from `tsconfig.json`; it was just confusing people
25 | * karma.config + karma-test-shim can handle multiple spec source paths (issue #294)
26 | * cosmetic `app.component.spec.ts` changes
27 | * cosmetic `karma.config.js` changes
28 |
29 |
30 | # 0.2.17 (2016-11-16)
31 | * Conform to updated QuickStart advice
32 | * removed docker everywhere (was nice but not necessary)
33 | * removed wallaby
34 | * shrink styles.css
35 | * refine tsconfig.json
36 | * `AppComponent` uses interpolation
37 |
38 |
39 | # 0.2.16 (2016-11-14)
40 | * Update to Angular 2.2.0
41 |
42 |
43 | # 0.2.15 (2016-10-29)
44 | * Revert to Jasmine 2.4.1 because bug in 2.5.x (see [jasmine issue #1231](https://github.com/jasmine/jasmine/issues/1231))
45 |
46 |
47 | # 0.2.14 (2016-10-29)
48 | * Remove bootstrap.css install
49 | * Angular v2.1.2
50 |
51 |
52 | # 0.2.13 (2016-10-20)
53 | * Protractor 4
54 | * Move from `typings` to `@types`. See `tsconfig.json` changes.
55 | * Angular v2.1.1
56 |
57 |
58 | # 0.2.12 (2016-10-06)
59 | * Angular v2.1.0
60 |
61 |
62 | # 0.2.11 (2016-10-06)
63 | * Angular v2.0.2
64 | * License is MIT
65 | * Current testing configuration
66 | * No code changes
67 |
68 |
69 | # 0.2.10 (2016-09-19)
70 | * All "Angular 2" references become just "Angular"
71 | * No code changes
72 |
73 |
74 | # 0.2.9 (2016-09-14)
75 | * Angular 2.0.0 version
76 | * Update to Typescript 2.0.2
77 | * Fix e2e test missing dir
78 |
79 |
80 | # 0.2.8 (2016-09-01)
81 | * remove @angular test libraries from system.js (now in shim)
82 | * update test related files
83 | * wallaby doesn't completely work. Researching.
84 |
85 |
86 | # 0.2.7 (2016-08-31)
87 | * Angular 2 RC6 version
88 | * Updated new forms, router, angular2-in-memory-web-api, karma, core-js, rxjs and zone.js packages
89 | * Removed router-deprecated package
90 | * Updated karma.conf.js and systemjs.config.js
91 |
92 |
93 | # 0.2.6 (2016-08-09)
94 | * Angular 2 RC5 version
95 | * Updated new forms, router and angular2-in-memory-web-api
96 |
97 |
98 | # 0.2.5 (2016-06-30)
99 | * Angular 2 RC4 version
100 | * Updated new forms and router
101 |
102 |
103 | # 0.2.4 (2016-06-21)
104 | * Angular 2 RC3 version
105 | * Add new forms and router
106 | * Add support for TS e2e tests
107 |
108 |
109 | # 0.2.3 (2016-06-15)
110 | * Angular 2 RC2 version
111 |
112 |
113 | # 0.2.2 (2016-05-21)
114 | * Update to Typings 1.x
115 |
116 |
117 | # 0.2.1 (2016-05-03)
118 | * Angular 2 RC01 version
119 |
120 |
121 | # 0.2.0 (2016-05-02)
122 | * Angular 2 RC0 version
123 |
124 |
125 | # 0.1.17 (2016-04-29)
126 | * update packages
127 | * Angular 2 beta 17
128 | * RxJS 5.0.0-beta.6
129 | * a2-in-memory-web-api 0.1.17
130 |
131 |
132 | # 0.1.16 (2016-04-26)
133 | * update packages
134 | * Angular 2 beta 16
135 | * a2-in-memory-web-api 0.1.6
136 | * protractor 3.3.0
137 | * typings 0.8.1
138 | * zone.js 0.6.12
139 |
140 | * added favicon.ico
141 |
142 | * testing
143 | - updated wallaby.js and karma.conf.js
144 | - updated app.component.spec.ts
145 |
146 |
147 |
148 | # 0.1.15 (2016-04-13)
149 | * Add testing support
150 | * npm scripts
151 | * karma/jasmine
152 | * protractor
153 |
154 | * update packages
155 | * Angular 2 beta 15
156 | * lite-server 2.2.0
157 | * systemjs 0.19.26
158 | * typescript 1.8.10
159 | * typings 0.7.12
160 |
161 | * add run packages
162 | * a2-in-memory-web-api
163 |
164 | * add testing dev-dependency packages
165 | * canonical-path: 0.0.2,
166 | * http-server: ^0.9.0,
167 | * jasmine-core: ~2.4.1,
168 | * karma: ^0.13.22,
169 | * karma-chrome-launcher: ^0.2.3,
170 | * karma-cli: ^0.1.2,
171 | * karma-htmlfile-reporter: ^0.2.2,
172 | * karma-jasmine: ^0.3.8,
173 | * protractor: ^3.2.2,
174 | * rimraf: ^2.5.2
175 |
176 |
177 | # 0.1.14 (2016-04-07)
178 | * update packages
179 | * Angular 2 beta 14
180 | * lite-server 2.2.0
181 | * typings 0.7.12
182 |
183 |
184 | # 0.1.13 (2016-03-31)
185 | * update packages
186 | * Angular 2 beta 13
187 |
188 |
189 | # 0.1.12 (2016-03-23)
190 | * update packages
191 | * Angular 2 beta 12
192 | * zones 0.6.6
193 | * remove es6-promise because no longer needed.
194 |
195 |
196 | # 0.1.11 (2016-03-18)
197 | * update packages
198 | * Angular 2 beta 11
199 | * zones 0.6.4
200 | * typescript 1.8.9
201 | * typings 0.7.9
202 |
--------------------------------------------------------------------------------
/week1/1/todoApp/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2014-2016 Google, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/week1/1/todoApp/README.md:
--------------------------------------------------------------------------------
1 | # Very Simple Todo App
2 |
3 | * add todos
4 | * click on the todo to set it as complete or uncomplete
5 | * use filter to filter out todos
6 |
7 | # This app is build with angular QuickStart. QuickStart info bellow:
8 |
9 | # Angular QuickStart Source
10 | [![Build Status][travis-badge]][travis-badge-url]
11 |
12 | This repository holds the TypeScript source code of the [angular.io quickstart](https://angular.io/docs/ts/latest/quickstart.html),
13 | the foundation for most of the documentation samples and potentially a good starting point for your application.
14 |
15 | It's been extended with testing support so you can start writing tests immediately.
16 |
17 | **This is not the perfect arrangement for your application. It is not designed for production.
18 | It exists primarily to get you started quickly with learning and prototyping in Angular**
19 |
20 | We are unlikely to accept suggestions about how to grow this QuickStart into something it is not.
21 | Please keep that in mind before posting issues and PRs.
22 |
23 | ## Updating to a newer version of the Quickstart Repo
24 |
25 | From time to time the QuickStart will add be enhanced with support for new features or to reflect
26 | changes to the [official Style Guide](https://angular.io/docs/ts/latest/guide/style-guide.html).
27 |
28 | You can update your existing project to an up-to-date QuickStart by following these instructions:
29 | - Create a new project using the [instructions below](#create-a-new-project-based-on-the-quickstart)
30 | - Copy the code you have in your project's `main.ts` file onto `src/app/main.ts` in the new project
31 | - Copy your old `app` folder into `src/app`
32 | - Delete `src/app/main.ts` if you have one (we now use `src/main.ts` instead)
33 | - Copy your old `index.html`, `styles.css` and `tsconfig.json` into `src/`
34 | - Install all your third party dependencies
35 | - Copy your old `e2e/` folder into `e2e/`
36 | - Copy over any other files you added to your project
37 | - Copy your old `.git` folder into your new project's root
38 |
39 | Now you can continue working on the new project.
40 |
41 | ## Prerequisites
42 |
43 | Node.js and npm are essential to Angular development.
44 |
45 |
46 | Get it now if it's not already installed on your machine.
47 |
48 | **Verify that you are running at least node `v4.x.x` and npm `3.x.x`**
49 | by running `node -v` and `npm -v` in a terminal/console window.
50 | Older versions produce errors.
51 |
52 | We recommend [nvm](https://github.com/creationix/nvm) for managing multiple versions of node and npm.
53 |
54 | ## Create a new project based on the QuickStart
55 |
56 | Clone this repo into new project folder (e.g., `my-proj`).
57 | ```shell
58 | git clone https://github.com/angular/quickstart my-proj
59 | cd my-proj
60 | ```
61 |
62 | We have no intention of updating the source on `angular/quickstart`.
63 | Discard the `.git` folder..
64 | ```shell
65 | rm -rf .git # OS/X (bash)
66 | rd .git /S/Q # windows
67 | ```
68 | ### Delete _non-essential_ files (optional)
69 |
70 | You can quickly delete the _non-essential_ files that concern testing and QuickStart repository maintenance
71 | (***including all git-related artifacts*** such as the `.git` folder and `.gitignore`!)
72 | by entering the following commands while in the project folder:
73 |
74 | ##### OS/X (bash)
75 | ```shell
76 | xargs -a non-essential-files.txt rm -rf
77 | rm app/*.spec*.ts
78 | rm non-essential-files.txt
79 | ```
80 |
81 | ##### Windows
82 | ```shell
83 | for /f %i in (non-essential-files.txt) do del %i /F /S /Q
84 | rd .git /s /q
85 | rd e2e /s /q
86 | ```
87 |
88 | ### Create a new git repo
89 | You could [start writing code](#start-development) now and throw it all away when you're done.
90 | If you'd rather preserve your work under source control, consider taking the following steps.
91 |
92 | Initialize this project as a *local git repo* and make the first commit:
93 | ```shell
94 | git init
95 | git add .
96 | git commit -m "Initial commit"
97 | ```
98 |
99 | >Recover the deleted `.gitignore` from the QuickStart repository
100 | if you lost it in the _Delete non-essential files_ step.
101 |
102 | Create a *remote repository* for this project on the service of your choice.
103 |
104 | Grab its address (e.g. *`https://github.com//my-proj.git`*) and push the *local repo* to the *remote*.
105 | ```shell
106 | git remote add origin
107 | git push -u origin master
108 | ```
109 | ## Install npm packages
110 |
111 | > See npm and nvm version notes above
112 |
113 | Install the npm packages described in the `package.json` and verify that it works:
114 |
115 | ```shell
116 | npm install
117 | npm start
118 | ```
119 |
120 | >Doesn't work in _Bash for Windows_ which does not support servers as of January, 2017.
121 |
122 | The `npm start` command first compiles the application,
123 | then simultaneously re-compiles and runs the `lite-server`.
124 | Both the compiler and the server watch for file changes.
125 |
126 | Shut it down manually with `Ctrl-C`.
127 |
128 | You're ready to write your application.
129 |
130 | ### npm scripts
131 |
132 | We've captured many of the most useful commands in npm scripts defined in the `package.json`:
133 |
134 | * `npm start` - runs the compiler and a server at the same time, both in "watch mode".
135 | * `npm run build` - runs the TypeScript compiler once.
136 | * `npm run build:w` - runs the TypeScript compiler in watch mode; the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them.
137 | * `npm run serve` - runs the [lite-server](https://www.npmjs.com/package/lite-server), a light-weight, static file server, written and maintained by
138 | [John Papa](https://github.com/johnpapa) and
139 | [Christopher Martin](https://github.com/cgmartin)
140 | with excellent support for Angular apps that use routing.
141 |
142 | Here are the test related scripts:
143 | * `npm test` - compiles, runs and watches the karma unit tests
144 | * `npm run e2e` - compiles and run protractor e2e tests, written in Typescript (*e2e-spec.ts)
145 |
146 | ## Testing
147 |
148 | The QuickStart documentation doesn't discuss testing.
149 | This repo adds both karma/jasmine unit test and protractor end-to-end testing support.
150 |
151 | These tools are configured for specific conventions described below.
152 |
153 | *It is unwise and rarely possible to run the application, the unit tests, and the e2e tests at the same time.
154 | We recommend that you shut down one before starting another.*
155 |
156 | ### Unit Tests
157 | TypeScript unit-tests are usually in the `src/app` folder. Their filenames must end in `.spec.ts`.
158 |
159 | Look for the example `src/app/app.component.spec.ts`.
160 | Add more `.spec.ts` files as you wish; we configured karma to find them.
161 |
162 | Run it with `npm test`
163 |
164 | That command first compiles the application, then simultaneously re-compiles and runs the karma test-runner.
165 | Both the compiler and the karma watch for (different) file changes.
166 |
167 | Shut it down manually with `Ctrl-C`.
168 |
169 | Test-runner output appears in the terminal window.
170 | We can update our app and our tests in real-time, keeping a weather eye on the console for broken tests.
171 | Karma is occasionally confused and it is often necessary to shut down its browser or even shut the command down (`Ctrl-C`) and
172 | restart it. No worries; it's pretty quick.
173 |
174 | ### End-to-end (E2E) Tests
175 |
176 | E2E tests are in the `e2e` directory, side by side with the `src` folder.
177 | Their filenames must end in `.e2e-spec.ts`.
178 |
179 | Look for the example `e2e/app.e2e-spec.ts`.
180 | Add more `.e2e-spec.js` files as you wish (although one usually suffices for small projects);
181 | we configured Protractor to find them.
182 |
183 | Thereafter, run them with `npm run e2e`.
184 |
185 | That command first compiles, then simultaneously starts the `lite-server` at `localhost:8080`
186 | and launches Protractor.
187 |
188 | The pass/fail test results appear at the bottom of the terminal window.
189 | A custom reporter (see `protractor.config.js`) generates a `./_test-output/protractor-results.txt` file
190 | which is easier to read; this file is excluded from source control.
191 |
192 | Shut it down manually with `Ctrl-C`.
193 |
194 | [travis-badge]: https://travis-ci.org/angular/quickstart.svg?branch=master
195 | [travis-badge-url]: https://travis-ci.org/angular/quickstart
196 |
--------------------------------------------------------------------------------
/week1/1/todoApp/bs-config.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "open": false,
3 | "logLevel": "silent",
4 | "port": 8080,
5 | "server": {
6 | "baseDir": "src",
7 | "routes": {
8 | "/node_modules": "node_modules"
9 | },
10 | "middleware": {
11 | "0": null
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/week1/1/todoApp/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "baseDir": "src",
4 | "routes": {
5 | "/node_modules": "node_modules"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/week1/1/todoApp/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | describe('QuickStart E2E Tests', function () {
4 |
5 | let expectedMsg = 'Hello Angular';
6 |
7 | beforeEach(function () {
8 | browser.get('');
9 | });
10 |
11 | it('should display: ' + expectedMsg, function () {
12 | expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
13 | });
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/week1/1/todoApp/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "lib": [ "es2015", "dom" ],
10 | "noImplicitAny": true,
11 | "suppressImplicitAnyIndexErrors": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/week1/1/todoApp/karma-test-shim.js:
--------------------------------------------------------------------------------
1 | // /*global jasmine, __karma__, window*/
2 | Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.
3 |
4 | // Uncomment to get full stacktrace output. Sometimes helpful, usually not.
5 | // Error.stackTraceLimit = Infinity; //
6 |
7 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
8 |
9 | // builtPaths: root paths for output ("built") files
10 | // get from karma.config.js, then prefix with '/base/' (default is 'src/')
11 | var builtPaths = (__karma__.config.builtPaths || ['src/'])
12 | .map(function(p) { return '/base/'+p;});
13 |
14 | __karma__.loaded = function () { };
15 |
16 | function isJsFile(path) {
17 | return path.slice(-3) == '.js';
18 | }
19 |
20 | function isSpecFile(path) {
21 | return /\.spec\.(.*\.)?js$/.test(path);
22 | }
23 |
24 | // Is a "built" file if is JavaScript file in one of the "built" folders
25 | function isBuiltFile(path) {
26 | return isJsFile(path) &&
27 | builtPaths.reduce(function(keep, bp) {
28 | return keep || (path.substr(0, bp.length) === bp);
29 | }, false);
30 | }
31 |
32 | var allSpecFiles = Object.keys(window.__karma__.files)
33 | .filter(isSpecFile)
34 | .filter(isBuiltFile);
35 |
36 | System.config({
37 | // Base URL for System.js calls. 'base/' is where Karma serves files from.
38 | baseURL: 'base/src',
39 | // Extend usual application package list with test folder
40 | packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } },
41 |
42 | // Assume npm: is set in `paths` in systemjs.config
43 | // Map the angular testing umd bundles
44 | map: {
45 | '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
46 | '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
47 | '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
48 | '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
49 | '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
50 | '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
51 | '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
52 | '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
53 | },
54 | });
55 |
56 | System.import('systemjs.config.js')
57 | .then(importSystemJsExtras)
58 | .then(initTestBed)
59 | .then(initTesting);
60 |
61 | /** Optional SystemJS configuration extras. Keep going w/o it */
62 | function importSystemJsExtras(){
63 | return System.import('systemjs.config.extras.js')
64 | .catch(function(reason) {
65 | console.log(
66 | 'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.'
67 | );
68 | console.log(reason);
69 | });
70 | }
71 |
72 | function initTestBed(){
73 | return Promise.all([
74 | System.import('@angular/core/testing'),
75 | System.import('@angular/platform-browser-dynamic/testing')
76 | ])
77 |
78 | .then(function (providers) {
79 | var coreTesting = providers[0];
80 | var browserTesting = providers[1];
81 |
82 | coreTesting.TestBed.initTestEnvironment(
83 | browserTesting.BrowserDynamicTestingModule,
84 | browserTesting.platformBrowserDynamicTesting());
85 | })
86 | }
87 |
88 | // Import all spec files and start karma
89 | function initTesting () {
90 | return Promise.all(
91 | allSpecFiles.map(function (moduleName) {
92 | return System.import(moduleName);
93 | })
94 | )
95 | .then(__karma__.start, __karma__.error);
96 | }
97 |
--------------------------------------------------------------------------------
/week1/1/todoApp/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 |
3 | var appBase = 'src/'; // transpiled app JS and map files
4 | var appSrcBase = appBase; // app source TS files
5 |
6 | // Testing helpers (optional) are conventionally in a folder called `testing`
7 | var testingBase = 'testing/'; // transpiled test JS and map files
8 | var testingSrcBase = 'testing/'; // test source TS files
9 |
10 | config.set({
11 | basePath: '',
12 | frameworks: ['jasmine'],
13 |
14 | plugins: [
15 | require('karma-jasmine'),
16 | require('karma-chrome-launcher'),
17 | require('karma-jasmine-html-reporter')
18 | ],
19 |
20 | client: {
21 | builtPaths: [appBase, testingBase], // add more spec base paths as needed
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 |
25 | customLaunchers: {
26 | // From the CLI. Not used here but interesting
27 | // chrome setup for travis CI using chromium
28 | Chrome_travis_ci: {
29 | base: 'Chrome',
30 | flags: ['--no-sandbox']
31 | }
32 | },
33 |
34 | files: [
35 | // System.js for module loading
36 | 'node_modules/systemjs/dist/system.src.js',
37 |
38 | // Polyfills
39 | 'node_modules/core-js/client/shim.js',
40 |
41 | // zone.js
42 | 'node_modules/zone.js/dist/zone.js',
43 | 'node_modules/zone.js/dist/long-stack-trace-zone.js',
44 | 'node_modules/zone.js/dist/proxy.js',
45 | 'node_modules/zone.js/dist/sync-test.js',
46 | 'node_modules/zone.js/dist/jasmine-patch.js',
47 | 'node_modules/zone.js/dist/async-test.js',
48 | 'node_modules/zone.js/dist/fake-async-test.js',
49 |
50 | // RxJs
51 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
52 | { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },
53 |
54 | // Paths loaded via module imports:
55 | // Angular itself
56 | { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false },
57 | { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false },
58 |
59 | { pattern: appBase + '/systemjs.config.js', included: false, watched: false },
60 | { pattern: appBase + '/systemjs.config.extras.js', included: false, watched: false },
61 | 'karma-test-shim.js', // optionally extend SystemJS mapping e.g., with barrels
62 |
63 | // transpiled application & spec code paths loaded via module imports
64 | { pattern: appBase + '**/*.js', included: false, watched: true },
65 | { pattern: testingBase + '**/*.js', included: false, watched: true },
66 |
67 |
68 | // Asset (HTML & CSS) paths loaded via Angular's component compiler
69 | // (these paths need to be rewritten, see proxies section)
70 | { pattern: appBase + '**/*.html', included: false, watched: true },
71 | { pattern: appBase + '**/*.css', included: false, watched: true },
72 |
73 | // Paths for debugging with source maps in dev tools
74 | { pattern: appBase + '**/*.ts', included: false, watched: false },
75 | { pattern: appBase + '**/*.js.map', included: false, watched: false },
76 | { pattern: testingSrcBase + '**/*.ts', included: false, watched: false },
77 | { pattern: testingBase + '**/*.js.map', included: false, watched: false}
78 | ],
79 |
80 | // Proxied base paths for loading assets
81 | proxies: {
82 | // required for modules fetched by SystemJS
83 | '/base/src/node_modules/': '/base/node_modules/'
84 | },
85 |
86 | exclude: [],
87 | preprocessors: {},
88 | reporters: ['progress', 'kjhtml'],
89 |
90 | port: 9876,
91 | colors: true,
92 | logLevel: config.LOG_INFO,
93 | autoWatch: true,
94 | browsers: ['Chrome'],
95 | singleRun: false
96 | })
97 | }
98 |
--------------------------------------------------------------------------------
/week1/1/todoApp/non-essential-files.txt:
--------------------------------------------------------------------------------
1 | .git
2 | .gitignore
3 | .travis.yml
4 | *.spec*.ts
5 | CHANGELOG.md
6 | e2e
7 | favicon.ico
8 | karma.conf.js
9 | karma-test-shim.js
10 | LICENSE
11 | non-essential-files.txt
12 | protractor.config.js
13 | README.md
14 |
--------------------------------------------------------------------------------
/week1/1/todoApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-quickstart",
3 | "version": "1.0.0",
4 | "description": "QuickStart package.json from the documentation, supplemented with testing support",
5 | "scripts": {
6 | "build": "tsc -p src/",
7 | "build:watch": "tsc -p src/ -w",
8 | "build:e2e": "tsc -p e2e/",
9 | "serve": "lite-server -c=bs-config.json",
10 | "serve:e2e": "lite-server -c=bs-config.e2e.json",
11 | "prestart": "npm run build",
12 | "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
13 | "pree2e": "npm run build:e2e",
14 | "e2e": "concurrently \"npm run serve:e2e\" \"npm run protractor\" --kill-others --success first",
15 | "preprotractor": "webdriver-manager update",
16 | "protractor": "protractor protractor.config.js",
17 | "pretest": "npm run build",
18 | "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
19 | "pretest:once": "npm run build",
20 | "test:once": "karma start karma.conf.js --single-run",
21 | "lint": "tslint ./src/**/*.ts -t verbose"
22 | },
23 | "keywords": [],
24 | "author": "",
25 | "license": "MIT",
26 | "dependencies": {
27 | "@angular/common": "~2.4.0",
28 | "@angular/compiler": "~2.4.0",
29 | "@angular/core": "~2.4.0",
30 | "@angular/forms": "~2.4.0",
31 | "@angular/http": "~2.4.0",
32 | "@angular/platform-browser": "~2.4.0",
33 | "@angular/platform-browser-dynamic": "~2.4.0",
34 | "@angular/router": "~3.4.0",
35 |
36 | "angular-in-memory-web-api": "~0.2.4",
37 | "systemjs": "0.19.40",
38 | "core-js": "^2.4.1",
39 | "rxjs": "5.0.1",
40 | "zone.js": "^0.7.4"
41 | },
42 | "devDependencies": {
43 | "concurrently": "^3.1.0",
44 | "lite-server": "^2.2.2",
45 | "typescript": "~2.0.10",
46 |
47 | "canonical-path": "0.0.2",
48 | "tslint": "^3.15.1",
49 | "lodash": "^4.16.4",
50 | "jasmine-core": "~2.4.1",
51 | "karma": "^1.3.0",
52 | "karma-chrome-launcher": "^2.0.0",
53 | "karma-cli": "^1.0.1",
54 | "karma-jasmine": "^1.0.2",
55 | "karma-jasmine-html-reporter": "^0.2.2",
56 | "protractor": "~4.0.14",
57 | "rimraf": "^2.5.4",
58 |
59 | "@types/node": "^6.0.46",
60 | "@types/jasmine": "^2.5.36"
61 | },
62 | "repository": {}
63 | }
64 |
--------------------------------------------------------------------------------
/week1/1/todoApp/protractor.config.js:
--------------------------------------------------------------------------------
1 | // FIRST TIME ONLY- run:
2 | // ./node_modules/.bin/webdriver-manager update
3 | //
4 | // Try: `npm run webdriver:update`
5 | //
6 | // AND THEN EVERYTIME ...
7 | // 1. Compile with `tsc`
8 | // 2. Make sure the test server (e.g., lite-server: localhost:8080) is running.
9 | // 3. ./node_modules/.bin/protractor protractor.config.js
10 | //
11 | // To do all steps, try: `npm run e2e`
12 |
13 | var fs = require('fs');
14 | var path = require('canonical-path');
15 | var _ = require('lodash');
16 |
17 |
18 | exports.config = {
19 | directConnect: true,
20 |
21 | // Capabilities to be passed to the webdriver instance.
22 | capabilities: {
23 | 'browserName': 'chrome'
24 | },
25 |
26 | // Framework to use. Jasmine is recommended.
27 | framework: 'jasmine',
28 |
29 | // Spec patterns are relative to this config file
30 | specs: ['**/*e2e-spec.js' ],
31 |
32 |
33 | // For angular tests
34 | useAllAngular2AppRoots: true,
35 |
36 | // Base URL for application server
37 | baseUrl: 'http://localhost:8080',
38 |
39 | // doesn't seem to work.
40 | // resultJsonOutputFile: "foo.json",
41 |
42 | onPrepare: function() {
43 | //// SpecReporter
44 | //var SpecReporter = require('jasmine-spec-reporter');
45 | //jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'none'}));
46 | //// jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'}));
47 |
48 | // debugging
49 | // console.log('browser.params:' + JSON.stringify(browser.params));
50 | jasmine.getEnv().addReporter(new Reporter( browser.params )) ;
51 |
52 | // Allow changing bootstrap mode to NG1 for upgrade tests
53 | global.setProtractorToNg1Mode = function() {
54 | browser.useAllAngular2AppRoots = false;
55 | browser.rootEl = 'body';
56 | };
57 | },
58 |
59 | jasmineNodeOpts: {
60 | // defaultTimeoutInterval: 60000,
61 | defaultTimeoutInterval: 10000,
62 | showTiming: true,
63 | print: function() {}
64 | }
65 | };
66 |
67 | // Custom reporter
68 | function Reporter(options) {
69 | var _defaultOutputFile = path.resolve(process.cwd(), './_test-output', 'protractor-results.txt');
70 | options.outputFile = options.outputFile || _defaultOutputFile;
71 |
72 | initOutputFile(options.outputFile);
73 | options.appDir = options.appDir || './';
74 | var _root = { appDir: options.appDir, suites: [] };
75 | log('AppDir: ' + options.appDir, +1);
76 | var _currentSuite;
77 |
78 | this.suiteStarted = function(suite) {
79 | _currentSuite = { description: suite.description, status: null, specs: [] };
80 | _root.suites.push(_currentSuite);
81 | log('Suite: ' + suite.description, +1);
82 | };
83 |
84 | this.suiteDone = function(suite) {
85 | var statuses = _currentSuite.specs.map(function(spec) {
86 | return spec.status;
87 | });
88 | statuses = _.uniq(statuses);
89 | var status = statuses.indexOf('failed') >= 0 ? 'failed' : statuses.join(', ');
90 | _currentSuite.status = status;
91 | log('Suite ' + _currentSuite.status + ': ' + suite.description, -1);
92 | };
93 |
94 | this.specStarted = function(spec) {
95 |
96 | };
97 |
98 | this.specDone = function(spec) {
99 | var currentSpec = {
100 | description: spec.description,
101 | status: spec.status
102 | };
103 | if (spec.failedExpectations.length > 0) {
104 | currentSpec.failedExpectations = spec.failedExpectations;
105 | }
106 |
107 | _currentSuite.specs.push(currentSpec);
108 | log(spec.status + ' - ' + spec.description);
109 | };
110 |
111 | this.jasmineDone = function() {
112 | outputFile = options.outputFile;
113 | //// Alternate approach - just stringify the _root - not as pretty
114 | //// but might be more useful for automation.
115 | // var output = JSON.stringify(_root, null, 2);
116 | var output = formatOutput(_root);
117 | fs.appendFileSync(outputFile, output);
118 | };
119 |
120 | function ensureDirectoryExistence(filePath) {
121 | var dirname = path.dirname(filePath);
122 | if (directoryExists(dirname)) {
123 | return true;
124 | }
125 | ensureDirectoryExistence(dirname);
126 | fs.mkdirSync(dirname);
127 | }
128 |
129 | function directoryExists(path) {
130 | try {
131 | return fs.statSync(path).isDirectory();
132 | }
133 | catch (err) {
134 | return false;
135 | }
136 | }
137 |
138 | function initOutputFile(outputFile) {
139 | ensureDirectoryExistence(outputFile);
140 | var header = "Protractor results for: " + (new Date()).toLocaleString() + "\n\n";
141 | fs.writeFileSync(outputFile, header);
142 | }
143 |
144 | // for output file output
145 | function formatOutput(output) {
146 | var indent = ' ';
147 | var pad = ' ';
148 | var results = [];
149 | results.push('AppDir:' + output.appDir);
150 | output.suites.forEach(function(suite) {
151 | results.push(pad + 'Suite: ' + suite.description + ' -- ' + suite.status);
152 | pad+=indent;
153 | suite.specs.forEach(function(spec) {
154 | results.push(pad + spec.status + ' - ' + spec.description);
155 | if (spec.failedExpectations) {
156 | pad+=indent;
157 | spec.failedExpectations.forEach(function (fe) {
158 | results.push(pad + 'message: ' + fe.message);
159 | });
160 | pad=pad.substr(2);
161 | }
162 | });
163 | pad = pad.substr(2);
164 | results.push('');
165 | });
166 | results.push('');
167 | return results.join('\n');
168 | }
169 |
170 | // for console output
171 | var _pad;
172 | function log(str, indent) {
173 | _pad = _pad || '';
174 | if (indent == -1) {
175 | _pad = _pad.substr(2);
176 | }
177 | console.log(_pad + str);
178 | if (indent == 1) {
179 | _pad = _pad + ' ';
180 | }
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/add.component/add.component.css:
--------------------------------------------------------------------------------
1 | #add-todo {
2 | padding: 20px;
3 | }
4 |
5 | #add-todo * {
6 | display: inline-block;
7 | }
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/add.component/add.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Add
4 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/add.component/add.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Output, EventEmitter } from '@angular/core';
2 | import { Todo } from '../todo.model';
3 |
4 | @Component({
5 | selector: 'add-todo',
6 | templateUrl: './app/add.component/add.component.html',
7 | styleUrls: ['./app/add.component/add.component.css'],
8 | })
9 | export class AddComponent {
10 | @Output() newTodo: EventEmitter = new EventEmitter();
11 |
12 | add(text: string) {
13 | this.newTodo.emit(new Todo(text));
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { AppComponent } from './app.component';
2 |
3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
4 | import { By } from '@angular/platform-browser';
5 | import { DebugElement } from '@angular/core';
6 |
7 | describe('AppComponent', function () {
8 | let de: DebugElement;
9 | let comp: AppComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ AppComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(AppComponent);
21 | comp = fixture.componentInstance;
22 | de = fixture.debugElement.query(By.css('h1'));
23 | });
24 |
25 | it('should create component', () => expect(comp).toBeDefined() );
26 |
27 | it('should have expected text', () => {
28 | fixture.detectChanges();
29 | const h1 = de.nativeElement;
30 | expect(h1.innerText).toMatch(/angular/i,
31 | ' should say something about "Angular"');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Todo } from './todo.model';
3 | import { FilterState } from './enums/filter';
4 |
5 | const todoFiltersMap: {[key: number]: (todo?: Todo) => boolean } = {
6 | [FilterState.All]: (): boolean => true,
7 | [FilterState.Default]: (todo: Todo): boolean => !todo.isChecked,
8 | [FilterState.CompletedOnly]: (todo: Todo): boolean => !!todo.isChecked
9 | };
10 |
11 | @Component({
12 | selector: 'my-app',
13 | template: `
14 | {{title}}
15 |
16 |
17 |
18 | `,
19 | })
20 | export class AppComponent {
21 | title = 'TODO APP';
22 | todos: Todo[] = [];
23 | filterState: FilterState = FilterState.Default;
24 |
25 | newTodoHandler(todo: Todo) {
26 | this.todos.push(todo);
27 | }
28 |
29 | stateChangeHandler(state: FilterState) {
30 | this.filterState = state;
31 | }
32 |
33 | private get todoList(): Todo[] {
34 | return this.todos.filter(todoFiltersMap[this.filterState]);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 |
4 | import { AppComponent } from './app.component';
5 |
6 | import { ListComponent } from './list.component/list.component';
7 | import { AddComponent } from './add.component/add.component';
8 | import { FilterComponent } from './filter.component/filter.component';
9 |
10 | @NgModule({
11 | imports: [ BrowserModule ],
12 | declarations: [ AppComponent, ListComponent, AddComponent, FilterComponent ],
13 | bootstrap: [ AppComponent ]
14 | })
15 | export class AppModule { }
16 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/enums/filter.ts:
--------------------------------------------------------------------------------
1 | export enum FilterState {
2 | Default,
3 | CompletedOnly,
4 | All
5 | };
6 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/filter.component/filter.component.css:
--------------------------------------------------------------------------------
1 | #filter {
2 | width: 100%;
3 | }
4 |
5 | #filter li {
6 | display: inline-block;
7 | margin: 5px;
8 | padding: 20px;
9 | }
10 |
11 | #filter li.active {
12 | background-color: rgba(0, 128, 0, 0.57);
13 | color: white;
14 | }
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/filter.component/filter.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/filter.component/filter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Output, EventEmitter } from '@angular/core';
2 | import { FilterState } from '../enums/filter';
3 |
4 | @Component({
5 | selector: 'filter',
6 | templateUrl: './app/filter.component/filter.component.html',
7 | styleUrls: ['./app/filter.component/filter.component.css']
8 | })
9 | export class FilterComponent {
10 | @Input() state: FilterState;
11 | @Output() stateChange: EventEmitter = new EventEmitter();
12 |
13 | private states: string[] = [];
14 |
15 | constructor() {
16 | this.states = Object.keys(FilterState).filter(el => isNaN(parseInt(el, 10)));
17 | }
18 |
19 | stateChanged(stateName: string) {
20 | this.stateChange.emit(FilterState[stateName]);
21 | }
22 |
23 | private isActive(stateName: string): boolean {
24 | return FilterState[stateName] === this.state;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/list.component/list.component.css:
--------------------------------------------------------------------------------
1 | li.todo {
2 | color: orange;
3 | }
4 |
5 | li.todo.completed {
6 | color: green;
7 | }
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/list.component/list.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{item.getText()}}
3 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/list.component/list.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 | import { Todo } from '../todo.model';
3 | @Component({
4 | selector: 'todo-list',
5 | templateUrl: './app/list.component/list.component.html',
6 | styleUrls: ['./app/list.component/list.component.css']
7 | })
8 | export class ListComponent {
9 | @Input() list: Todo[] = [];
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/app/todo.model.ts:
--------------------------------------------------------------------------------
1 | export class Todo {
2 |
3 | get isChecked() {
4 | return this.checked;
5 | }
6 |
7 | private checked: boolean = false;
8 |
9 | constructor(private text: string) {}
10 |
11 | getText(): string {
12 | return this.text;
13 | }
14 |
15 | toggleChacked() {
16 | this.checked = !this.checked;
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week1/1/todoApp/src/favicon.ico
--------------------------------------------------------------------------------
/week1/1/todoApp/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Angular QuickStart
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 | Loading AppComponent content here ...
24 |
25 |
26 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 | platformBrowserDynamic().bootstrapModule(AppModule);
6 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/styles.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | color: #369;
3 | font-family: Arial, Helvetica, sans-serif;
4 | font-size: 250%;
5 | }
6 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/systemjs.config.extras.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Add barrels and stuff
3 | * Adjust as necessary for your application needs.
4 | */
5 | // (function (global) {
6 | // System.config({
7 | // packages: {
8 | // // add packages here
9 | // }
10 | // });
11 | // })(this);
12 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/systemjs.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * System configuration for Angular samples
3 | * Adjust as necessary for your application needs.
4 | */
5 | (function (global) {
6 | System.config({
7 | paths: {
8 | // paths serve as alias
9 | 'npm:': 'node_modules/'
10 | },
11 | // map tells the System loader where to look for things
12 | map: {
13 | // our app is within the app folder
14 | app: 'app',
15 |
16 | // angular bundles
17 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
18 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
19 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
20 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
21 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
22 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
23 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
24 | // '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
25 |
26 | // other libraries
27 | 'rxjs': 'npm:rxjs',
28 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
29 | },
30 | // packages tells the System loader how to load when no filename and/or no extension
31 | packages: {
32 | app: {
33 | defaultExtension: 'js'
34 | },
35 | rxjs: {
36 | defaultExtension: 'js'
37 | }
38 | }
39 | });
40 | })(this);
41 |
--------------------------------------------------------------------------------
/week1/1/todoApp/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "lib": [ "es2015", "dom" ],
10 | "noImplicitAny": true,
11 | "suppressImplicitAnyIndexErrors": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/week1/1/todoApp/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "comment-format": [
5 | true,
6 | "check-space"
7 | ],
8 | "curly": true,
9 | "eofline": true,
10 | "forin": true,
11 | "indent": [
12 | true,
13 | "spaces"
14 | ],
15 | "label-position": true,
16 | "label-undefined": true,
17 | "max-line-length": [
18 | true,
19 | 140
20 | ],
21 | "member-access": false,
22 | "member-ordering": [
23 | true,
24 | "static-before-instance",
25 | "variables-before-functions"
26 | ],
27 | "no-arg": true,
28 | "no-bitwise": true,
29 | "no-console": [
30 | true,
31 | "debug",
32 | "info",
33 | "time",
34 | "timeEnd",
35 | "trace"
36 | ],
37 | "no-construct": true,
38 | "no-debugger": true,
39 | "no-duplicate-key": true,
40 | "no-duplicate-variable": true,
41 | "no-empty": false,
42 | "no-eval": true,
43 | "no-inferrable-types": true,
44 | "no-shadowed-variable": true,
45 | "no-string-literal": false,
46 | "no-switch-case-fall-through": true,
47 | "no-trailing-whitespace": true,
48 | "no-unused-expression": true,
49 | "no-unused-variable": true,
50 | "no-unreachable": true,
51 | "no-use-before-declare": true,
52 | "no-var-keyword": true,
53 | "object-literal-sort-keys": false,
54 | "one-line": [
55 | true,
56 | "check-open-brace",
57 | "check-catch",
58 | "check-else",
59 | "check-whitespace"
60 | ],
61 | "quotemark": [
62 | true,
63 | "single"
64 | ],
65 | "radix": true,
66 | "semicolon": [
67 | "always"
68 | ],
69 | "triple-equals": [
70 | true,
71 | "allow-null-check"
72 | ],
73 | "typedef-whitespace": [
74 | true,
75 | {
76 | "call-signature": "nospace",
77 | "index-signature": "nospace",
78 | "parameter": "nospace",
79 | "property-declaration": "nospace",
80 | "variable-declaration": "nospace"
81 | }
82 | ],
83 | "variable-name": false,
84 | "whitespace": [
85 | true,
86 | "check-branch",
87 | "check-decl",
88 | "check-operator",
89 | "check-separator",
90 | "check-type"
91 | ]
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/week1/2/README.md:
--------------------------------------------------------------------------------
1 | # Week 1.2
2 |
3 | # Lecture:
4 | Click [here](https://speakerdeck.com/iliaidakiev/2-functional-programming-and-rxjs)
5 |
6 | # Tasks
7 |
8 | ## Using RxJS solve the tasks bellow (use pure functions and separate functionality):
9 | Use this [link](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/categories.md) if you need help.
10 | ---
11 |
12 | ### Part 1.
13 | 1.1.Sum up all the elements from the array bellow:
14 | ```
15 | const numbers = [10,64,12,32];
16 | ```
17 |
18 | 1.2.Extract the odd numbers from the array bellow:
19 | ```
20 | const numbers = [3,7,5,2,8,1];
21 | ```
22 |
23 | 1.3.From the given array extract all the names and ages to separate arrays:
24 | ```
25 | const users = [{
26 | name: 'Ivan',
27 | age: 18
28 | }, {
29 | name: 'Petar',
30 | age: 25
31 | }, {
32 | name: 'Alex',
33 | age: 10
34 | }]
35 | ```
36 |
37 | 1.4.Create a component clock that gets the current time from the browser on initialization and creates an Observable. Subscribe to the observable and set the value to a local property. Every minute this proeperty needs to be changed to represent the real time on our page.
38 |
39 | ---
40 |
41 | ### Part 2.
42 | 2.1.We have a dummy method post in our main component that looks like:
43 | ```
44 | get(url, callback) {
45 | console.log(`fake get request to ${url}`);
46 | const id = setTimeout(() => {
47 | console.log(`get request JSON response`)
48 | callback(null, `[{
49 | "name": "Ivan",
50 | "age": 18
51 | }, {
52 | "name": "Petar",
53 | "age": 25
54 | }, {
55 | "name": "Alex",
56 | "age": 10
57 | }]`)
58 | }, 2000);
59 | return {
60 | cancel: () => clearInterval(id)
61 | }
62 | }
63 |
64 | ```
65 | Using Observables wrap up this get method so we can use it like:
66 |
67 | ```
68 | this.get('url').map(...).map(...).subscribe(...)
69 | ```
70 |
71 | The flow should be like: get -> JSON.parse -> modify and use 1.4 to extract names and ages
72 |
73 | 2.2.We have an array of urls. Using the map operator and the modified get from the previous task, simulate getting the data from each urls.
74 | ```
75 | const urls = ['http://domain.com', 'http://domain.bg', 'http://domain.eu']
76 | ```
77 |
78 | ---
79 |
80 | ### Part 3.
81 | 3.1.Use the modified dummy get method bellow and make sure you handle the error and present the error message to the user:
82 |
83 | ```
84 | errorGet(url: string, callback: any) {
85 | console.log(`fake get request to ${url}`);
86 | if(/(.*)\.(bg)/.test(url)) callback(new Error('Cannot resolve domain .bg'));
87 | const id = setTimeout(() => {
88 | console.log(`get request JSON response`)
89 | callback(null, `[{
90 | "name": "Ivan",
91 | "age": 18
92 | }, {
93 | "name": "Petar",
94 | "age": 25
95 | }, {
96 | "name": "Alex",
97 | "age": 10
98 | }]`)
99 | }, 2000);
100 | return {
101 | cancel: () => clearInterval(id)
102 | };
103 | }
104 | ```
105 |
106 | 3.2.Make sure that all the urls from the array are fetched. If there is a failed request just set the data as ``null`` (Chain isolation). Show the results to the user like so:
107 | ```
108 | http://domain.com
109 | Ivan - 18
110 | Petar - 25
111 | Alex - 10
112 |
113 | http://domain.eu
114 | Ivan - 18
115 | Petar - 25
116 | Alex - 10
117 | ```
118 | ### Part 4.
119 | 4.1 In this task we will simulate a socket connection. We have a method ``connect`` that takes a url and creates a (fake) connection to the given url. The returned value of calling this method is an (Hot) Observable. When we subscribe to the method we should get the same stream and not open a new conncetion. Use `interval(1500)` to simulate data coming from the server.
120 |
121 | ### Part 5.
122 | Use a ReplySubject for this task to create data caching for the socket connection from the previous task. By doing this every subscriber will receive all the data emited from the source when subscribed. Review links: [link1](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md), [link2](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/replaysubject.md).
--------------------------------------------------------------------------------
/week1/2/solutionsApp/.editorconfig:
--------------------------------------------------------------------------------
1 | # 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 |
12 | [*.md]
13 | max_line_length = 0
14 | trim_trailing_whitespace = false
15 |
16 | # Indentation override
17 | #[lib/**.js]
18 | #[{package.json,.travis.yml}]
19 | #[**/**.js]
20 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | jspm_packages
4 | npm-debug.log
5 | debug.log
6 | src/**/*.js
7 | !src/systemjs.config.extras.js
8 | !src/systemjs.config.js
9 | *.js.map
10 | e2e/**/*.js
11 | e2e/**/*.js.map
12 | _test-output
13 | _temp
14 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: required
3 | language: node_js
4 | node_js:
5 | - "5"
6 | os:
7 | - linux
8 | env:
9 | global:
10 | - DBUS_SESSION_BUS_ADDRESS=/dev/null
11 | - DISPLAY=:99.0
12 | - CHROME_BIN=chromium-browser
13 | before_script:
14 | - sh -e /etc/init.d/xvfb start
15 | install:
16 | - npm install
17 | script:
18 | - npm run lint
19 | - npm run test:once
20 | - npm run e2e
21 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible Node.js debug attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Launch Program",
11 | "program": "${workspaceRoot}/serve\"",
12 | "cwd": "${workspaceRoot}",
13 | "outFiles": []
14 | },
15 | {
16 | "type": "node",
17 | "request": "attach",
18 | "name": "Attach to Process",
19 | "port": 5858,
20 | "outFiles": []
21 | }
22 | ]
23 | }
--------------------------------------------------------------------------------
/week1/2/solutionsApp/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "0.1.0",
5 | "command": "echo",
6 | "isShellCommand": true,
7 | "args": ["Hello World"],
8 | "showOutput": "never"
9 | }
--------------------------------------------------------------------------------
/week1/2/solutionsApp/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Angular Documentation QuickStart Changelog
2 | Upgraders: for a fresh start, consider running these commands
3 | * `git clean -xdf`
4 | * `npm install`
5 |
6 |
7 | # 0.2.22 (2017-01-05)
8 | * Add `non-essential-files.txt` and instructions to use it to README
9 |
10 |
11 | # 0.2.21 (2016-12-14)
12 | * Update to in-memory-web-api v.0.2.1
13 |
14 |
15 | # 0.2.20 (2016-12-07)
16 | * Update to Angular 2.3.0
17 |
18 |
19 | # 0.2.19 (2016-11-30)
20 | * remove upgrade mappings from `systemjs.config.js` PR #301
21 |
22 |
23 | # 0.2.18 (2016-11-30)
24 | * remove `exclude` clause from `tsconfig.json`; it was just confusing people
25 | * karma.config + karma-test-shim can handle multiple spec source paths (issue #294)
26 | * cosmetic `app.component.spec.ts` changes
27 | * cosmetic `karma.config.js` changes
28 |
29 |
30 | # 0.2.17 (2016-11-16)
31 | * Conform to updated QuickStart advice
32 | * removed docker everywhere (was nice but not necessary)
33 | * removed wallaby
34 | * shrink styles.css
35 | * refine tsconfig.json
36 | * `AppComponent` uses interpolation
37 |
38 |
39 | # 0.2.16 (2016-11-14)
40 | * Update to Angular 2.2.0
41 |
42 |
43 | # 0.2.15 (2016-10-29)
44 | * Revert to Jasmine 2.4.1 because bug in 2.5.x (see [jasmine issue #1231](https://github.com/jasmine/jasmine/issues/1231))
45 |
46 |
47 | # 0.2.14 (2016-10-29)
48 | * Remove bootstrap.css install
49 | * Angular v2.1.2
50 |
51 |
52 | # 0.2.13 (2016-10-20)
53 | * Protractor 4
54 | * Move from `typings` to `@types`. See `tsconfig.json` changes.
55 | * Angular v2.1.1
56 |
57 |
58 | # 0.2.12 (2016-10-06)
59 | * Angular v2.1.0
60 |
61 |
62 | # 0.2.11 (2016-10-06)
63 | * Angular v2.0.2
64 | * License is MIT
65 | * Current testing configuration
66 | * No code changes
67 |
68 |
69 | # 0.2.10 (2016-09-19)
70 | * All "Angular 2" references become just "Angular"
71 | * No code changes
72 |
73 |
74 | # 0.2.9 (2016-09-14)
75 | * Angular 2.0.0 version
76 | * Update to Typescript 2.0.2
77 | * Fix e2e test missing dir
78 |
79 |
80 | # 0.2.8 (2016-09-01)
81 | * remove @angular test libraries from system.js (now in shim)
82 | * update test related files
83 | * wallaby doesn't completely work. Researching.
84 |
85 |
86 | # 0.2.7 (2016-08-31)
87 | * Angular 2 RC6 version
88 | * Updated new forms, router, angular2-in-memory-web-api, karma, core-js, rxjs and zone.js packages
89 | * Removed router-deprecated package
90 | * Updated karma.conf.js and systemjs.config.js
91 |
92 |
93 | # 0.2.6 (2016-08-09)
94 | * Angular 2 RC5 version
95 | * Updated new forms, router and angular2-in-memory-web-api
96 |
97 |
98 | # 0.2.5 (2016-06-30)
99 | * Angular 2 RC4 version
100 | * Updated new forms and router
101 |
102 |
103 | # 0.2.4 (2016-06-21)
104 | * Angular 2 RC3 version
105 | * Add new forms and router
106 | * Add support for TS e2e tests
107 |
108 |
109 | # 0.2.3 (2016-06-15)
110 | * Angular 2 RC2 version
111 |
112 |
113 | # 0.2.2 (2016-05-21)
114 | * Update to Typings 1.x
115 |
116 |
117 | # 0.2.1 (2016-05-03)
118 | * Angular 2 RC01 version
119 |
120 |
121 | # 0.2.0 (2016-05-02)
122 | * Angular 2 RC0 version
123 |
124 |
125 | # 0.1.17 (2016-04-29)
126 | * update packages
127 | * Angular 2 beta 17
128 | * RxJS 5.0.0-beta.6
129 | * a2-in-memory-web-api 0.1.17
130 |
131 |
132 | # 0.1.16 (2016-04-26)
133 | * update packages
134 | * Angular 2 beta 16
135 | * a2-in-memory-web-api 0.1.6
136 | * protractor 3.3.0
137 | * typings 0.8.1
138 | * zone.js 0.6.12
139 |
140 | * added favicon.ico
141 |
142 | * testing
143 | - updated wallaby.js and karma.conf.js
144 | - updated app.component.spec.ts
145 |
146 |
147 |
148 | # 0.1.15 (2016-04-13)
149 | * Add testing support
150 | * npm scripts
151 | * karma/jasmine
152 | * protractor
153 |
154 | * update packages
155 | * Angular 2 beta 15
156 | * lite-server 2.2.0
157 | * systemjs 0.19.26
158 | * typescript 1.8.10
159 | * typings 0.7.12
160 |
161 | * add run packages
162 | * a2-in-memory-web-api
163 |
164 | * add testing dev-dependency packages
165 | * canonical-path: 0.0.2,
166 | * http-server: ^0.9.0,
167 | * jasmine-core: ~2.4.1,
168 | * karma: ^0.13.22,
169 | * karma-chrome-launcher: ^0.2.3,
170 | * karma-cli: ^0.1.2,
171 | * karma-htmlfile-reporter: ^0.2.2,
172 | * karma-jasmine: ^0.3.8,
173 | * protractor: ^3.2.2,
174 | * rimraf: ^2.5.2
175 |
176 |
177 | # 0.1.14 (2016-04-07)
178 | * update packages
179 | * Angular 2 beta 14
180 | * lite-server 2.2.0
181 | * typings 0.7.12
182 |
183 |
184 | # 0.1.13 (2016-03-31)
185 | * update packages
186 | * Angular 2 beta 13
187 |
188 |
189 | # 0.1.12 (2016-03-23)
190 | * update packages
191 | * Angular 2 beta 12
192 | * zones 0.6.6
193 | * remove es6-promise because no longer needed.
194 |
195 |
196 | # 0.1.11 (2016-03-18)
197 | * update packages
198 | * Angular 2 beta 11
199 | * zones 0.6.4
200 | * typescript 1.8.9
201 | * typings 0.7.9
202 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2014-2016 Google, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/README.md:
--------------------------------------------------------------------------------
1 | # RxJS practice
2 |
3 | ## rxjs.practice contains tasks:
4 | * 1.1
5 | * 1.2
6 | * 1.3
7 |
8 | ## clock.component is task 1.4
9 |
10 | ## app.component.ts contains taks:
11 | * 2.1
12 | * 2.2
13 | * 3.1
14 | * 3.2
15 | * 4.1
16 | * 5.1
17 |
18 | ---
19 | * `npm start` - runs the compiler and a server at the same time, both in "watch mode".
20 | * `npm run build` - runs the TypeScript compiler once.
21 | * `npm run build:w` - runs the TypeScript compiler in watch mode; the process keeps running, awaiting changes to TypeScript files and re-compiling when it sees them.
22 | * `npm run serve` - runs the [lite-server](https://www.npmjs.com/package/lite-server), a light-weight, static file server, written and maintained by
--------------------------------------------------------------------------------
/week1/2/solutionsApp/bs-config.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "open": false,
3 | "logLevel": "silent",
4 | "port": 8080,
5 | "server": {
6 | "baseDir": "src",
7 | "routes": {
8 | "/node_modules": "node_modules"
9 | },
10 | "middleware": {
11 | "0": null
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "baseDir": "src",
4 | "routes": {
5 | "/node_modules": "node_modules"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | describe('QuickStart E2E Tests', function () {
4 |
5 | let expectedMsg = 'Hello Angular';
6 |
7 | beforeEach(function () {
8 | browser.get('');
9 | });
10 |
11 | it('should display: ' + expectedMsg, function () {
12 | expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
13 | });
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "lib": [ "es2015", "dom" ],
10 | "noImplicitAny": true,
11 | "suppressImplicitAnyIndexErrors": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/karma-test-shim.js:
--------------------------------------------------------------------------------
1 | // /*global jasmine, __karma__, window*/
2 | Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.
3 |
4 | // Uncomment to get full stacktrace output. Sometimes helpful, usually not.
5 | // Error.stackTraceLimit = Infinity; //
6 |
7 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
8 |
9 | // builtPaths: root paths for output ("built") files
10 | // get from karma.config.js, then prefix with '/base/' (default is 'src/')
11 | var builtPaths = (__karma__.config.builtPaths || ['src/'])
12 | .map(function(p) { return '/base/'+p;});
13 |
14 | __karma__.loaded = function () { };
15 |
16 | function isJsFile(path) {
17 | return path.slice(-3) == '.js';
18 | }
19 |
20 | function isSpecFile(path) {
21 | return /\.spec\.(.*\.)?js$/.test(path);
22 | }
23 |
24 | // Is a "built" file if is JavaScript file in one of the "built" folders
25 | function isBuiltFile(path) {
26 | return isJsFile(path) &&
27 | builtPaths.reduce(function(keep, bp) {
28 | return keep || (path.substr(0, bp.length) === bp);
29 | }, false);
30 | }
31 |
32 | var allSpecFiles = Object.keys(window.__karma__.files)
33 | .filter(isSpecFile)
34 | .filter(isBuiltFile);
35 |
36 | System.config({
37 | // Base URL for System.js calls. 'base/' is where Karma serves files from.
38 | baseURL: 'base/src',
39 | // Extend usual application package list with test folder
40 | packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } },
41 |
42 | // Assume npm: is set in `paths` in systemjs.config
43 | // Map the angular testing umd bundles
44 | map: {
45 | '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
46 | '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
47 | '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
48 | '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
49 | '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
50 | '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
51 | '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
52 | '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
53 | },
54 | });
55 |
56 | System.import('systemjs.config.js')
57 | .then(importSystemJsExtras)
58 | .then(initTestBed)
59 | .then(initTesting);
60 |
61 | /** Optional SystemJS configuration extras. Keep going w/o it */
62 | function importSystemJsExtras(){
63 | return System.import('systemjs.config.extras.js')
64 | .catch(function(reason) {
65 | console.log(
66 | 'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.'
67 | );
68 | console.log(reason);
69 | });
70 | }
71 |
72 | function initTestBed(){
73 | return Promise.all([
74 | System.import('@angular/core/testing'),
75 | System.import('@angular/platform-browser-dynamic/testing')
76 | ])
77 |
78 | .then(function (providers) {
79 | var coreTesting = providers[0];
80 | var browserTesting = providers[1];
81 |
82 | coreTesting.TestBed.initTestEnvironment(
83 | browserTesting.BrowserDynamicTestingModule,
84 | browserTesting.platformBrowserDynamicTesting());
85 | })
86 | }
87 |
88 | // Import all spec files and start karma
89 | function initTesting () {
90 | return Promise.all(
91 | allSpecFiles.map(function (moduleName) {
92 | return System.import(moduleName);
93 | })
94 | )
95 | .then(__karma__.start, __karma__.error);
96 | }
97 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 |
3 | var appBase = 'src/'; // transpiled app JS and map files
4 | var appSrcBase = appBase; // app source TS files
5 |
6 | // Testing helpers (optional) are conventionally in a folder called `testing`
7 | var testingBase = 'testing/'; // transpiled test JS and map files
8 | var testingSrcBase = 'testing/'; // test source TS files
9 |
10 | config.set({
11 | basePath: '',
12 | frameworks: ['jasmine'],
13 |
14 | plugins: [
15 | require('karma-jasmine'),
16 | require('karma-chrome-launcher'),
17 | require('karma-jasmine-html-reporter')
18 | ],
19 |
20 | client: {
21 | builtPaths: [appBase, testingBase], // add more spec base paths as needed
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 |
25 | customLaunchers: {
26 | // From the CLI. Not used here but interesting
27 | // chrome setup for travis CI using chromium
28 | Chrome_travis_ci: {
29 | base: 'Chrome',
30 | flags: ['--no-sandbox']
31 | }
32 | },
33 |
34 | files: [
35 | // System.js for module loading
36 | 'node_modules/systemjs/dist/system.src.js',
37 |
38 | // Polyfills
39 | 'node_modules/core-js/client/shim.js',
40 |
41 | // zone.js
42 | 'node_modules/zone.js/dist/zone.js',
43 | 'node_modules/zone.js/dist/long-stack-trace-zone.js',
44 | 'node_modules/zone.js/dist/proxy.js',
45 | 'node_modules/zone.js/dist/sync-test.js',
46 | 'node_modules/zone.js/dist/jasmine-patch.js',
47 | 'node_modules/zone.js/dist/async-test.js',
48 | 'node_modules/zone.js/dist/fake-async-test.js',
49 |
50 | // RxJs
51 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
52 | { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },
53 |
54 | // Paths loaded via module imports:
55 | // Angular itself
56 | { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false },
57 | { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false },
58 |
59 | { pattern: appBase + '/systemjs.config.js', included: false, watched: false },
60 | { pattern: appBase + '/systemjs.config.extras.js', included: false, watched: false },
61 | 'karma-test-shim.js', // optionally extend SystemJS mapping e.g., with barrels
62 |
63 | // transpiled application & spec code paths loaded via module imports
64 | { pattern: appBase + '**/*.js', included: false, watched: true },
65 | { pattern: testingBase + '**/*.js', included: false, watched: true },
66 |
67 |
68 | // Asset (HTML & CSS) paths loaded via Angular's component compiler
69 | // (these paths need to be rewritten, see proxies section)
70 | { pattern: appBase + '**/*.html', included: false, watched: true },
71 | { pattern: appBase + '**/*.css', included: false, watched: true },
72 |
73 | // Paths for debugging with source maps in dev tools
74 | { pattern: appBase + '**/*.ts', included: false, watched: false },
75 | { pattern: appBase + '**/*.js.map', included: false, watched: false },
76 | { pattern: testingSrcBase + '**/*.ts', included: false, watched: false },
77 | { pattern: testingBase + '**/*.js.map', included: false, watched: false}
78 | ],
79 |
80 | // Proxied base paths for loading assets
81 | proxies: {
82 | // required for modules fetched by SystemJS
83 | '/base/src/node_modules/': '/base/node_modules/'
84 | },
85 |
86 | exclude: [],
87 | preprocessors: {},
88 | reporters: ['progress', 'kjhtml'],
89 |
90 | port: 9876,
91 | colors: true,
92 | logLevel: config.LOG_INFO,
93 | autoWatch: true,
94 | browsers: ['Chrome'],
95 | singleRun: false
96 | })
97 | }
98 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/non-essential-files.txt:
--------------------------------------------------------------------------------
1 | .git
2 | .gitignore
3 | .travis.yml
4 | *.spec*.ts
5 | CHANGELOG.md
6 | e2e
7 | favicon.ico
8 | karma.conf.js
9 | karma-test-shim.js
10 | LICENSE
11 | non-essential-files.txt
12 | protractor.config.js
13 | README.md
14 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-quickstart",
3 | "version": "1.0.0",
4 | "description": "QuickStart package.json from the documentation, supplemented with testing support",
5 | "scripts": {
6 | "build": "tsc -p src/",
7 | "build:watch": "tsc -p src/ -w",
8 | "build:e2e": "tsc -p e2e/",
9 | "serve": "lite-server -c=bs-config.json",
10 | "serve:e2e": "lite-server -c=bs-config.e2e.json",
11 | "prestart": "npm run build",
12 | "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
13 | "pree2e": "npm run build:e2e",
14 | "e2e": "concurrently \"npm run serve:e2e\" \"npm run protractor\" --kill-others --success first",
15 | "preprotractor": "webdriver-manager update",
16 | "protractor": "protractor protractor.config.js",
17 | "pretest": "npm run build",
18 | "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
19 | "pretest:once": "npm run build",
20 | "test:once": "karma start karma.conf.js --single-run",
21 | "lint": "tslint ./src/**/*.ts -t verbose"
22 | },
23 | "keywords": [],
24 | "author": "",
25 | "license": "MIT",
26 | "dependencies": {
27 | "@angular/common": "~2.4.0",
28 | "@angular/compiler": "~2.4.0",
29 | "@angular/core": "~2.4.0",
30 | "@angular/forms": "~2.4.0",
31 | "@angular/http": "~2.4.0",
32 | "@angular/platform-browser": "~2.4.0",
33 | "@angular/platform-browser-dynamic": "~2.4.0",
34 | "@angular/router": "~3.4.0",
35 |
36 | "angular-in-memory-web-api": "~0.2.4",
37 | "systemjs": "0.19.40",
38 | "core-js": "^2.4.1",
39 | "rxjs": "5.0.1",
40 | "zone.js": "^0.7.4"
41 | },
42 | "devDependencies": {
43 | "concurrently": "^3.1.0",
44 | "lite-server": "^2.2.2",
45 | "typescript": "~2.0.10",
46 |
47 | "canonical-path": "0.0.2",
48 | "tslint": "^3.15.1",
49 | "lodash": "^4.16.4",
50 | "jasmine-core": "~2.4.1",
51 | "karma": "^1.3.0",
52 | "karma-chrome-launcher": "^2.0.0",
53 | "karma-cli": "^1.0.1",
54 | "karma-jasmine": "^1.0.2",
55 | "karma-jasmine-html-reporter": "^0.2.2",
56 | "protractor": "~4.0.14",
57 | "rimraf": "^2.5.4",
58 |
59 | "@types/node": "^6.0.46",
60 | "@types/jasmine": "^2.5.36"
61 | },
62 | "repository": {}
63 | }
64 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/protractor.config.js:
--------------------------------------------------------------------------------
1 | // FIRST TIME ONLY- run:
2 | // ./node_modules/.bin/webdriver-manager update
3 | //
4 | // Try: `npm run webdriver:update`
5 | //
6 | // AND THEN EVERYTIME ...
7 | // 1. Compile with `tsc`
8 | // 2. Make sure the test server (e.g., lite-server: localhost:8080) is running.
9 | // 3. ./node_modules/.bin/protractor protractor.config.js
10 | //
11 | // To do all steps, try: `npm run e2e`
12 |
13 | var fs = require('fs');
14 | var path = require('canonical-path');
15 | var _ = require('lodash');
16 |
17 |
18 | exports.config = {
19 | directConnect: true,
20 |
21 | // Capabilities to be passed to the webdriver instance.
22 | capabilities: {
23 | 'browserName': 'chrome'
24 | },
25 |
26 | // Framework to use. Jasmine is recommended.
27 | framework: 'jasmine',
28 |
29 | // Spec patterns are relative to this config file
30 | specs: ['**/*e2e-spec.js' ],
31 |
32 |
33 | // For angular tests
34 | useAllAngular2AppRoots: true,
35 |
36 | // Base URL for application server
37 | baseUrl: 'http://localhost:8080',
38 |
39 | // doesn't seem to work.
40 | // resultJsonOutputFile: "foo.json",
41 |
42 | onPrepare: function() {
43 | //// SpecReporter
44 | //var SpecReporter = require('jasmine-spec-reporter');
45 | //jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'none'}));
46 | //// jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'}));
47 |
48 | // debugging
49 | // console.log('browser.params:' + JSON.stringify(browser.params));
50 | jasmine.getEnv().addReporter(new Reporter( browser.params )) ;
51 |
52 | // Allow changing bootstrap mode to NG1 for upgrade tests
53 | global.setProtractorToNg1Mode = function() {
54 | browser.useAllAngular2AppRoots = false;
55 | browser.rootEl = 'body';
56 | };
57 | },
58 |
59 | jasmineNodeOpts: {
60 | // defaultTimeoutInterval: 60000,
61 | defaultTimeoutInterval: 10000,
62 | showTiming: true,
63 | print: function() {}
64 | }
65 | };
66 |
67 | // Custom reporter
68 | function Reporter(options) {
69 | var _defaultOutputFile = path.resolve(process.cwd(), './_test-output', 'protractor-results.txt');
70 | options.outputFile = options.outputFile || _defaultOutputFile;
71 |
72 | initOutputFile(options.outputFile);
73 | options.appDir = options.appDir || './';
74 | var _root = { appDir: options.appDir, suites: [] };
75 | log('AppDir: ' + options.appDir, +1);
76 | var _currentSuite;
77 |
78 | this.suiteStarted = function(suite) {
79 | _currentSuite = { description: suite.description, status: null, specs: [] };
80 | _root.suites.push(_currentSuite);
81 | log('Suite: ' + suite.description, +1);
82 | };
83 |
84 | this.suiteDone = function(suite) {
85 | var statuses = _currentSuite.specs.map(function(spec) {
86 | return spec.status;
87 | });
88 | statuses = _.uniq(statuses);
89 | var status = statuses.indexOf('failed') >= 0 ? 'failed' : statuses.join(', ');
90 | _currentSuite.status = status;
91 | log('Suite ' + _currentSuite.status + ': ' + suite.description, -1);
92 | };
93 |
94 | this.specStarted = function(spec) {
95 |
96 | };
97 |
98 | this.specDone = function(spec) {
99 | var currentSpec = {
100 | description: spec.description,
101 | status: spec.status
102 | };
103 | if (spec.failedExpectations.length > 0) {
104 | currentSpec.failedExpectations = spec.failedExpectations;
105 | }
106 |
107 | _currentSuite.specs.push(currentSpec);
108 | log(spec.status + ' - ' + spec.description);
109 | };
110 |
111 | this.jasmineDone = function() {
112 | outputFile = options.outputFile;
113 | //// Alternate approach - just stringify the _root - not as pretty
114 | //// but might be more useful for automation.
115 | // var output = JSON.stringify(_root, null, 2);
116 | var output = formatOutput(_root);
117 | fs.appendFileSync(outputFile, output);
118 | };
119 |
120 | function ensureDirectoryExistence(filePath) {
121 | var dirname = path.dirname(filePath);
122 | if (directoryExists(dirname)) {
123 | return true;
124 | }
125 | ensureDirectoryExistence(dirname);
126 | fs.mkdirSync(dirname);
127 | }
128 |
129 | function directoryExists(path) {
130 | try {
131 | return fs.statSync(path).isDirectory();
132 | }
133 | catch (err) {
134 | return false;
135 | }
136 | }
137 |
138 | function initOutputFile(outputFile) {
139 | ensureDirectoryExistence(outputFile);
140 | var header = "Protractor results for: " + (new Date()).toLocaleString() + "\n\n";
141 | fs.writeFileSync(outputFile, header);
142 | }
143 |
144 | // for output file output
145 | function formatOutput(output) {
146 | var indent = ' ';
147 | var pad = ' ';
148 | var results = [];
149 | results.push('AppDir:' + output.appDir);
150 | output.suites.forEach(function(suite) {
151 | results.push(pad + 'Suite: ' + suite.description + ' -- ' + suite.status);
152 | pad+=indent;
153 | suite.specs.forEach(function(spec) {
154 | results.push(pad + spec.status + ' - ' + spec.description);
155 | if (spec.failedExpectations) {
156 | pad+=indent;
157 | spec.failedExpectations.forEach(function (fe) {
158 | results.push(pad + 'message: ' + fe.message);
159 | });
160 | pad=pad.substr(2);
161 | }
162 | });
163 | pad = pad.substr(2);
164 | results.push('');
165 | });
166 | results.push('');
167 | return results.join('\n');
168 | }
169 |
170 | // for console output
171 | var _pad;
172 | function log(str, indent) {
173 | _pad = _pad || '';
174 | if (indent == -1) {
175 | _pad = _pad.substr(2);
176 | }
177 | console.log(_pad + str);
178 | if (indent == 1) {
179 | _pad = _pad + ' ';
180 | }
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { AppComponent } from './app.component';
2 |
3 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
4 | import { By } from '@angular/platform-browser';
5 | import { DebugElement } from '@angular/core';
6 |
7 | describe('AppComponent', function () {
8 | let de: DebugElement;
9 | let comp: AppComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ AppComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(AppComponent);
21 | comp = fixture.componentInstance;
22 | de = fixture.debugElement.query(By.css('h1'));
23 | });
24 |
25 | it('should create component', () => expect(comp).toBeDefined() );
26 |
27 | it('should have expected text', () => {
28 | fixture.detectChanges();
29 | const h1 = de.nativeElement;
30 | expect(h1.innerText).toMatch(/angular/i,
31 | ' should say something about "Angular"');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import './rxjs.practice';
3 | import { Observable } from 'rxjs/Observable';
4 | import { ReplaySubject } from 'rxjs/ReplaySubject';
5 | import { Observer } from 'rxjs/Observer';
6 | import { extract } from './rxjs.practice';
7 | import 'rxjs/add/operator/mergeMap';
8 | import 'rxjs/add/operator/catch';
9 | import 'rxjs/add/operator/bufferCount';
10 | import 'rxjs/add/operator/take';
11 | import 'rxjs/add/operator/delay';
12 | import 'rxjs/add/operator/publish';
13 | import 'rxjs/add/observable/of';
14 | import 'rxjs/add/observable/from';
15 |
16 | @Component({
17 | selector: 'my-app',
18 | template: `
19 | {{title}}
20 |
21 | `,
22 | })
23 | export class AppComponent {
24 | title = 'RxJS is cool';
25 | socketConnections: { [key: string]: Observable } = {};
26 | cachedSockets: { [key: string]: Observable } = {};
27 | constructor() {
28 | // Tasl 2.1
29 | this.get$('http://someurl.com')
30 | .map(data => JSON.parse(data))
31 | .mergeMap(data => extract(data))
32 | .subscribe(console.log, console.error);
33 |
34 | // Task 2.2
35 | const urls = ['http://domain.com', 'http://domain.bg', 'http://domain.eu'];
36 | Observable.from(urls).mergeMap(url => this.get$(url)).map(data => JSON.parse(data)).subscribe(console.log);
37 |
38 | // Task 3.1
39 | Observable.from(urls).mergeMap(url => this.errorGet$(url)).map(data => JSON.parse(data)).subscribe(console.log, console.error);
40 |
41 | // Task 3.2
42 | Observable.from(urls)
43 | .mergeMap((url) => {
44 | return Observable.of(url)
45 | .mergeMap(url => this.errorGet$(url))
46 | .map(res => JSON.parse(res))
47 | .catch(err => {
48 | console.error(err);
49 | return Observable.of(null);
50 | })
51 | .map(responseData => ({ responseData, url }));
52 | })
53 | .bufferCount(urls.length)
54 | .subscribe(res => console.log('4.1 ', res));
55 |
56 | // Task 4.1
57 | const socket_url = 'Some URL';
58 | this.connect(socket_url).subscribe(data => console.log(`socket connecting 1: ${data}`));
59 | setTimeout(() => this.connect(socket_url).subscribe(data => console.log(`socket connection 2: ${data}`)), 4000);
60 |
61 | // Task 5.1
62 | const cache_socket_url = 'Cache Some URL';
63 | setTimeout(() => {
64 | console.log('Cache');
65 | setTimeout(() => this.socketCache(cache_socket_url).subscribe(data => console.log(`cached socket connection 1 ${data}`)), 2000);
66 | setTimeout(() => this.socketCache(cache_socket_url).subscribe(data => console.log(`cached socket connection 2: ${data}`)), 6000);
67 | setTimeout(() => this.socketCache(cache_socket_url).subscribe(data => console.log(`cached socket connection 3: ${data}`)), 12000);
68 | }, 10000);
69 | }
70 |
71 | get$(url: string): Observable {
72 | return new Observable((observer: Observer) => {
73 | const request = this.get(url, (err: any, data: any) => {
74 | if (err) return observer.error(err);
75 | observer.next(data);
76 | observer.complete();
77 | });
78 |
79 | return () => {
80 | request.cancel();
81 | };
82 | });
83 | }
84 |
85 | get(url: string, callback: any) {
86 | console.log(`fake get request to ${url}`);
87 | const id = setTimeout(() => {
88 | console.log(`get request JSON response`)
89 | callback(null, `[{
90 | "name": "Ivan",
91 | "age": 18
92 | }, {
93 | "name": "Petar",
94 | "age": 25
95 | }, {
96 | "name": "Alex",
97 | "age": 10
98 | }]`);
99 | }, 2000);
100 | return {
101 | cancel: () => clearInterval(id)
102 | };
103 | }
104 |
105 | errorGet(url: string, callback: any) {
106 | console.log(`fake get request to ${url}`);
107 | if (/(.*)\.(bg)/.test(url)) callback(new Error('Cannot resolve domain .bg'));
108 | const id = setTimeout(() => {
109 | console.log(`get request JSON response`)
110 | callback(null, `[{
111 | "name": "Ivan",
112 | "age": 18
113 | }, {
114 | "name": "Petar",
115 | "age": 25
116 | }, {
117 | "name": "Alex",
118 | "age": 10
119 | }]`)
120 | }, 2000);
121 | return {
122 | cancel: () => clearInterval(id)
123 | };
124 | }
125 |
126 | errorGet$(url: string): Observable {
127 | return new Observable((observer: Observer) => {
128 | const request = this.errorGet(url, (err: any, data: any) => {
129 | if (err) return observer.error(err);
130 | observer.next(data);
131 | observer.complete();
132 | });
133 |
134 | return () => {
135 | request.cancel();
136 | };
137 | });
138 | }
139 |
140 | connect(url: string) {
141 | console.log(`socket connecting to url: ${url}`);
142 | let socket;
143 | if (socket = this.socketConnections[url]) { return socket; }
144 | return this.socketConnections[url] = Observable.interval(1000)
145 | .startWith(-1)
146 | .delay(1000)
147 | .take(5)
148 | .map(i => i === -1 ? 'socket connected' : `socket message ${i}`)
149 | .publish()
150 | .refCount();
151 | }
152 |
153 | socketCache(url: string) {
154 | let socket;
155 | if (socket = this.cachedSockets[url]) { return socket; }
156 | const subject = new ReplaySubject();
157 | this.connect(url).subscribe(subject);
158 | return this.cachedSockets[url] = subject;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { ClockComponent } from './clock.component/clock.component';
4 |
5 | import { AppComponent } from './app.component';
6 |
7 | @NgModule({
8 | imports: [ BrowserModule ],
9 | declarations: [ AppComponent, ClockComponent ],
10 | bootstrap: [ AppComponent ]
11 | })
12 | export class AppModule { }
13 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/app/clock.component/clock.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Observable } from 'rxjs/Observable';
3 | import 'rxjs/add/observable/of';
4 | import 'rxjs/add/observable/interval';
5 | import 'rxjs/add/operator/delay';
6 | import 'rxjs/add/operator/map';
7 | import 'rxjs/add/operator/startWith';
8 |
9 | const getTime = () => {
10 | const d = new Date();
11 | return {
12 | hours: d.getHours(),
13 | minutes: d.getMinutes(),
14 | seconds: d.getSeconds()
15 | };
16 | };
17 |
18 | @Component({
19 | selector: 'clock',
20 | template: `
21 | 0 {{clock.hours}}:0 {{clock.minutes}}
22 | `,
23 | })
24 | export class ClockComponent {
25 | clock: { hours: number, minutes: number, seconds: number } = null;
26 | constructor() {
27 | /*
28 | Task 1.4
29 | This solution is more complicated because I want to have the exact time but the main idea was to have something like:
30 | Observable.interval(6000).startWith(0).map(getTime()).subscribe(...)
31 | */
32 | Observable.interval(60000) // every 60 seconds we want our stream to emit a value
33 | .startWith(0) // when the delay is over the interval will be turend on so we will miss one value so we just poroduce one here
34 | .delay((60 - getTime().seconds) * 1000) // we want our stream to produce values on the exact minute so seconds need to be 0
35 | .startWith(0) // produce an extra init value so we can get the clock initialized
36 | .map(() => getTime()) // we dont care about the value just get the time
37 | .map(val => { console.log(val); return val; }) // just loging
38 | .subscribe(val => this.clock = val); // set the value
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/app/rxjs.practice.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs/Observable';
2 | import 'rxjs/add/observable/from';
3 | import 'rxjs/add/observable/of';
4 | import 'rxjs/add/observable/zip';
5 | import 'rxjs/add/operator/reduce';
6 | import 'rxjs/add/operator/filter';
7 | import 'rxjs/add/operator/map';
8 | import 'rxjs/add/operator/bufferCount';
9 |
10 | const users = [{
11 | name: 'Ivan',
12 | age: 18
13 | }, {
14 | name: 'Petar',
15 | age: 25
16 | }, {
17 | name: 'Alex',
18 | age: 10
19 | }];
20 | // 1.1
21 | Observable.from([10, 64, 12, 32]).reduce((acc, curr) => acc + curr, 0).subscribe(console.log);
22 | // 1.2
23 | Observable.from([3, 7, 5, 2, 8, 1]).filter(x => x % 2 !== 0).subscribe(console.log);
24 | // 1.3
25 | export const extract = (arr: any[]) => {
26 | const source$ = Observable.from(arr);
27 | const names$ = source$.map(u => u.name).bufferCount(arr.length);
28 | const ages$ = source$.map(u => u.ages).bufferCount(arr.length);
29 | return Observable.zip(names$, ages$, (names, ages) => ({names, ages}));
30 | };
31 |
32 | extract(users).subscribe(console.log);
33 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week1/2/solutionsApp/src/favicon.ico
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Angular QuickStart
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 | Loading AppComponent content here ...
24 |
25 |
26 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 | platformBrowserDynamic().bootstrapModule(AppModule);
6 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/styles.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | color: #369;
3 | font-family: Arial, Helvetica, sans-serif;
4 | font-size: 250%;
5 | }
6 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/systemjs.config.extras.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Add barrels and stuff
3 | * Adjust as necessary for your application needs.
4 | */
5 | // (function (global) {
6 | // System.config({
7 | // packages: {
8 | // // add packages here
9 | // }
10 | // });
11 | // })(this);
12 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/systemjs.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * System configuration for Angular samples
3 | * Adjust as necessary for your application needs.
4 | */
5 | (function (global) {
6 | System.config({
7 | paths: {
8 | // paths serve as alias
9 | 'npm:': 'node_modules/'
10 | },
11 | // map tells the System loader where to look for things
12 | map: {
13 | // our app is within the app folder
14 | app: 'app',
15 |
16 | // angular bundles
17 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
18 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
19 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
20 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
21 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
22 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
23 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
24 | // '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
25 |
26 | // other libraries
27 | 'rxjs': 'npm:rxjs',
28 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
29 | },
30 | // packages tells the System loader how to load when no filename and/or no extension
31 | packages: {
32 | app: {
33 | defaultExtension: 'js'
34 | },
35 | rxjs: {
36 | defaultExtension: 'js'
37 | }
38 | }
39 | });
40 | })(this);
41 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "lib": [ "es2015", "dom" ],
10 | "noImplicitAny": true,
11 | "suppressImplicitAnyIndexErrors": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/week1/2/solutionsApp/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "comment-format": [
5 | true,
6 | "check-space"
7 | ],
8 | "curly": true,
9 | "eofline": true,
10 | "forin": true,
11 | "indent": [
12 | true,
13 | "spaces"
14 | ],
15 | "label-position": true,
16 | "label-undefined": true,
17 | "max-line-length": [
18 | true,
19 | 140
20 | ],
21 | "member-access": false,
22 | "member-ordering": [
23 | true,
24 | "static-before-instance",
25 | "variables-before-functions"
26 | ],
27 | "no-arg": true,
28 | "no-bitwise": true,
29 | "no-console": [
30 | true,
31 | "debug",
32 | "info",
33 | "time",
34 | "timeEnd",
35 | "trace"
36 | ],
37 | "no-construct": true,
38 | "no-debugger": true,
39 | "no-duplicate-key": true,
40 | "no-duplicate-variable": true,
41 | "no-empty": false,
42 | "no-eval": true,
43 | "no-inferrable-types": true,
44 | "no-shadowed-variable": true,
45 | "no-string-literal": false,
46 | "no-switch-case-fall-through": true,
47 | "no-trailing-whitespace": true,
48 | "no-unused-expression": true,
49 | "no-unused-variable": true,
50 | "no-unreachable": true,
51 | "no-use-before-declare": true,
52 | "no-var-keyword": true,
53 | "object-literal-sort-keys": false,
54 | "one-line": [
55 | true,
56 | "check-open-brace",
57 | "check-catch",
58 | "check-else",
59 | "check-whitespace"
60 | ],
61 | "quotemark": [
62 | true,
63 | "single"
64 | ],
65 | "radix": true,
66 | "semicolon": [
67 | "always"
68 | ],
69 | "triple-equals": [
70 | true,
71 | "allow-null-check"
72 | ],
73 | "typedef-whitespace": [
74 | true,
75 | {
76 | "call-signature": "nospace",
77 | "index-signature": "nospace",
78 | "parameter": "nospace",
79 | "property-declaration": "nospace",
80 | "variable-declaration": "nospace"
81 | }
82 | ],
83 | "variable-name": false,
84 | "whitespace": [
85 | true,
86 | "check-branch",
87 | "check-decl",
88 | "check-operator",
89 | "check-separator",
90 | "check-type"
91 | ]
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/week2/1/README.md:
--------------------------------------------------------------------------------
1 | # Week 2
2 |
3 | ## Lecture
4 | Click [here](https://speakerdeck.com/iliaidakiev/3-angular-cli-custom-directives-renderer)
5 |
6 | ## Tasks
7 |
8 | 1. Create a custom directive called angActive that takes two inputs. The first input is a color that needs to be applied if the second input is true (second input is a predicate).
9 |
10 | 2. Create a custom directive called angIf that shows the contents of the template if a condition is true and hides it otherwise.
11 |
12 | 3. Create a custom directive angIfElse. (Use ContentChild or ContentChildren to get the children)
13 |
14 | 4. Create a directive called pager. It takes three inputs: data - array of items, currentPage and pageSize. Depending on the inputs it needs to list the necessary items. (use rxjs skip and take operators)
15 |
16 | 5. Create a component called grid. It has the same inputs as pager and it uses pager to present the data. The grid component needs to hold the state for the currentPage and to create buttons for the different pages (use the directive from task 1). Handle the case when there are too many pages and some of the page buttons are replaced by ... (example 1 2 3 ... 10, 1 ... 4 5 6 ... 10)
--------------------------------------------------------------------------------
/week2/1/tasks/.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 |
--------------------------------------------------------------------------------
/week2/1/tasks/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 |
7 | # dependencies
8 | /node_modules
9 |
10 | # IDEs and editors
11 | /.idea
12 | .project
13 | .classpath
14 | .c9/
15 | *.launch
16 | .settings/
17 |
18 | # IDE - VSCode
19 | .vscode/*
20 | !.vscode/settings.json
21 | !.vscode/tasks.json
22 | !.vscode/launch.json
23 | !.vscode/extensions.json
24 |
25 | # misc
26 | /.sass-cache
27 | /connect.lock
28 | /coverage/*
29 | /libpeerconnection.log
30 | npm-debug.log
31 | testem.log
32 | /typings
33 |
34 | # e2e
35 | /e2e/*.js
36 | /e2e/*.map
37 |
38 | #System Files
39 | .DS_Store
40 | Thumbs.db
41 |
--------------------------------------------------------------------------------
/week2/1/tasks/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "vsicons.presets.angular": true
3 | }
--------------------------------------------------------------------------------
/week2/1/tasks/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "0.1.0",
5 | "command": "echo",
6 | "isShellCommand": true,
7 | "args": ["Hello World"],
8 | "showOutput": "never"
9 | }
--------------------------------------------------------------------------------
/week2/1/tasks/README.md:
--------------------------------------------------------------------------------
1 | # Tasks
2 |
3 | This project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.28.3.
4 |
5 | ## Development server
6 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
7 |
8 | ## Code scaffolding
9 |
10 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
11 |
12 | ## Build
13 |
14 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
15 |
16 | ## Running unit tests
17 |
18 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
19 |
20 | ## Running end-to-end tests
21 |
22 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
23 | Before running the tests make sure you are serving the app via `ng serve`.
24 |
25 | ## Deploying to GitHub Pages
26 |
27 | Run `ng github-pages:deploy` to deploy to GitHub Pages.
28 |
29 | ## Further help
30 |
31 | To get more help on the `angular-cli` use `ng help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
32 |
--------------------------------------------------------------------------------
/week2/1/tasks/angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "project": {
3 | "version": "1.0.0-beta.28.3",
4 | "name": "tasks"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.json",
19 | "prefix": "app",
20 | "styles": [
21 | "styles.css"
22 | ],
23 | "scripts": [],
24 | "environments": {
25 | "source": "environments/environment.ts",
26 | "dev": "environments/environment.ts",
27 | "prod": "environments/environment.prod.ts"
28 | }
29 | }
30 | ],
31 | "e2e": {
32 | "protractor": {
33 | "config": "./protractor.conf.js"
34 | }
35 | },
36 | "lint": [
37 | {
38 | "files": "src/**/*.ts",
39 | "project": "src/tsconfig.json"
40 | },
41 | {
42 | "files": "e2e/**/*.ts",
43 | "project": "e2e/tsconfig.json"
44 | }
45 | ],
46 | "test": {
47 | "karma": {
48 | "config": "./karma.conf.js"
49 | }
50 | },
51 | "defaults": {
52 | "styleExt": "css",
53 | "prefixInterfaces": false,
54 | "inline": {
55 | "style": false,
56 | "template": false
57 | },
58 | "spec": {
59 | "class": false,
60 | "component": true,
61 | "directive": true,
62 | "module": false,
63 | "pipe": true,
64 | "service": true
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/week2/1/tasks/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { TasksPage } from './app.po';
2 |
3 | describe('tasks App', function() {
4 | let page: TasksPage;
5 |
6 | beforeEach(() => {
7 | page = new TasksPage();
8 | });
9 |
10 | it('should display message saying app works', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('app works!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/week2/1/tasks/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | export class TasksPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/week2/1/tasks/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "module": "commonjs",
8 | "moduleResolution": "node",
9 | "outDir": "../dist/out-tsc-e2e",
10 | "sourceMap": true,
11 | "target": "es5",
12 | "typeRoots": [
13 | "../node_modules/@types"
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/week2/1/tasks/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-remap-istanbul'),
12 | require('angular-cli/plugins/karma')
13 | ],
14 | files: [
15 | { pattern: './src/test.ts', watched: false }
16 | ],
17 | preprocessors: {
18 | './src/test.ts': ['angular-cli']
19 | },
20 | mime: {
21 | 'text/x-typescript': ['ts','tsx']
22 | },
23 | remapIstanbulReporter: {
24 | reports: {
25 | html: 'coverage',
26 | lcovonly: './coverage/coverage.lcov'
27 | }
28 | },
29 | angularCli: {
30 | config: './angular-cli.json',
31 | environment: 'dev'
32 | },
33 | reporters: config.angularCli && config.angularCli.codeCoverage
34 | ? ['progress', 'karma-remap-istanbul']
35 | : ['progress'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false
42 | });
43 | };
44 |
--------------------------------------------------------------------------------
/week2/1/tasks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tasks",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "angular-cli": {},
6 | "scripts": {
7 | "ng": "ng",
8 | "start": "ng serve",
9 | "test": "ng test",
10 | "pree2e": "webdriver-manager update --standalone false --gecko false",
11 | "e2e": "protractor"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/common": "^2.3.1",
16 | "@angular/compiler": "^2.3.1",
17 | "@angular/core": "^2.3.1",
18 | "@angular/forms": "^2.3.1",
19 | "@angular/http": "^2.3.1",
20 | "@angular/platform-browser": "^2.3.1",
21 | "@angular/platform-browser-dynamic": "^2.3.1",
22 | "@angular/router": "^3.3.1",
23 | "core-js": "^2.4.1",
24 | "rxjs": "^5.0.1",
25 | "ts-helpers": "^1.1.1",
26 | "zone.js": "^0.7.2"
27 | },
28 | "devDependencies": {
29 | "@angular/compiler-cli": "^2.3.1",
30 | "@types/jasmine": "2.5.38",
31 | "@types/node": "^6.0.42",
32 | "angular-cli": "1.0.0-beta.28.3",
33 | "codelyzer": "~2.0.0-beta.1",
34 | "jasmine-core": "2.5.2",
35 | "jasmine-spec-reporter": "2.5.0",
36 | "karma": "1.2.0",
37 | "karma-chrome-launcher": "^2.0.0",
38 | "karma-cli": "^1.0.1",
39 | "karma-jasmine": "^1.0.2",
40 | "karma-remap-istanbul": "^0.2.1",
41 | "protractor": "~4.0.13",
42 | "ts-node": "1.2.1",
43 | "tslint": "^4.3.0",
44 | "typescript": "~2.0.3"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/week2/1/tasks/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 | /*global jasmine */
5 | var SpecReporter = require('jasmine-spec-reporter');
6 |
7 | exports.config = {
8 | allScriptsTimeout: 11000,
9 | specs: [
10 | './e2e/**/*.e2e-spec.ts'
11 | ],
12 | capabilities: {
13 | 'browserName': 'chrome'
14 | },
15 | directConnect: true,
16 | baseUrl: 'http://localhost:4200/',
17 | framework: 'jasmine',
18 | jasmineNodeOpts: {
19 | showColors: true,
20 | defaultTimeoutInterval: 30000,
21 | print: function() {}
22 | },
23 | useAllAngular2AppRoots: true,
24 | beforeLaunch: function() {
25 | require('ts-node').register({
26 | project: 'e2e'
27 | });
28 | },
29 | onPrepare: function() {
30 | jasmine.getEnv().addReporter(new SpecReporter());
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week2/1/tasks/src/app/app.component.css
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{title}}
3 |
4 |
5 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 |
3 | import { TestBed, async } from '@angular/core/testing';
4 | import { AppComponent } from './app.component';
5 |
6 | describe('AppComponent', () => {
7 | beforeEach(() => {
8 | TestBed.configureTestingModule({
9 | declarations: [
10 | AppComponent
11 | ],
12 | });
13 | TestBed.compileComponents();
14 | });
15 |
16 | it('should create the app', async(() => {
17 | const fixture = TestBed.createComponent(AppComponent);
18 | const app = fixture.debugElement.componentInstance;
19 | expect(app).toBeTruthy();
20 | }));
21 |
22 | it(`should have as title 'app works!'`, async(() => {
23 | const fixture = TestBed.createComponent(AppComponent);
24 | const app = fixture.debugElement.componentInstance;
25 | expect(app.title).toEqual('app works!');
26 | }));
27 |
28 | it('should render title in a h1 tag', async(() => {
29 | const fixture = TestBed.createComponent(AppComponent);
30 | fixture.detectChanges();
31 | const compiled = fixture.debugElement.nativeElement;
32 | expect(compiled.querySelector('h1').textContent).toContain('app works!');
33 | }));
34 | });
35 |
--------------------------------------------------------------------------------
/week2/1/tasks/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 works!';
10 | data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
11 | }
12 |
--------------------------------------------------------------------------------
/week2/1/tasks/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 { DirectivesModule } from './directives/directives.module';
8 |
9 | @NgModule({
10 | declarations: [
11 | AppComponent
12 | ],
13 | imports: [
14 | BrowserModule,
15 | FormsModule,
16 | HttpModule,
17 | DirectivesModule
18 | ],
19 | providers: [],
20 | bootstrap: [AppComponent]
21 | })
22 | export class AppModule { }
23 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/directives.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { PagerDirective } from './pager.directive';
4 | import { GridComponent } from './grid/grid.component';
5 |
6 | @NgModule({
7 | imports: [
8 | CommonModule
9 | ],
10 | declarations: [PagerDirective, GridComponent],
11 | exports: [GridComponent]
12 | })
13 | export class DirectivesModule { }
14 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/grid/grid.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week2/1/tasks/src/app/directives/grid/grid.component.css
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/grid/grid.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{item}}
3 |
4 | Prev
5 | Next
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/grid/grid.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { GridComponent } from './grid.component';
7 |
8 | describe('GridComponent', () => {
9 | let component: GridComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ GridComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(GridComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/grid/grid.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-grid',
5 | templateUrl: './grid.component.html',
6 | styleUrls: ['./grid.component.css']
7 | })
8 | export class GridComponent implements OnInit {
9 |
10 | @Input() pageSize: number;
11 | @Input() data: any[];
12 | currentPage: number = 1;
13 |
14 | constructor() { }
15 |
16 | ngOnInit() {
17 | this.pageSize = parseInt(this.pageSize.toString());
18 | }
19 |
20 | prev() {
21 | if(this.currentPage - 1 <= 0) return;
22 | --this.currentPage;
23 | }
24 |
25 | next() {
26 | if(this.currentPage + 1 > Math.ceil(this.data.length / this.pageSize)) return;
27 | ++this.currentPage;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/pager.directive.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 |
3 | import { TestBed, async } from '@angular/core/testing';
4 | import { PagerDirective } from './pager.directive';
5 |
6 | describe('PagerDirective', () => {
7 | it('should create an instance', () => {
8 | const directive = new PagerDirective();
9 | expect(directive).toBeTruthy();
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/app/directives/pager.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, TemplateRef, ViewContainerRef, Input, ContentChild, OnChanges } from '@angular/core';
2 | import { Observable } from 'rxjs/Observable';
3 | import 'rxjs/add/observable/from';
4 | import 'rxjs/add/operator/skip';
5 | import 'rxjs/add/operator/take';
6 |
7 | @Directive({
8 | selector: '[pager]'
9 | })
10 | export class PagerDirective implements OnChanges {
11 | @Input() pageSize: number;
12 | @Input() currentPage: number;
13 | @Input() data: any[];
14 |
15 | constructor(private _template: TemplateRef, private _vc: ViewContainerRef) { }
16 |
17 | ngOnChanges() {
18 | this._vc.clear();
19 | Observable.from(this.data).skip((this.currentPage - 1) * this.pageSize).take(this.pageSize).subscribe(item => {
20 | this._vc.createEmbeddedView(this._template, { item });
21 | });
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week2/1/tasks/src/assets/.gitkeep
--------------------------------------------------------------------------------
/week2/1/tasks/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/week2/1/tasks/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 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week2/1/tasks/src/favicon.ico
--------------------------------------------------------------------------------
/week2/1/tasks/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Tasks
6 |
7 |
8 |
9 |
10 |
11 |
12 | Loading...
13 |
14 |
15 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 | import { enableProdMode } from '@angular/core';
3 | import { environment } from './environments/environment';
4 | import { AppModule } from './app/app.module';
5 |
6 | if (environment.production) {
7 | enableProdMode();
8 | }
9 |
10 | platformBrowserDynamic().bootstrapModule(AppModule);
11 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | // This file includes polyfills needed by Angular and is loaded before the app.
2 | // You can add your own extra polyfills to this file.
3 | import 'core-js/es6/symbol';
4 | import 'core-js/es6/object';
5 | import 'core-js/es6/function';
6 | import 'core-js/es6/parse-int';
7 | import 'core-js/es6/parse-float';
8 | import 'core-js/es6/number';
9 | import 'core-js/es6/math';
10 | import 'core-js/es6/string';
11 | import 'core-js/es6/date';
12 | import 'core-js/es6/array';
13 | import 'core-js/es6/regexp';
14 | import 'core-js/es6/map';
15 | import 'core-js/es6/set';
16 | import 'core-js/es6/reflect';
17 |
18 | import 'core-js/es7/reflect';
19 | import 'zone.js/dist/zone';
20 |
21 | // If you need to support the browsers/features below, uncomment the import
22 | // and run `npm install import-name-here';
23 | // Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
24 |
25 | // Needed for: IE9
26 | // import 'classlist.js';
27 |
28 | // Animations
29 | // Needed for: All but Chrome and Firefox, Not supported in IE9
30 | // import 'web-animations-js';
31 |
32 | // Date, currency, decimal and percent pipes
33 | // Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
34 | // import 'intl';
35 |
36 | // NgClass on SVG elements
37 | // Needed for: IE10, IE11
38 | // import 'classlist.js';
39 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare var __karma__: any;
17 | declare var require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/week2/1/tasks/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "",
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "lib": ["es6", "dom"],
8 | "mapRoot": "./",
9 | "module": "es6",
10 | "moduleResolution": "node",
11 | "outDir": "../dist/out-tsc",
12 | "sourceMap": true,
13 | "target": "es5",
14 | "typeRoots": [
15 | "../node_modules/@types"
16 | ]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/week2/1/tasks/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": true,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": true,
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/week2/2/README.md:
--------------------------------------------------------------------------------
1 | # Week 2.2
2 |
3 | ## Lecture
4 | Click [here](https://speakerdeck.com/iliaidakiev/4-dependency-injection-providers-and-injectors)
5 |
6 | ## Tasks
7 | For all tasks we are going to use this [API](https://jsonplaceholder.typicode.com)
8 |
9 | 1. Create a models for user, post and comment that will interact with the http service. They need to fetch the data when needed and sore it in a DataSource class that will act as storage. Whenever the component needs data it will ask the model for it. The model will check the store to see if its available and return it. If not, the model will fetch the data from the API, store it in the dataSource and return it to the component (inclue a flag that will be used for force fetch). Separate logic into differnet modules and just list all the items.
10 |
11 | 2. Refactor the DataSource to act as Hot Observable for each store entry (you can use Subjects if you feel like for the different data that we will be keeping (in our case users, posts comments)). When ever a certain entity is updated we want the store to to push the update to all of its subscribers for the certain set. The idea is to extract the state from our components into one place.
--------------------------------------------------------------------------------
/week3/1/README.md:
--------------------------------------------------------------------------------
1 | # Week 3.1
2 |
3 | ### Lecture
4 |
5 | [Click here!](https://speakerdeck.com/iliaidakiev/5-predictable-reactive-state-management)
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/.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 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 |
7 | # dependencies
8 | /node_modules
9 |
10 | # IDEs and editors
11 | /.idea
12 | .project
13 | .classpath
14 | .c9/
15 | *.launch
16 | .settings/
17 |
18 | # IDE - VSCode
19 | .vscode/*
20 | !.vscode/settings.json
21 | !.vscode/tasks.json
22 | !.vscode/launch.json
23 | !.vscode/extensions.json
24 |
25 | # misc
26 | /.sass-cache
27 | /connect.lock
28 | /coverage/*
29 | /libpeerconnection.log
30 | npm-debug.log
31 | testem.log
32 | /typings
33 |
34 | # e2e
35 | /e2e/*.js
36 | /e2e/*.map
37 |
38 | #System Files
39 | .DS_Store
40 | Thumbs.db
41 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "0.1.0",
5 | "command": "echo",
6 | "isShellCommand": true,
7 | "args": [""],
8 | "showOutput": "never"
9 | }
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/README.md:
--------------------------------------------------------------------------------
1 | # NgrxTodoApp
2 |
3 | This project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.28.3.
4 |
5 | ## Development server
6 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
7 |
8 | ## Code scaffolding
9 |
10 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
11 |
12 | ## Build
13 |
14 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
15 |
16 | ## Running unit tests
17 |
18 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
19 |
20 | ## Running end-to-end tests
21 |
22 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
23 | Before running the tests make sure you are serving the app via `ng serve`.
24 |
25 | ## Deploying to GitHub Pages
26 |
27 | Run `ng github-pages:deploy` to deploy to GitHub Pages.
28 |
29 | ## Further help
30 |
31 | To get more help on the `angular-cli` use `ng help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
32 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "project": {
3 | "version": "1.0.0-beta.28.3",
4 | "name": "ngrx-todo-app"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.json",
19 | "prefix": "app",
20 | "styles": [
21 | "styles.css"
22 | ],
23 | "scripts": [],
24 | "environments": {
25 | "source": "environments/environment.ts",
26 | "dev": "environments/environment.ts",
27 | "prod": "environments/environment.prod.ts"
28 | }
29 | }
30 | ],
31 | "e2e": {
32 | "protractor": {
33 | "config": "./protractor.conf.js"
34 | }
35 | },
36 | "lint": [
37 | {
38 | "files": "src/**/*.ts",
39 | "project": "src/tsconfig.json"
40 | },
41 | {
42 | "files": "e2e/**/*.ts",
43 | "project": "e2e/tsconfig.json"
44 | }
45 | ],
46 | "test": {
47 | "karma": {
48 | "config": "./karma.conf.js"
49 | }
50 | },
51 | "defaults": {
52 | "styleExt": "css",
53 | "prefixInterfaces": false,
54 | "inline": {
55 | "style": false,
56 | "template": false
57 | },
58 | "spec": {
59 | "class": false,
60 | "component": true,
61 | "directive": true,
62 | "module": false,
63 | "pipe": true,
64 | "service": true
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { NgrxTodoAppPage } from './app.po';
2 |
3 | describe('ngrx-todo-app App', function() {
4 | let page: NgrxTodoAppPage;
5 |
6 | beforeEach(() => {
7 | page = new NgrxTodoAppPage();
8 | });
9 |
10 | it('should display message saying app works', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('app works!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | export class NgrxTodoAppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "module": "commonjs",
8 | "moduleResolution": "node",
9 | "outDir": "../dist/out-tsc-e2e",
10 | "sourceMap": true,
11 | "target": "es5",
12 | "typeRoots": [
13 | "../node_modules/@types"
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/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-remap-istanbul'),
12 | require('angular-cli/plugins/karma')
13 | ],
14 | files: [
15 | { pattern: './src/test.ts', watched: false }
16 | ],
17 | preprocessors: {
18 | './src/test.ts': ['angular-cli']
19 | },
20 | mime: {
21 | 'text/x-typescript': ['ts','tsx']
22 | },
23 | remapIstanbulReporter: {
24 | reports: {
25 | html: 'coverage',
26 | lcovonly: './coverage/coverage.lcov'
27 | }
28 | },
29 | angularCli: {
30 | config: './angular-cli.json',
31 | environment: 'dev'
32 | },
33 | reporters: config.angularCli && config.angularCli.codeCoverage
34 | ? ['progress', 'karma-remap-istanbul']
35 | : ['progress'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false
42 | });
43 | };
44 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngrx-todo-app",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "angular-cli": {},
6 | "scripts": {
7 | "ng": "ng",
8 | "start": "ng serve",
9 | "test": "ng test",
10 | "pree2e": "webdriver-manager update --standalone false --gecko false",
11 | "e2e": "protractor"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/common": "^2.3.1",
16 | "@angular/compiler": "^2.3.1",
17 | "@angular/core": "^2.3.1",
18 | "@angular/forms": "^2.3.1",
19 | "@angular/http": "^2.3.1",
20 | "@angular/platform-browser": "^2.3.1",
21 | "@angular/platform-browser-dynamic": "^2.3.1",
22 | "@angular/router": "^3.3.1",
23 | "@ngrx/core": "^1.2.0",
24 | "@ngrx/effects": "^2.0.0",
25 | "@ngrx/router-store": "^1.2.5",
26 | "@ngrx/store": "^2.2.1",
27 | "@ngrx/store-devtools": "^3.2.3",
28 | "core-js": "^2.4.1",
29 | "immutability-helper": "^2.1.1",
30 | "reselect": "^2.5.4",
31 | "rxjs": "^5.0.1",
32 | "ts-helpers": "^1.1.1",
33 | "zone.js": "^0.7.2"
34 | },
35 | "devDependencies": {
36 | "@angular/compiler-cli": "^2.3.1",
37 | "@types/jasmine": "2.5.38",
38 | "@types/node": "^6.0.42",
39 | "angular-cli": "1.0.0-beta.28.3",
40 | "codelyzer": "~2.0.0-beta.1",
41 | "jasmine-core": "2.5.2",
42 | "jasmine-spec-reporter": "2.5.0",
43 | "karma": "1.2.0",
44 | "karma-chrome-launcher": "^2.0.0",
45 | "karma-cli": "^1.0.1",
46 | "karma-jasmine": "^1.0.2",
47 | "karma-remap-istanbul": "^0.2.1",
48 | "protractor": "~4.0.13",
49 | "ts-node": "1.2.1",
50 | "tslint": "^4.3.0",
51 | "typescript": "~2.0.3"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/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 | /*global jasmine */
5 | var SpecReporter = require('jasmine-spec-reporter');
6 |
7 | exports.config = {
8 | allScriptsTimeout: 11000,
9 | specs: [
10 | './e2e/**/*.e2e-spec.ts'
11 | ],
12 | capabilities: {
13 | 'browserName': 'chrome'
14 | },
15 | directConnect: true,
16 | baseUrl: 'http://localhost:4200/',
17 | framework: 'jasmine',
18 | jasmineNodeOpts: {
19 | showColors: true,
20 | defaultTimeoutInterval: 30000,
21 | print: function() {}
22 | },
23 | useAllAngular2AppRoots: true,
24 | beforeLaunch: function() {
25 | require('ts-node').register({
26 | project: 'e2e'
27 | });
28 | },
29 | onPrepare: function() {
30 | jasmine.getEnv().addReporter(new SpecReporter());
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week3/1/ngrxTodoApp/src/app/app.component.css
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{title}}
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{model.todos$ | async | json }}
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 |
3 | import { TestBed, async } from '@angular/core/testing';
4 | import { AppComponent } from './app.component';
5 |
6 | describe('AppComponent', () => {
7 | beforeEach(() => {
8 | TestBed.configureTestingModule({
9 | declarations: [
10 | AppComponent
11 | ],
12 | });
13 | TestBed.compileComponents();
14 | });
15 |
16 | it('should create the app', async(() => {
17 | const fixture = TestBed.createComponent(AppComponent);
18 | const app = fixture.debugElement.componentInstance;
19 | expect(app).toBeTruthy();
20 | }));
21 |
22 | it(`should have as title 'app works!'`, async(() => {
23 | const fixture = TestBed.createComponent(AppComponent);
24 | const app = fixture.debugElement.componentInstance;
25 | expect(app.title).toEqual('app works!');
26 | }));
27 |
28 | it('should render title in a h1 tag', async(() => {
29 | const fixture = TestBed.createComponent(AppComponent);
30 | fixture.detectChanges();
31 | const compiled = fixture.debugElement.nativeElement;
32 | expect(compiled.querySelector('h1').textContent).toContain('app works!');
33 | }));
34 | });
35 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { AppModel } from './store/app.model';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.css']
8 | })
9 | export class AppComponent {
10 | title = 'app works!';
11 | constructor(private model: AppModel) {
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/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 { StoreModule } from '@ngrx/store';
7 |
8 | import { AppComponent } from './app.component';
9 | import { TodoListComponent } from './todo-list/todo-list.component';
10 | import { TodoEditComponent } from './todo-edit/todo-edit.component';
11 | import { TodoFilterComponent } from './todo-filter/todo-filter.component';
12 | import { todoReducer } from './store/app.reducer';
13 |
14 | // import { appStore } from './store/index';
15 |
16 | import { StoreDevtoolsModule } from '@ngrx/store-devtools';
17 | import { AppModel } from './store/app.model';
18 |
19 | @NgModule({
20 | declarations: [
21 | AppComponent,
22 | TodoListComponent,
23 | TodoEditComponent,
24 | TodoFilterComponent
25 | ],
26 | imports: [
27 | BrowserModule,
28 | FormsModule,
29 | HttpModule,
30 | StoreModule.provideStore(todoReducer),
31 | StoreDevtoolsModule.instrumentOnlyWithExtension()
32 | ],
33 | providers: [ AppModel ],
34 | bootstrap: [AppComponent]
35 | })
36 | export class AppModule { }
37 |
38 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/filter-state.enum.ts:
--------------------------------------------------------------------------------
1 | export enum FilterState {
2 | Default,
3 | CompletedOnly,
4 | All
5 | };
6 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/store/app.actions.ts:
--------------------------------------------------------------------------------
1 | import { Action } from '@ngrx/store';
2 | import { FilterState } from '../filter-state.enum';
3 | import { Todo } from '../todo.model';
4 |
5 | export const ActionTypes = {
6 | SAVE_TODO: '[App] Save Todo',
7 | TODO_SAVED: '[App] Todo Saved',
8 | TODO_TOGGLE: '[App] Todo Toggle',
9 | TODO_TOGGLED: '[App] Todo Toggled',
10 | SET_FILTER: '[App] Set Filter'
11 | };
12 |
13 | export class SaveTodoAction implements Action {
14 | type = ActionTypes.SAVE_TODO;
15 | constructor(public payload: { todo: Todo }) {}
16 | }
17 |
18 | export class CompleteTodoAction implements Action {
19 | type = ActionTypes.TODO_TOGGLE;
20 | constructor(public payload: { id: number }) {}
21 | }
22 |
23 | export class SetFilterAction implements Action {
24 | type = ActionTypes.SET_FILTER;
25 | constructor(public payload: { filterState: FilterState }) {}
26 | }
27 |
28 |
29 |
30 |
31 | export class TodoSavedAction implements Action {
32 | type = ActionTypes.TODO_SAVED;
33 | constructor(public payload: { todo: Todo }) {}
34 | }
35 |
36 | export class TodoCompletedAction implements Action {
37 | type = ActionTypes.TODO_TOGGLED;
38 | constructor(public payload: { id: number }) {}
39 | }
40 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/store/app.model.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Store } from '@ngrx/store';
3 | import { IAppState, todoReducer, getTodos, getFilterState, getFilteredTodos } from './app.reducer';
4 | import { Todo } from '../todo.model';
5 | import { Observable } from 'rxjs/Observable';
6 | import { FilterState } from '../filter-state.enum';
7 | import { SaveTodoAction, CompleteTodoAction, SetFilterAction } from './app.actions';
8 |
9 | @Injectable()
10 | export class AppModel {
11 | todos$: Observable;
12 | filterState$: Observable;
13 |
14 | constructor(private _store: Store) {
15 | this.todos$ = this._store.select(s => getFilteredTodos(s));
16 | this.filterState$ = this._store.select(s => getFilterState(s));
17 | }
18 |
19 | addTodo(todo: Todo) {
20 | this._store.dispatch(new SaveTodoAction({ todo }));
21 | }
22 |
23 | toggleCompleted(todo: Todo) {
24 | this._store.dispatch(new CompleteTodoAction({ id: todo.id }));
25 | }
26 |
27 | setFilter(filterState: FilterState) {
28 | this._store.dispatch(new SetFilterAction({ filterState }));
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/store/app.reducer.ts:
--------------------------------------------------------------------------------
1 | import { ActionTypes } from './app.actions';
2 | import { Todo } from '../todo.model';
3 | import { FilterState } from '../filter-state.enum';
4 | import { Action, combineReducers } from '@ngrx/store';
5 | import { reducerFactory } from './reducer-factory';
6 | import { routerReducer, RouterStoreModule } from '@ngrx/router-store';
7 |
8 | import { createSelector } from 'reselect';
9 |
10 | export interface IAppState {
11 | readonly todos?: Todo[];
12 | readonly filterState?: FilterState;
13 | }
14 |
15 | export const initialState: IAppState = {
16 | todos: [],
17 | filterState: FilterState.Default
18 | };
19 |
20 | export const map: { [key: string]: (payload: any, state: IAppState) => IAppState} = {
21 | [ActionTypes.SAVE_TODO]: function(payload: { todo: Todo }, state: IAppState) {
22 | const newState: IAppState = {
23 | todos: state.todos.concat(payload.todo)
24 | };
25 | return Object.assign({}, state, newState);
26 | },
27 | [ActionTypes.TODO_TOGGLE]: function(payload: { id: number }, state: IAppState) {
28 | const todosUpdated = state.todos.map(t => {
29 | if (t.id !== payload.id) return t;
30 | return Object.assign({}, t, { checked: !t.checked });
31 | });
32 | const newState: IAppState = {
33 | todos: todosUpdated
34 | };
35 | return Object.assign({}, state, newState);
36 | },
37 | [ActionTypes.SET_FILTER]: function(paylaod: { filterState: FilterState }, state: IAppState) {
38 | const newState: IAppState = {
39 | filterState: paylaod.filterState
40 | };
41 | return Object.assign({}, state, newState);
42 | }
43 | };
44 |
45 | export function todoReducer(state, action) {
46 | const todoReducer = reducerFactory(initialState, map);
47 | return todoReducer(state, action);
48 | // const customRouterReducer = function(theState, theAction) {
49 | // console.log(theAction, 'routerReducer');
50 | // return routerReducer(theState, theAction);
51 | // };
52 | // return combineReducers({ todo: todoReducer, router: customRouterReducer })(state, action);
53 | }
54 |
55 |
56 | export const getTodos = (state: IAppState) => state.todos;
57 | export const getFilterState = (state: IAppState) => state.filterState;
58 |
59 | export const getFilteredTodos = createSelector(getTodos, getFilterState, (todos: Todo[], filterState: FilterState) => {
60 | let result;
61 | switch (filterState) {
62 | case FilterState.Default:
63 | result = todos.filter(t => !t.checked);
64 | break;
65 | case FilterState.CompletedOnly:
66 | result = todos.filter(t => t.checked);
67 | break;
68 | case FilterState.All:
69 | result = todos;
70 | break;
71 | }
72 | return result;
73 | });
74 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/store/index.ts:
--------------------------------------------------------------------------------
1 | import { todoReducer } from './app.reducer';
2 |
3 | export function appStore(state, action) {
4 | return {
5 | todo: todoReducer(state, action)
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/store/reducer-factory.ts:
--------------------------------------------------------------------------------
1 | import { Action } from '@ngrx/store';
2 |
3 | export function reducerFactory(initialState: State, map: { [key: string]: (payload: any, state: State) => State } ) {
4 | return function reducer(state = initialState, action: Action) {
5 | return map[action.type] && map[action.type](action.payload, state) || state;
6 | };
7 | };
8 |
9 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-edit/todo-edit.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week3/1/ngrxTodoApp/src/app/todo-edit/todo-edit.component.css
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-edit/todo-edit.component.html:
--------------------------------------------------------------------------------
1 | Add Todo
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-edit/todo-edit.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { TodoEditComponent } from './todo-edit.component';
7 |
8 | describe('TodoEditComponent', () => {
9 | let component: TodoEditComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ TodoEditComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(TodoEditComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-edit/todo-edit.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { AppModel } from '../store/app.model';
3 | import { Todo } from '../todo.model';
4 |
5 | @Component({
6 | selector: 'app-todo-edit',
7 | templateUrl: './todo-edit.component.html',
8 | styleUrls: ['./todo-edit.component.css']
9 | })
10 | export class TodoEditComponent implements OnInit {
11 |
12 | constructor(private appModel: AppModel) { }
13 |
14 | ngOnInit() {
15 | }
16 |
17 | addTodo(text: string) {
18 | this.appModel.addTodo(new Todo(text));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-filter/todo-filter.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week3/1/ngrxTodoApp/src/app/todo-filter/todo-filter.component.css
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-filter/todo-filter.component.html:
--------------------------------------------------------------------------------
1 |
2 | Default
3 | CompletedOnly
4 | All
5 |
6 | {{ model.filterState$ | async }}
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-filter/todo-filter.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { TodoFilterComponent } from './todo-filter.component';
7 |
8 | describe('TodoFilterComponent', () => {
9 | let component: TodoFilterComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ TodoFilterComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(TodoFilterComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-filter/todo-filter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { AppModel } from '../store/app.model';
3 | import { FilterState } from '../filter-state.enum';
4 |
5 | @Component({
6 | selector: 'app-todo-filter',
7 | templateUrl: './todo-filter.component.html',
8 | styleUrls: ['./todo-filter.component.css']
9 | })
10 | export class TodoFilterComponent implements OnInit {
11 |
12 | constructor(private model: AppModel) { }
13 |
14 | ngOnInit() {
15 | }
16 |
17 | setFilterState(filterState: FilterState) {
18 | this.model.setFilter(filterState);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-list/todo-list.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week3/1/ngrxTodoApp/src/app/todo-list/todo-list.component.css
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-list/todo-list.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{todo.text}}
4 | Toggle checked
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-list/todo-list.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { TodoListComponent } from './todo-list.component';
7 |
8 | describe('TodoListComponent', () => {
9 | let component: TodoListComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ TodoListComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(TodoListComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo-list/todo-list.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { AppModel } from '../store/app.model';
3 | import { Observable } from 'rxjs/Observable';
4 | import { Todo } from '../todo.model';
5 |
6 | @Component({
7 | selector: 'app-todo-list',
8 | templateUrl: './todo-list.component.html',
9 | styleUrls: ['./todo-list.component.css']
10 | })
11 | export class TodoListComponent implements OnInit {
12 | todos$: Observable;
13 |
14 | constructor(private appModel: AppModel) {
15 | this.todos$ = appModel.todos$;
16 | }
17 |
18 | ngOnInit() {
19 | }
20 |
21 | toggleTodo(todo: Todo) {
22 | this.appModel.toggleCompleted(todo);
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/app/todo.model.ts:
--------------------------------------------------------------------------------
1 | let lastTodoId = 0;
2 |
3 | export class Todo {
4 | id: number;
5 | checked: boolean = false;
6 |
7 | constructor(private text: string) {
8 | this.id = ++lastTodoId;
9 | }
10 |
11 | };
12 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week3/1/ngrxTodoApp/src/assets/.gitkeep
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/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 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackBulgaria/Angular-2/c584709e30b08e9800e8629242e96672b60f7226/week3/1/ngrxTodoApp/src/favicon.ico
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NgrxTodoApp
6 |
7 |
8 |
9 |
10 |
11 |
12 | Loading...
13 |
14 |
15 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 | import { enableProdMode } from '@angular/core';
3 | import { environment } from './environments/environment';
4 | import { AppModule } from './app/app.module';
5 |
6 | if (environment.production) {
7 | enableProdMode();
8 | }
9 |
10 | platformBrowserDynamic().bootstrapModule(AppModule);
11 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | // This file includes polyfills needed by Angular and is loaded before the app.
2 | // You can add your own extra polyfills to this file.
3 | import 'core-js/es6/symbol';
4 | import 'core-js/es6/object';
5 | import 'core-js/es6/function';
6 | import 'core-js/es6/parse-int';
7 | import 'core-js/es6/parse-float';
8 | import 'core-js/es6/number';
9 | import 'core-js/es6/math';
10 | import 'core-js/es6/string';
11 | import 'core-js/es6/date';
12 | import 'core-js/es6/array';
13 | import 'core-js/es6/regexp';
14 | import 'core-js/es6/map';
15 | import 'core-js/es6/set';
16 | import 'core-js/es6/reflect';
17 |
18 | import 'core-js/es7/reflect';
19 | import 'zone.js/dist/zone';
20 |
21 | // If you need to support the browsers/features below, uncomment the import
22 | // and run `npm install import-name-here';
23 | // Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
24 |
25 | // Needed for: IE9
26 | // import 'classlist.js';
27 |
28 | // Animations
29 | // Needed for: All but Chrome and Firefox, Not supported in IE9
30 | // import 'web-animations-js';
31 |
32 | // Date, currency, decimal and percent pipes
33 | // Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
34 | // import 'intl';
35 |
36 | // NgClass on SVG elements
37 | // Needed for: IE10, IE11
38 | // import 'classlist.js';
39 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare var __karma__: any;
17 | declare var require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "",
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "lib": ["es6", "dom"],
8 | "mapRoot": "./",
9 | "module": "es6",
10 | "moduleResolution": "node",
11 | "outDir": "../dist/out-tsc",
12 | "sourceMap": true,
13 | "target": "es5",
14 | "typeRoots": [
15 | "../node_modules/@types"
16 | ]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/week3/1/ngrxTodoApp/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": false,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": false,
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/week3/2/README.md:
--------------------------------------------------------------------------------
1 | # Week 3.2
2 |
3 | ### Lecture
4 |
5 | ### Tasks:
6 |
7 | (Use the pager and grid from [here](https://github.com/HackBulgaria/Angular-2/tree/master/week2/1/tasks/src/app/directives). Use ContentChild and ViewChild to solve the tasks bellow)
8 |
9 | 1. Modify the grid component so it can present a custom header and footer that the user provided.
10 | 2. Modify the grid component and the pager to be able to use a custom template provided by the user and remove the default one. This will allow the user to control how the data is displayed.
11 | 3. Create search input that will filter the results showin in the grid dynamically. Use ```Observable.fromEvent(nativeElement, 'keyup').``` Don't forget to throttle the events. (Use [ElementRef](https://angular.io/docs/js/latest/api/core/index/ElementRef-class.html) to get the input element)
12 | 4. Modify the app to use redux (ngrx)
13 | 5. Use ngrx/effects to dispatch an action that will fetch the data from this [API](https://jsonplaceholder.typicode.com/), put it into the store and show it to the user.
--------------------------------------------------------------------------------
/week4/1/README.md:
--------------------------------------------------------------------------------
1 | # Week 4.1
2 |
3 | ### Lecture
4 | [click here](https://speakerdeck.com/iliaidakiev/7-forms-and-simple-validations)
5 |
6 | ### Tasks
7 |
8 | * Try using ngrx/store to export all your state and ngrx/effects for the (fake) server calls.
9 | * Use [ng-bootstrap](https://ng-bootstrap.github.io/#/home) to create the dialogs.
10 | * Create a [core module](https://angular.io/docs/ts/latest/guide/style-guide.html#!#04-11) that will contain all the single use components.
11 | * Consider using [combineReducer](https://github.com/ngrx/ngrx.github.io/blob/master/store/api/combine_reducers.md) to separate the different stores (auth store that will contain the loggedUser and todo store).
12 |
13 | 1. Create a reactive signup form for our todoApp from last time. We are going to need the first name, last name, email, password and a confirmation password field, address, city, post code (create a form group for address, city, post code). If the form is submitted and there are any errors in the form display an error message.
14 |
15 | 2. Create a fake auth service that will receive the input data from the form and simulate an ajax call (use the [localStorage](https://developer.mozilla.org/en/docs/Web/API/Window/localStorage) to save the registered users). After a few seconds return a response with { success: true } if the user is registered successfuly and { success: false } otherwise (if the email is already registered).
16 |
17 | 3. Create a login popup using the template driven approach. If the form is invalid and submitted show an error message.
18 |
19 | 4. Create an async login method on the auth service and check if the user exists and if so check if the passwords are matching. Return a proper response message and if the user is logged in successfully show the todoApp.
20 |
21 |
--------------------------------------------------------------------------------
/week4/2/README.md:
--------------------------------------------------------------------------------
1 | # Week 4.2
2 |
3 | ### Lecture
4 | [Click here](https://speakerdeck.com/iliaidakiev/8-custom-validations-controls-and-multi-providers)
5 | ### Tasks
6 | 1. Finish the tasks from last time
7 | 2. Create a custom password validation for the registration form. Password should contain 1 specail symbol (*, _, &).
8 | 3. Create a custom async model driven validation to check if the provided email in the registration form is not already registered.
9 | 4. Create a custom async template driven validation to check if the provided email in the login is registered.
10 | 5. Create a custom clock form control that will be used for setting the time of the todo.
11 |
--------------------------------------------------------------------------------
/week5/1/README.md:
--------------------------------------------------------------------------------
1 | # Week 5.1
2 |
3 | ### Lecture
4 | [Click here](https://speakerdeck.com/iliaidakiev/9-routing-and-navigation)
5 | ### Tasks
6 |
7 | 1. Use the application from last time and create a view where all the registered users are listed.
8 | 2. Create a UserEditComponent where the users can be edited (use a route param :id, get the user id using activatedRoute snapshot and get the user from the store)
9 | 3. Create a default 404 component that will handle not found routes.
10 | 3. Separate the user components into a different module - user.module. Create child routes for the components and use LazyLoading to load the module when the user clicks on the navigation link.
11 | 4. Use the preload strategies to preload the users module after the application is bootstrapped.
--------------------------------------------------------------------------------
/week5/2/README.md:
--------------------------------------------------------------------------------
1 | # Week 5.2
2 |
3 | ### Lecture
4 | [Click here](https://speakerdeck.com/iliaidakiev/10-routing-and-navigation-2)
5 |
6 | ### Tasks
7 |
8 | 1. Create a pipe called time that gets applied to a string that represents time (e.g. 16:45) and takes an optional number argument - format ( 12, 24 ). Depending on the format the pipe will convert the time (e.g. 16:45 | time: 12 -> 4:45 pm) and make this as a setting for our todo application.
9 | 2. Create a CanDeactivate guard that checks if there is any data written on the add todo form when the user is trying to navigate elsewhere. If there is show a confirmation popup. If the user clicks 'yes' proceed with the CanDeactivate procedure if 'no' do nothing. Use a named outlet to show the popup.
--------------------------------------------------------------------------------