├── README.md
├── angular.json
├── package.json
├── src
├── app
│ ├── alternateParentChild
│ │ ├── alternate-child
│ │ │ ├── alternate-child.component.css
│ │ │ ├── alternate-child.component.html
│ │ │ └── alternate-child.component.ts
│ │ └── alternate-parent
│ │ │ ├── alternate-parent.component.css
│ │ │ ├── alternate-parent.component.html
│ │ │ └── alternate-parent.component.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── hello.component.ts
│ ├── multiDirectionData
│ │ ├── multi-child
│ │ │ ├── multi-child.component.css
│ │ │ ├── multi-child.component.html
│ │ │ └── multi-child.component.ts
│ │ └── multi-parent
│ │ │ ├── multi-parent.component.css
│ │ │ ├── multi-parent.component.html
│ │ │ └── multi-parent.component.ts
│ ├── parentToChild
│ │ ├── child
│ │ │ ├── child.component.css
│ │ │ ├── child.component.html
│ │ │ └── child.component.ts
│ │ └── parent
│ │ │ ├── parent.component.css
│ │ │ ├── parent.component.html
│ │ │ └── parent.component.ts
│ ├── siblings
│ │ ├── child-one
│ │ │ ├── child-one.component.css
│ │ │ ├── child-one.component.html
│ │ │ └── child-one.component.ts
│ │ ├── child-two
│ │ │ ├── child-two.component.css
│ │ │ ├── child-two.component.html
│ │ │ └── child-two.component.ts
│ │ └── parent.directive.ts
│ └── unrelated
│ │ ├── activator
│ │ ├── activator.component.css
│ │ ├── activator.component.html
│ │ └── activator.component.ts
│ │ ├── toast.service.ts
│ │ └── toast
│ │ ├── toast.component.css
│ │ ├── toast.component.html
│ │ └── toast.component.ts
├── index.html
├── karma.conf.js
├── main.ts
├── polyfills.ts
├── styles.css
├── tsconfig.app.json
└── tsconfig.spec.json
└── tsconfig.json
/README.md:
--------------------------------------------------------------------------------
1 | # erxk-component-communication
2 |
3 | [Edit on StackBlitz ⚡️](https://stackblitz.com/edit/erxk-component-communication)
4 |
5 | ### Article
6 | https://medium.com/@erxk_verduin/angular-effective-component-patterns-f5f7f08e2072
7 |
8 | ### Getting Started
9 | ```
10 | git clone https://github.com/Everduin94/component-communication-patterns.git
11 | cd component-communication-patterns
12 | npm install
13 | ng serve --o
14 | ```
15 |
--------------------------------------------------------------------------------
/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.6.9",
14 | "rxjs": "6.5.2",
15 | "tslib": "^1.10.0",
16 | "zone.js": "0.9.1"
17 | },
18 | "scripts": {
19 | "ng": "ng",
20 | "start": "ng serve",
21 | "build": "ng build",
22 | "test": "ng test",
23 | "lint": "ng lint",
24 | "e2e": "ng e2e"
25 | },
26 | "devDependencies": {
27 | "@angular-devkit/build-angular": "~0.10.0",
28 | "@angular/cli": "~7.0.2",
29 | "@angular/compiler-cli": "~7.0.0",
30 | "@angular/language-service": "~7.0.0",
31 | "@types/node": "~8.9.4",
32 | "@types/jasmine": "~2.8.8",
33 | "@types/jasminewd2": "~2.0.3",
34 | "codelyzer": "~4.5.0",
35 | "jasmine-core": "~2.99.1",
36 | "jasmine-spec-reporter": "~4.2.1",
37 | "karma": "~3.0.0",
38 | "karma-chrome-launcher": "~2.2.0",
39 | "karma-coverage-istanbul-reporter": "~2.0.1",
40 | "karma-jasmine": "~1.1.2",
41 | "karma-jasmine-html-reporter": "^0.2.2",
42 | "protractor": "~5.4.0",
43 | "ts-node": "~7.0.0",
44 | "tslint": "~5.11.0",
45 | "typescript": "~3.1.1"
46 | }
47 | }
--------------------------------------------------------------------------------
/src/app/alternateParentChild/alternate-child/alternate-child.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Everduin94/component-communication-patterns/78ab62ae5c1c6868d87ca213c5e8cbdc345ff91a/src/app/alternateParentChild/alternate-child/alternate-child.component.css
--------------------------------------------------------------------------------
/src/app/alternateParentChild/alternate-child/alternate-child.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{getMessage(eventData.enabled)}}
3 |
--------------------------------------------------------------------------------
/src/app/alternateParentChild/alternate-child/alternate-child.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-alternate-child',
5 | templateUrl: './alternate-child.component.html',
6 | styleUrls: ['./alternate-child.component.css']
7 | })
8 | export class AlternateChildComponent implements OnInit {
9 |
10 | @Input('eventData') eventData;
11 |
12 | constructor() {}
13 |
14 | ngOnInit() {}
15 |
16 | getMessage(toggle) {
17 | if (toggle) return 'Agreed';
18 | else return 'Agree to terms by clicking';
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/src/app/alternateParentChild/alternate-parent/alternate-parent.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Everduin94/component-communication-patterns/78ab62ae5c1c6868d87ca213c5e8cbdc345ff91a/src/app/alternateParentChild/alternate-parent/alternate-parent.component.css
--------------------------------------------------------------------------------
/src/app/alternateParentChild/alternate-parent/alternate-parent.component.html:
--------------------------------------------------------------------------------
1 |
2 | Agree to the Terms of Service:
3 |
7 |
8 |
--------------------------------------------------------------------------------
/src/app/alternateParentChild/alternate-parent/alternate-parent.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { BehaviorSubject } from 'rxjs';
3 |
4 | @Component({
5 | selector: 'app-alternate-parent',
6 | templateUrl: './alternate-parent.component.html',
7 | styleUrls: ['./alternate-parent.component.css']
8 | })
9 | export class AlternateParentComponent implements OnInit {
10 |
11 | private data = new BehaviorSubject({
12 | enabled: false,
13 | toolTip: false
14 | });
15 | public eventStream$ = this.data.asObservable()
16 |
17 | constructor() { }
18 |
19 | ngOnInit() {}
20 |
21 | update(value, command) {
22 | let update = this.data.value;
23 | if (command === 'enabled') update.enabled = value;
24 | if (command === 'toolTip') update.toolTip = value;
25 | this.data.next(update);
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | p {
2 | font-family: Lato;
3 | }
4 |
5 | hr {
6 | margin: 10px;
7 | }
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'my-app',
5 | templateUrl: './app.component.html',
6 | styleUrls: [ './app.component.css' ]
7 | })
8 | export class AppComponent {
9 | name = 'Angular';
10 | }
11 |
--------------------------------------------------------------------------------
/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 |
5 | import { AppComponent } from './app.component';
6 | import { HelloComponent } from './hello.component';
7 |
8 | import { ChildOneComponent } from './siblings/child-one/child-one.component';
9 | import { ChildTwoComponent } from './siblings/child-two/child-two.component';
10 | import { ParentDirective } from './siblings/parent.directive';
11 | import { ToastComponent } from './unrelated/toast/toast.component';
12 | import { ParentComponent } from './parentToChild/parent/parent.component';
13 | import { ChildComponent } from './parentToChild/child/child.component';
14 | import { ActivatorComponent } from './unrelated/activator/activator.component';
15 |
16 | import { ToastService } from './unrelated/toast.service';
17 | import { MultiParentComponent } from './multiDirectionData/multi-parent/multi-parent.component';
18 | import { MultiChildComponent } from './multiDirectionData/multi-child/multi-child.component';
19 | import { AlternateParentComponent } from './alternateParentChild/alternate-parent/alternate-parent.component';
20 | import { AlternateChildComponent } from './alternateParentChild/alternate-child/alternate-child.component';
21 |
22 | @NgModule({
23 | imports: [ BrowserModule, FormsModule ],
24 | declarations: [ AppComponent, HelloComponent, ChildOneComponent, ChildTwoComponent, ParentDirective, ToastComponent, ParentComponent, ChildComponent, ActivatorComponent, MultiParentComponent, MultiChildComponent, AlternateParentComponent, AlternateChildComponent],
25 | bootstrap: [ AppComponent ],
26 | providers: [ToastService]
27 | })
28 | export class AppModule { }
29 |
--------------------------------------------------------------------------------
/src/app/hello.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'hello',
5 | template: `Hello {{name}}!
`,
6 | styles: [`h1 { font-family: Lato; }`]
7 | })
8 | export class HelloComponent {
9 | @Input() name: string;
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/multiDirectionData/multi-child/multi-child.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Everduin94/component-communication-patterns/78ab62ae5c1c6868d87ca213c5e8cbdc345ff91a/src/app/multiDirectionData/multi-child/multi-child.component.css
--------------------------------------------------------------------------------
/src/app/multiDirectionData/multi-child/multi-child.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{value}}
3 |
4 |
--------------------------------------------------------------------------------
/src/app/multiDirectionData/multi-child/multi-child.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core';
2 | import { BehaviorSubject, interval } from 'rxjs';
3 | import { tap, take } from 'rxjs/operators';
4 |
5 | @Component({
6 | selector: 'app-multi-child',
7 | templateUrl: './multi-child.component.html',
8 | styleUrls: ['./multi-child.component.css']
9 | })
10 | export class MultiChildComponent implements OnInit, OnDestroy {
11 |
12 | @Input('loadtime') loadtime;
13 | @Input('eventStream') eventStream$;
14 | state: BehaviorSubject = new BehaviorSubject('');
15 | // @Output('done') outputStream$ = this.state.asObservable();
16 | @Output('done') eventEmitter = new EventEmitter();
17 |
18 | constructor() { }
19 |
20 | ngOnInit() {
21 | this.state.subscribe(val => {
22 | this.eventEmitter.emit(val);
23 | });
24 | this.eventStream$ = this.eventStream$.pipe(
25 | tap(val => {
26 | if (val === 'Running') this.start();
27 | })
28 | )
29 | }
30 |
31 | start() {
32 | this.state.next('Loading...');
33 | setTimeout(val => {
34 | this.state.next('Complete!');
35 | }, this.loadtime);
36 | }
37 |
38 | ngOnDestroy() {
39 | this.state.unsubscribe();
40 | }
41 | }
--------------------------------------------------------------------------------
/src/app/multiDirectionData/multi-parent/multi-parent.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Everduin94/component-communication-patterns/78ab62ae5c1c6868d87ca213c5e8cbdc345ff91a/src/app/multiDirectionData/multi-parent/multi-parent.component.css
--------------------------------------------------------------------------------
/src/app/multiDirectionData/multi-parent/multi-parent.component.html:
--------------------------------------------------------------------------------
1 | {{state.value}}
2 |
3 |
7 |
11 |
--------------------------------------------------------------------------------
/src/app/multiDirectionData/multi-parent/multi-parent.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
2 | import { BehaviorSubject, combineLatest, fromEvent, Observable } from 'rxjs';
3 | import { map, mapTo, startWith } from 'rxjs/operators';
4 |
5 | @Component({
6 | selector: 'app-multi-parent',
7 | templateUrl: './multi-parent.component.html',
8 | styleUrls: ['./multi-parent.component.css']
9 | })
10 | export class MultiParentComponent implements OnInit {
11 |
12 | private counter = 0;
13 | private state = new BehaviorSubject('Off');
14 | public eventStream$: Observable = this.state.asObservable();
15 |
16 |
17 | constructor() { }
18 |
19 | ngOnInit() {}
20 |
21 | updateStatus(value) {
22 | if (value === 'Complete!') this.counter++;
23 | if (this.counter === 2) {
24 | this.state.next('Process Complete');
25 | this.counter = 0;
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/app/parentToChild/child/child.component.css:
--------------------------------------------------------------------------------
1 | div {
2 | margin: 10px;
3 | padding: 10px;
4 | background: dodgerblue;
5 | border-radius: 2px;
6 | border: 1px solid rgb(55, 137, 219);
7 | box-shadow: 6px 6px 2px 1px rgba(30, 144, 255, .2);
8 | text-align: center;
9 | color: #FFFFFF;
10 | }
--------------------------------------------------------------------------------
/src/app/parentToChild/child/child.component.html:
--------------------------------------------------------------------------------
1 |
2 | {{getMessage(toggle.enabled)}}
3 |
--------------------------------------------------------------------------------
/src/app/parentToChild/child/child.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input, AfterViewInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-child',
5 | templateUrl: './child.component.html',
6 | styleUrls: ['./child.component.css']
7 | })
8 | export class ChildComponent implements OnInit {
9 |
10 | @Input('eventStream') eventStream$;
11 |
12 | constructor() {}
13 |
14 | ngOnInit() {}
15 |
16 | getMessage(toggle) {
17 | if (toggle) return 'Agreed';
18 | else return 'Agree to terms by clicking';
19 | }
20 | }
--------------------------------------------------------------------------------
/src/app/parentToChild/parent/parent.component.css:
--------------------------------------------------------------------------------
1 | span {
2 | margin-left: 10px;
3 |
4 | font-weight: 600;
5 | }
--------------------------------------------------------------------------------
/src/app/parentToChild/parent/parent.component.html:
--------------------------------------------------------------------------------
1 | Agree to the Terms of Service:
2 |
6 |
--------------------------------------------------------------------------------
/src/app/parentToChild/parent/parent.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { BehaviorSubject } from 'rxjs';
3 | import { map } from 'rxjs/operators';
4 |
5 | @Component({
6 | selector: 'app-parent',
7 | templateUrl: './parent.component.html',
8 | styleUrls: ['./parent.component.css']
9 | })
10 | export class ParentComponent implements OnInit {
11 |
12 | private data = new BehaviorSubject({
13 | enabled: false,
14 | toolTip: false
15 | });
16 | public eventStream$ = this.data.asObservable()
17 |
18 | constructor() { }
19 |
20 | ngOnInit() {}
21 |
22 | update(value, command) {
23 | let update = this.data.value;
24 | if (command === 'enabled') update.enabled = value;
25 | if (command === 'toolTip') update.toolTip = value;
26 | this.data.next(update);
27 | }
28 | }
--------------------------------------------------------------------------------
/src/app/siblings/child-one/child-one.component.css:
--------------------------------------------------------------------------------
1 | div {
2 | margin: 2%;
3 | width: 98%;
4 | height: 100px;
5 | text-align: center;
6 | color: #FFFFFF;
7 | line-height: 100px;
8 | }
--------------------------------------------------------------------------------
/src/app/siblings/child-one/child-one.component.html:
--------------------------------------------------------------------------------
1 |
3 | Select Theme
4 |
--------------------------------------------------------------------------------
/src/app/siblings/child-one/child-one.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { ParentDirective } from '../parent.directive';
3 |
4 | @Component({
5 | selector: 'app-child-one',
6 | templateUrl: './child-one.component.html',
7 | styleUrls: ['./child-one.component.css']
8 | })
9 | export class ChildOneComponent implements OnInit {
10 |
11 | color$;
12 |
13 | constructor(public directive: ParentDirective) { }
14 |
15 | ngOnInit() {
16 | this.color$ = this.directive.observable$;
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/src/app/siblings/child-two/child-two.component.css:
--------------------------------------------------------------------------------
1 | input {
2 | margin-left: 10px;
3 | }
--------------------------------------------------------------------------------
/src/app/siblings/child-two/child-two.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/src/app/siblings/child-two/child-two.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { ParentDirective } from '../parent.directive';
3 |
4 | @Component({
5 | selector: 'app-child-two',
6 | templateUrl: './child-two.component.html',
7 | styleUrls: ['./child-two.component.css']
8 | })
9 | export class ChildTwoComponent implements OnInit {
10 |
11 | color$;
12 |
13 | constructor(public directive: ParentDirective) { }
14 |
15 | ngOnInit() {
16 | this.color$ = this.directive.observable$;
17 | }
18 |
19 | updateColor(val) {
20 | this.directive.updateColor(val);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/app/siblings/parent.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, Input } from '@angular/core';
2 | import { BehaviorSubject, Observable} from 'rxjs';
3 |
4 | @Directive({
5 | selector: '[appParent]'
6 | })
7 | export class ParentDirective {
8 |
9 | private behaviorSubject = new BehaviorSubject('#1e90ff');
10 | public observable$ = this.behaviorSubject.asObservable();
11 |
12 | constructor() { }
13 |
14 | ngOnInit() { }
15 |
16 | updateColor(color) {
17 | this.behaviorSubject.next(color);
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/src/app/unrelated/activator/activator.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Everduin94/component-communication-patterns/78ab62ae5c1c6868d87ca213c5e8cbdc345ff91a/src/app/unrelated/activator/activator.component.css
--------------------------------------------------------------------------------
/src/app/unrelated/activator/activator.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/unrelated/activator/activator.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { ToastService } from '../toast.service';
3 |
4 | @Component({
5 | selector: 'app-activator',
6 | templateUrl: './activator.component.html',
7 | styleUrls: ['./activator.component.css']
8 | })
9 | export class ActivatorComponent implements OnInit {
10 |
11 | constructor(private ts: ToastService) { }
12 |
13 | ngOnInit() {
14 | }
15 |
16 | onChange() {
17 | this.ts.setEnabled();
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/src/app/unrelated/toast.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { BehaviorSubject } from 'rxjs';
3 |
4 | @Injectable()
5 | export class ToastService {
6 |
7 | private bs = new BehaviorSubject(false);
8 | public eventStream$ = this.bs.asObservable();
9 |
10 | constructor() {}
11 |
12 | public setEnabled() {
13 | if (!this.bs.value) {
14 | this.bs.next(true);
15 | setTimeout(val => {
16 | this.bs.next(false);
17 | }, 5000);
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/app/unrelated/toast/toast.component.css:
--------------------------------------------------------------------------------
1 | .toast {
2 | background: dodgerblue;
3 | color: #FFFFFF;
4 | padding: 10px;
5 | /* Required to Center (Must have width) */
6 | position: absolute;
7 | width: 130px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | left: 0px;
11 | right: 0px;
12 | opacity: 0;
13 |
14 | text-align: center;
15 | animation: moveUp 2.5s 2 forwards alternate;
16 | }
17 |
18 | @keyframes moveUp {
19 | 0% {
20 | bottom: 0px;
21 | opacity: 0;
22 | }
23 |
24 | 30% {
25 | opacity: 1;
26 | bottom: 30px;
27 | }
28 |
29 | 100% {
30 | opacity: 1;
31 | bottom: 30px;
32 | }
33 | }
--------------------------------------------------------------------------------
/src/app/unrelated/toast/toast.component.html:
--------------------------------------------------------------------------------
1 |
2 | Activated Process!
3 |
--------------------------------------------------------------------------------
/src/app/unrelated/toast/toast.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { ToastService } from '../toast.service';
3 |
4 | @Component({
5 | selector: 'app-toast',
6 | templateUrl: './toast.component.html',
7 | styleUrls: ['./toast.component.css']
8 | })
9 | export class ToastComponent implements OnInit {
10 |
11 | eventStream$
12 |
13 | constructor(private ts: ToastService) {
14 | this.eventStream$ = ts.eventStream$;
15 | }
16 |
17 | ngOnInit() {
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Angular App
4 |
5 |
6 | loading
7 |
8 |
--------------------------------------------------------------------------------
/src/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, '../coverage'),
20 | reports: ['html', 'lcovonly'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false
30 | });
31 | };
--------------------------------------------------------------------------------
/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! */
2 | button {
3 | padding: 10px;
4 | margin: 10px;
5 | background: dodgerblue;
6 | color: #FFFFFF;
7 | font-weight: 600;
8 | border-radius: 2px;
9 | border: 1px solid dodgerblue;
10 | }
11 |
12 | button:hover {
13 | color: dodgerblue;
14 | background: #FFFFFF;
15 | }
--------------------------------------------------------------------------------
/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "types": []
6 | },
7 | "exclude": [
8 | "test.ts",
9 | "**/*.spec.ts"
10 | ]
11 | }
--------------------------------------------------------------------------------
/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "test.ts",
12 | "polyfills.ts"
13 | ],
14 | "include": [
15 | "**/*.spec.ts",
16 | "**/*.d.ts"
17 | ]
18 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "module": "es2015",
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "target": "es5",
13 | "typeRoots": [
14 | "node_modules/@types"
15 | ],
16 | "lib": [
17 | "es2018",
18 | "dom"
19 | ]
20 | }
21 | }
--------------------------------------------------------------------------------