├── .vscode
└── settings.json
├── README.md
├── angular.json
├── package.json
└── src
├── app
├── app.component.css
├── app.component.html
├── app.component.ts
├── app.module.ts
├── todos
│ ├── todo.service.ts
│ ├── todo1.component.html
│ ├── todo1.component.ts
│ ├── todo2.component.html
│ └── todo2.component.ts
└── users
│ └── user.service.ts
├── index.html
├── main.ts
├── polyfills.ts
└── styles.css
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // "editor.theme": "vs-dark",
3 | /**
4 | * Render vertical lines at the specified columns.
5 | * Defaults to empty array.
6 | */
7 | // "editor.rulers": [],
8 | /**
9 | * A string containing the word separators used when doing word navigation.
10 | * Defaults to `~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?
11 | */
12 | // "editor.wordSeparators": "`~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?",
13 | /**
14 | * Enable Linux primary clipboard.
15 | * Defaults to true.
16 | */
17 | // "editor.selectionClipboard": true,
18 | /**
19 | * Control the rendering of line numbers.
20 | * If it is a function, it will be invoked when rendering a line number and the return value will be rendered.
21 | * Otherwise, if it is a truey, line numbers will be rendered normally (equivalent of using an identity function).
22 | * Otherwise, line numbers will not be rendered.
23 | * Defaults to true.
24 | */
25 | // "editor.lineNumbers": "on",
26 | /**
27 | * Should the corresponding line be selected when clicking on the line number?
28 | * Defaults to true.
29 | */
30 | // "editor.selectOnLineNumbers": true,
31 | /**
32 | * Control the width of line numbers, by reserving horizontal space for rendering at least an amount of digits.
33 | * Defaults to 5.
34 | */
35 | // "editor.lineNumbersMinChars": 5,
36 | /**
37 | * Enable the rendering of the glyph margin.
38 | * Defaults to true in vscode and to false in monaco-editor.
39 | */
40 | // "editor.glyphMargin": true,
41 | /**
42 | * The width reserved for line decorations (in px).
43 | * Line decorations are placed between line numbers and the editor content.
44 | * You can pass in a string in the format floating point followed by "ch". e.g. 1.3ch.
45 | * Defaults to 10.
46 | */
47 | // "editor.lineDecorationsWidth": 10,
48 | /**
49 | * When revealing the cursor, a virtual padding (px) is added to the cursor, turning it into a rectangle.
50 | * This virtual padding ensures that the cursor gets revealed before hitting the edge of the viewport.
51 | * Defaults to 30 (px).
52 | */
53 | // "editor.revealHorizontalRightPadding": 30,
54 | /**
55 | * Render the editor selection with rounded borders.
56 | * Defaults to true.
57 | */
58 | // "editor.roundedSelection": true,
59 | /**
60 | * Control the behavior and rendering of the minimap.
61 | */
62 | // "editor.minimap": {
63 | // "enabled": false
64 | // },
65 | /**
66 | * Display overflow widgets as `fixed`.
67 | * Defaults to `false`.
68 | */
69 | // "editor.fixedOverflowWidgets": false,
70 | /**
71 | * The number of vertical lanes the overview ruler should render.
72 | * Defaults to 2.
73 | */
74 | // "editor.overviewRulerLanes": 2,
75 | /**
76 | * Controls if a border should be drawn around the overview ruler.
77 | * Defaults to `true`.
78 | */
79 | // "editor.overviewRulerBorder": true,
80 | /**
81 | * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'.
82 | * Defaults to 'blink'.
83 | */
84 | // "editor.cursorBlinking": "blink",
85 | /**
86 | * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl.
87 | * Defaults to false.
88 | */
89 | // "editor.mouseWheelZoom": false,
90 | /**
91 | * Control the cursor style, either 'block' or 'line'.
92 | * Defaults to 'line'.
93 | */
94 | // "editor.cursorStyle": "line",
95 | /**
96 | * Control the width of the cursor when cursorStyle is set to 'line'
97 | */
98 | // "editor.cursorWidth": 1,
99 | /**
100 | * Enable font ligatures.
101 | * Defaults to false.
102 | */
103 | // "editor.fontLigatures": false,
104 | /**
105 | * Disable the use of `will-change` for the editor margin and lines layers.
106 | * The usage of `will-change` acts as a hint for browsers to create an extra layer.
107 | * Defaults to false.
108 | */
109 | // "editor.disableLayerHinting": false,
110 | /**
111 | * Disable the optimizations for monospace fonts.
112 | * Defaults to false.
113 | */
114 | // "editor.disableMonospaceOptimizations": false,
115 | /**
116 | * Should the cursor be hidden in the overview ruler.
117 | * Defaults to false.
118 | */
119 | // "editor.hideCursorInOverviewRuler": false,
120 | /**
121 | * Enable that scrolling can go one screen size after the last line.
122 | * Defaults to true.
123 | */
124 | // "editor.scrollBeyondLastLine": true,
125 | /**
126 | * Enable that scrolling can go beyond the last column by a number of columns.
127 | * Defaults to 5.
128 | */
129 | // "editor.scrollBeyondLastColumn": 5,
130 | /**
131 | * Enable that the editor animates scrolling to a position.
132 | * Defaults to false.
133 | */
134 | // "editor.smoothScrolling": false,
135 | /**
136 | * Enable that the editor will install an interval to check if its container dom node size has changed.
137 | * Enabling this might have a severe performance impact.
138 | * Defaults to false.
139 | */
140 | // "editor.automaticLayout": false,
141 | /**
142 | * Control the wrapping of the editor.
143 | * When `wordWrap` = "off", the lines will never wrap.
144 | * When `wordWrap` = "on", the lines will wrap at the viewport width.
145 | * When `wordWrap` = "wordWrapColumn", the lines will wrap at `wordWrapColumn`.
146 | * When `wordWrap` = "bounded", the lines will wrap at min(viewport width, wordWrapColumn).
147 | * Defaults to "off".
148 | */
149 | // "editor.wordWrap": "on",
150 | /**
151 | * Control the wrapping of the editor.
152 | * When `wordWrap` = "off", the lines will never wrap.
153 | * When `wordWrap` = "on", the lines will wrap at the viewport width.
154 | * When `wordWrap` = "wordWrapColumn", the lines will wrap at `wordWrapColumn`.
155 | * When `wordWrap` = "bounded", the lines will wrap at min(viewport width, wordWrapColumn).
156 | * Defaults to 80.
157 | */
158 | // "editor.wordWrapColumn": 0,
159 | /**
160 | * Force word wrapping when the text appears to be of a minified/generated file.
161 | * Defaults to true.
162 | */
163 | // "editor.wordWrapMinified": true,
164 | /**
165 | * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'.
166 | * Defaults to 'same' in vscode and to 'none' in monaco-editor.
167 | */
168 | // "editor.wrappingIndent": "same",
169 | /**
170 | * Configure word wrapping characters. A break will be introduced before these characters.
171 | * Defaults to '{([+'.
172 | */
173 | // "editor.wordWrapBreakBeforeCharacters": "{([+",
174 | /**
175 | * Configure word wrapping characters. A break will be introduced after these characters.
176 | * Defaults to ' \t})]?|&,;'.
177 | */
178 | // "editor.wordWrapBreakAfterCharacters": " \t})]?|&,;",
179 | /**
180 | * Configure word wrapping characters. A break will be introduced after these characters only if no `wordWrapBreakBeforeCharacters` or `wordWrapBreakAfterCharacters` were found.
181 | * Defaults to '.'.
182 | */
183 | // "editor.wordWrapBreakObtrusiveCharacters": ".",
184 | /**
185 | * Performance guard: Stop rendering a line after x characters.
186 | * Defaults to 10000.
187 | * Use -1 to never stop rendering
188 | */
189 | // "editor.stopRenderingLineAfter": -1,
190 | /**
191 | * Configure the editor's hover.
192 | */
193 | // "editor.hover": {
194 | /**
195 | * Enable the hover.
196 | * Defaults to true.
197 | */
198 | // "enabled": true,
199 | /**
200 | * Delay for showing the hover.
201 | * Defaults to 300.
202 | */
203 | // "delay": 300,
204 | /**
205 | * Is the hover sticky such that it can be clicked and its contents selected?
206 | * Defaults to true.
207 | */
208 | // "sticky": true
209 | // },
210 | /**
211 | * Enable detecting links and making them clickable.
212 | * Defaults to true.
213 | */
214 | // "editor.links": true,
215 | /**
216 | * Enable inline color decorators and color picker rendering.
217 | */
218 | // "editor.colorDecorators": true,
219 | /**
220 | * Enable custom contextmenu.
221 | * Defaults to true.
222 | */
223 | // "editor.contextmenu": true,
224 | /**
225 | * A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.
226 | * Defaults to 1.
227 | */
228 | // "editor.mouseWheelScrollSensitivity": 1,
229 | /**
230 | * The modifier to be used to add multiple cursors with the mouse.
231 | * Defaults to 'alt'
232 | */
233 | // "editor.multiCursorModifier": "alt",
234 | /**
235 | * Merge overlapping selections.
236 | * Defaults to true
237 | */
238 | // "editor.multiCursorMergeOverlapping": true,
239 | /**
240 | * Configure the editor's accessibility support.
241 | * Defaults to 'auto'. It is best to leave this to 'auto'.
242 | */
243 | // "editor.accessibilitySupport": "auto",
244 | /**
245 | * Suggest options.
246 | */
247 | // "editor.suggest": {
248 | /**
249 | * Enable graceful matching. Defaults to true.
250 | */
251 | // "filterGraceful": true,
252 | /**
253 | * Prevent quick suggestions when a snippet is active. Defaults to true.
254 | */
255 | // "snippetsPreventQuickSuggestions": true
256 | // },
257 | /**
258 | * Enable quick suggestions (shadow suggestions)
259 | * Defaults to true.
260 | */
261 | // "editor.quickSuggestions": true,
262 | /**
263 | * Quick suggestions show delay (in ms)
264 | * Defaults to 500 (ms)
265 | */
266 | // "editor.quickSuggestionsDelay": 500,
267 | /**
268 | * Parameter hint options.
269 | */
270 | // "editor.parameterHints": true,
271 | /**
272 | * Render icons in suggestions box.
273 | * Defaults to true.
274 | */
275 | // "editor.iconsInSuggestions": true,
276 | /**
277 | * Options for auto closing brackets.
278 | * Defaults to language defined behavior.
279 | */
280 | // "editor.autoClosingBrackets": true,
281 | /**
282 | * Enable auto indentation adjustment.
283 | * Defaults to false.
284 | */
285 | // "editor.autoIndent": false,
286 | /**
287 | * Enable format on type.
288 | * Defaults to false.
289 | */
290 | // "editor.formatOnType": false,
291 | /**
292 | * Enable format on paste.
293 | * Defaults to false.
294 | */
295 | // "editor.formatOnPaste": false,
296 | /**
297 | * Controls if the editor should allow to move selections via drag and drop.
298 | * Defaults to false.
299 | */
300 | // "editor.dragAndDrop": false,
301 | /**
302 | * Enable the suggestion box to pop-up on trigger characters.
303 | * Defaults to true.
304 | */
305 | // "editor.suggestOnTriggerCharacters": true,
306 | /**
307 | * Accept suggestions on ENTER.
308 | * Defaults to 'on'.
309 | */
310 | // "editor.acceptSuggestionOnEnter": "on",
311 | /**
312 | * Accept suggestions on provider defined characters.
313 | * Defaults to true.
314 | */
315 | // "editor.acceptSuggestionOnCommitCharacter": true,
316 | /**
317 | * Enable snippet suggestions. Default to 'true'.
318 | */
319 | // "editor.snippetSuggestions": "top",
320 | /**
321 | * Copying without a selection copies the current line.
322 | */
323 | // "editor.emptySelectionClipboard": true,
324 | /**
325 | * Enable word based suggestions. Defaults to 'true'
326 | */
327 | // "editor.wordBasedSuggestions": true,
328 | /**
329 | * The history mode for suggestions.
330 | */
331 | // "editor.suggestSelection": "recentlyUsedByPrefix",
332 | /**
333 | * Enable selection highlight.
334 | * Defaults to true.
335 | */
336 | // "editor.selectionHighlight": true,
337 | /**
338 | * Enable semantic occurrences highlight.
339 | * Defaults to true.
340 | */
341 | // "editor.occurrencesHighlight": true,
342 | /**
343 | * Show code lens
344 | * Defaults to true.
345 | */
346 | // "editor.codeLens": true,
347 | /**
348 | * Control the behavior and rendering of the code action lightbulb.
349 | */
350 | // "editor.lightbulb": {
351 | // "enabled": true
352 | // },
353 | /**
354 | * Enable code folding
355 | * Defaults to true.
356 | */
357 | // "editor.folding": true,
358 | /**
359 | * Selects the folding strategy. 'auto' uses the strategies contributed for the current document, 'indentation' uses the indentation based folding strategy.
360 | * Defaults to 'auto'.
361 | */
362 | // "editor.foldingStrategy": "auto",
363 | /**
364 | * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter.
365 | * Defaults to 'mouseover'.
366 | */
367 | // "editor.showFoldingControls": "mouseover",
368 | /**
369 | * Enable highlighting of matching brackets.
370 | * Defaults to true.
371 | */
372 | // "editor.matchBrackets": true,
373 | /**
374 | * Enable rendering of whitespace.
375 | * Defaults to none.
376 | */
377 | // "editor.renderWhitespace": "none",
378 | /**
379 | * Enable rendering of control characters.
380 | * Defaults to false.
381 | */
382 | // "editor.renderControlCharacters": false,
383 | /**
384 | * Enable rendering of indent guides.
385 | * Defaults to true.
386 | */
387 | // "editor.renderIndentGuides": true,
388 | /**
389 | * Enable highlighting of the active indent guide.
390 | * Defaults to true.
391 | */
392 | // "editor.highlightActiveIndentGuide": true,
393 | /**
394 | * Enable rendering of current line highlight.
395 | * Defaults to all.
396 | */
397 | // "editor.renderLineHighlight": "all",
398 | /**
399 | * Inserting and deleting whitespace follows tab stops.
400 | */
401 | // "editor.useTabStops": true,
402 | /**
403 | * The font family
404 | */
405 | // "editor.fontFamily": "Fira Code, Menlo, Monaco, 'Courier New', monospace",
406 | /**
407 | * The font weight
408 | */
409 | // "editor.fontWeight": "normal",
410 | /**
411 | * The font size
412 | */
413 | // "editor.fontSize": 12,
414 | /**
415 | * The line height
416 | */
417 | // "editor.lineHeight": 18,
418 | /**
419 | * The letter spacing
420 | */
421 | // "editor.letterSpacing": 0,
422 | /**
423 | * Controls fading out of unused variables.
424 | */
425 | // "editor.showUnused": true
426 | }
427 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-rxjs-child-deborahk
2 |
3 | Demonstrates several techniques for working with RxJS in child components.
4 |
5 | - Passing the Observable as an input property and using onPush change detection.
6 | - Passing the value of the Observable as an input property and using onPush change detection.
7 |
8 | [Edit on StackBlitz ⚡️](https://stackblitz.com/edit/angular-rxjs-child-deborahk)
9 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "demo": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "app",
11 | "schematics": {},
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "outputPath": "dist/demo",
17 | "index": "src/index.html",
18 | "main": "src/main.ts",
19 | "polyfills": "src/polyfills.ts",
20 | "tsConfig": "src/tsconfig.app.json",
21 | "assets": [
22 | "src/favicon.ico",
23 | "src/assets"
24 | ],
25 | "styles": [
26 | "src/styles.css"
27 | ],
28 | "scripts": []
29 | },
30 | "configurations": {
31 | "production": {
32 | "fileReplacements": [
33 | {
34 | "replace": "src/environments/environment.ts",
35 | "with": "src/environments/environment.prod.ts"
36 | }
37 | ],
38 | "optimization": true,
39 | "outputHashing": "all",
40 | "sourceMap": false,
41 | "extractCss": true,
42 | "namedChunks": false,
43 | "aot": true,
44 | "extractLicenses": true,
45 | "vendorChunk": false,
46 | "buildOptimizer": true
47 | }
48 | }
49 | },
50 | "serve": {
51 | "builder": "@angular-devkit/build-angular:dev-server",
52 | "options": {
53 | "browserTarget": "demo:build"
54 | },
55 | "configurations": {
56 | "production": {
57 | "browserTarget": "demo:build:production"
58 | }
59 | }
60 | },
61 | "extract-i18n": {
62 | "builder": "@angular-devkit/build-angular:extract-i18n",
63 | "options": {
64 | "browserTarget": "demo:build"
65 | }
66 | },
67 | "test": {
68 | "builder": "@angular-devkit/build-angular:karma",
69 | "options": {
70 | "main": "src/test.ts",
71 | "polyfills": "src/polyfills.ts",
72 | "tsConfig": "src/tsconfig.spec.json",
73 | "karmaConfig": "src/karma.conf.js",
74 | "styles": [
75 | "styles.css"
76 | ],
77 | "scripts": [],
78 | "assets": [
79 | "src/favicon.ico",
80 | "src/assets"
81 | ]
82 | }
83 | },
84 | "lint": {
85 | "builder": "@angular-devkit/build-angular:tslint",
86 | "options": {
87 | "tsConfig": [
88 | "src/tsconfig.app.json",
89 | "src/tsconfig.spec.json"
90 | ],
91 | "exclude": [
92 | "**/node_modules/**"
93 | ]
94 | }
95 | }
96 | }
97 | }
98 | },
99 | "defaultProject": "demo"
100 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular",
3 | "version": "0.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@angular/common": "^8.0.0",
7 | "@angular/compiler": "^8.0.0",
8 | "@angular/core": "^8.0.0",
9 | "@angular/forms": "^8.0.0",
10 | "@angular/platform-browser": "^8.0.0",
11 | "@angular/platform-browser-dynamic": "^8.0.0",
12 | "@angular/router": "^8.0.0",
13 | "core-js": "2",
14 | "rxjs": "^6.5.2",
15 | "zone.js": "^0.9.1"
16 | },
17 | "scripts": {
18 | "ng": "ng",
19 | "start": "ng serve",
20 | "build": "ng build",
21 | "test": "ng test",
22 | "lint": "ng lint",
23 | "e2e": "ng e2e"
24 | },
25 | "devDependencies": {
26 | "@angular-devkit/build-angular": "~0.10.0",
27 | "@angular/cli": "~7.0.2",
28 | "@angular/compiler-cli": "~7.0.0",
29 | "@angular/language-service": "~7.0.0",
30 | "@types/node": "~8.9.4",
31 | "@types/jasmine": "~2.8.8",
32 | "@types/jasminewd2": "~2.0.3",
33 | "codelyzer": "~4.5.0",
34 | "jasmine-core": "~2.99.1",
35 | "jasmine-spec-reporter": "~4.2.1",
36 | "karma": "~3.0.0",
37 | "karma-chrome-launcher": "~2.2.0",
38 | "karma-coverage-istanbul-reporter": "~2.0.1",
39 | "karma-jasmine": "~1.1.2",
40 | "karma-jasmine-html-reporter": "^0.2.2",
41 | "protractor": "~5.4.0",
42 | "ts-node": "~7.0.0",
43 | "tslint": "~5.11.0",
44 | "typescript": "~3.1.1"
45 | }
46 | }
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | p {
2 | font-family: Lato;
3 | }
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 | import { throwError, of, forkJoin, combineLatest, BehaviorSubject } from "rxjs";
3 | import { catchError, tap, map, switchMap, filter, first } from "rxjs/operators";
4 |
5 | import { UserService } from "./users/user.service";
6 | import { TodoService } from "./todos/todo.service";
7 |
8 | @Component({
9 | selector: "my-app",
10 | templateUrl: "./app.component.html",
11 | styleUrls: ["./app.component.css"]
12 | })
13 | export class AppComponent {
14 | // All of the users
15 | users$ = this.userService.users$;
16 |
17 | // TODOs for the user
18 | todos$ = this.todoService.todosForUser$;
19 |
20 | // Currently selected user
21 | selectedUserId: number;
22 |
23 | constructor(
24 | private userService: UserService,
25 | private todoService: TodoService
26 | ) {}
27 |
28 | onSelected(userId: number): void {
29 | this.selectedUserId = userId;
30 | this.userService.selectedUserChanged(userId);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { BrowserModule } from "@angular/platform-browser";
3 | import { FormsModule } from "@angular/forms";
4 | import { HttpClientModule } from "@angular/common/http";
5 |
6 | import { AppComponent } from "./app.component";
7 | import { Todo1Component } from "./todos/todo1.component";
8 | import { Todo2Component } from "./todos/todo2.component";
9 |
10 | @NgModule({
11 | imports: [BrowserModule, FormsModule, HttpClientModule],
12 | declarations: [AppComponent, Todo1Component, Todo2Component],
13 | bootstrap: [AppComponent]
14 | })
15 | export class AppModule {}
16 |
--------------------------------------------------------------------------------
/src/app/todos/todo.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from "@angular/core";
2 | import { HttpClient } from "@angular/common/http";
3 |
4 | import { throwError, forkJoin } from "rxjs";
5 | import { filter, switchMap, tap, shareReplay } from "rxjs/operators";
6 |
7 | import { UserService } from "../users/user.service";
8 |
9 | @Injectable({
10 | providedIn: "root"
11 | })
12 | export class TodoService {
13 | todoUrl = "https://jsonplaceholder.typicode.com/todos";
14 |
15 | // Watches for changes to the selected user
16 | // Emits an item and reexecutes the pipeline every time a different user is selected
17 | // As part of the pipeline, it retrieves the todos for the user using the emitted userId as an argument
18 | todosForUser$ = this.userService.userSelectedAction$.pipe(
19 | // Handle the case of no selection
20 | filter(userId => Boolean(userId)),
21 | switchMap(userId =>
22 | this.http.get(`${this.todoUrl}?userId=${userId}&completed=true`)
23 | ),
24 | shareReplay(1)
25 | );
26 |
27 | constructor(private http: HttpClient, private userService: UserService) {}
28 | }
29 |
30 | export interface ToDo {
31 | userId: number;
32 | id: number;
33 | title: string;
34 | completed: boolean;
35 | }
36 |
--------------------------------------------------------------------------------
/src/app/todos/todo1.component.html:
--------------------------------------------------------------------------------
1 | Child 1: Passing Observable
2 |
3 |
4 |
5 | User Id |
6 | Title |
7 | Completed? |
8 |
9 |
10 |
11 |
12 | {{ todo.userId }} |
13 | {{ todo.title }} |
14 | {{ todo.completed }} |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/app/todos/todo1.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
2 |
3 | import { Observable } from 'rxjs';
4 |
5 | import { ToDo } from './todo.service';
6 |
7 | @Component({
8 | selector: 'appTodo1',
9 | templateUrl: './todo1.component.html',
10 | changeDetection: ChangeDetectionStrategy.OnPush
11 | })
12 | export class Todo1Component {
13 | @Input() todos$: Observable;
14 | }
15 |
--------------------------------------------------------------------------------
/src/app/todos/todo2.component.html:
--------------------------------------------------------------------------------
1 | Child 2: Passing Emitted Value
2 |
3 |
4 |
5 | User Id |
6 | Title |
7 | Completed? |
8 |
9 |
10 |
11 |
12 | {{ todo.userId }} |
13 | {{ todo.title }} |
14 | {{ todo.completed }} |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/app/todos/todo2.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, ChangeDetectionStrategy } from "@angular/core";
2 |
3 | import { Observable } from "rxjs";
4 |
5 | import { ToDo } from "./todo.service";
6 |
7 | @Component({
8 | selector: "appTodo2",
9 | templateUrl: "./todo2.component.html",
10 | changeDetection: ChangeDetectionStrategy.OnPush
11 | })
12 | export class Todo2Component {
13 | @Input() todos: ToDo[];
14 | }
15 |
--------------------------------------------------------------------------------
/src/app/users/user.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from "@angular/core";
2 | import { HttpClient } from "@angular/common/http";
3 |
4 | import { BehaviorSubject, throwError, forkJoin } from "rxjs";
5 | import { catchError, filter, switchMap, map } from "rxjs/operators";
6 |
7 | @Injectable({
8 | providedIn: "root"
9 | })
10 | export class UserService {
11 | userUrl = "https://jsonplaceholder.typicode.com/users";
12 |
13 | // Action stream (one parameter)
14 | private userSelectedSubject = new BehaviorSubject(0);
15 | userSelectedAction$ = this.userSelectedSubject.asObservable();
16 |
17 | // All Users
18 | users$ = this.http.get(this.userUrl)
19 | .pipe(
20 | // tap(data => console.log('users', JSON.stringify(data))),
21 | catchError(err => throwError("Error occurred"))
22 | );
23 |
24 | constructor(private http: HttpClient) {}
25 |
26 | selectedUserChanged(userId: number): void {
27 | this.userSelectedSubject.next(userId);
28 | }
29 | }
30 |
31 | export interface User {
32 | id: number;
33 | name: string;
34 | username: string;
35 | email: string;
36 | website: string;
37 | }
38 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 | loading
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import './polyfills';
2 |
3 | import { enableProdMode } from '@angular/core';
4 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
5 |
6 | import { AppModule } from './app/app.module';
7 |
8 | platformBrowserDynamic().bootstrapModule(AppModule).then(ref => {
9 | // Ensure Angular destroys itself on hot reloads.
10 | if (window['ngRef']) {
11 | window['ngRef'].destroy();
12 | }
13 | window['ngRef'] = ref;
14 |
15 | // Otherwise, log the boot error
16 | }).catch(err => console.error(err));
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/set';
35 |
36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
37 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
38 |
39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */
40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
41 |
42 |
43 | /** Evergreen browsers require these. **/
44 | import 'core-js/es6/reflect';
45 | import 'core-js/es7/reflect';
46 |
47 |
48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone'; // Included with Angular CLI.
57 |
58 |
59 | /***************************************************************************************************
60 | * APPLICATION IMPORTS
61 | */
62 |
63 | /**
64 | * Date, currency, decimal and percent pipes.
65 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
66 | */
67 | // import 'intl'; // Run `npm install --save intl`.
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | /* Add application styles & imports to this file! */
--------------------------------------------------------------------------------