Error: More than one module matches. Use skip-import option to skip importing the component into the closest module ← when running
ng g
Chỉ cần chỉ rõ module nào để cho component này add vào là ok.
1ng g c new-component --module <module-cha>
CPU and RAM too high when using
ng serve
Disable
live-reload
by adding --live-reload false
. Then whenever you make some changes in the codes and the recompile process is finished, you have to manually reload the web app.Error 'BsDropdownDirective' is neither 'ComponentType' or 'DirectiveType’
I had the issue and it was
dropdown
directive missing from the upper div.Error: ExpressionChangedAfterItHasBeenCheckedError: Previous value: 'ng-untouched: true'. Current value: 'ng-untouched: false’
- Đến từ component có
ChangeDetectorRef
- (Ideta)
app-input-text
dùng 2 cái focus input 1 lúc trong view → conflict → có tình trạng ng-untouched chuyển từ true sang false là vậy!
async
pipes are automatically unsubscribing from the observables they're fed withAngular routing and
pathMatch
Read this SO answer (wonderful and complete explanation, should read). A
pathMatch: full
configuration is basically saying this:Ignore my children and only match me (you = url in the bar, me = configured path in the file). If I am not able to match all of the remaining URL segments myself, then move on.
Nếu dùng
redirectTo
thì chỉ cần match 1 phần url nó cũng redirect. Để tránh tình trạng này, ta thường dùng pathMatch: full
để chắc chắn rằng toàn bộ url phải match thì mới trigger cái redirectTo
.getRawValue()
this.form.value
chỉ return value của mấy controls mà ko disabled.
this.form.getRawValue()
reutrn value của tất cả các controls cho dù disabled hay không.
Auto scroll to the bottom of a div when adding a new child to an array
Create a
BaseComponent
A “hack” is to add
@Directive()
before the class.In case prettier isn’t working with VSCode
Open settings JSON file,
1"editor.defaultFormatter": "esbenp.prettier-vscode"
Or for a specific file type,
1"[html]": {
2 "editor.defaultFormatter": "esbenp.prettier-vscode"
3}
Angular change detector wont trigger on array mutations
It may leads to some error, for example, cdkVirtualFor doesn't detect changes in array.
1// Instead of this (delete an item from array)
2delete(i: number) {
3 this.items.splice(i,1);
4}
5
6// Use this
7delete(i: number) {
8 this.items = this.items.filter((a, index) => index !== i);
9}
1// If above option doesn't work
2// Instead of
3this.items = items;
4// do
5this.items = [...items];
Difference between
detectChanges
and markForCheck
Check this SO.
detectChanges
()
: It means, if there is a case where any thing inside your model (your class) has changed but it hasn't reflected the view, you might need to notify Angular to detect those changes (detect local changes) and update the view.
markForCheck
()
: This is mostly needed when the ChangeDetectionStrategy of your component is OnPush.
Lazy load for list in Angular
We use
ScrollingModule
from @angular/cdk/scrolling
.Note that, for elements of differing sizes, we can use
autosize
← this from @angular/cdk-experimental
.1<cdk-virtual-scroll-viewport autosize class="ideta-scrollbar">
2 <div *cdkVirtualFor="let item of list; let i = index" class="pb-2"></div>
3</cdk-virtual-scroll-viewport>
Creation
1// module with routing
2ng generate m --routing test
3// test.module.ts and test-routing.module.ts
Sau khi tạo module rùi, tạo thêm routing module sẽ không được. Tuy nhiên sau khi tạo module rồi, tạo thêm component vẫn ok.
1ng generate c test // test.component.ts
VScode extensions
For “Go to definition”, use Angular Language Service (ALS).
(Personal exp) Using Angular 13 and this function is not working → instead of modify
tsconfig.json
where angularCompilerOptions { "strictTemplates": true }
, we can go to ALS’s settings and tick “Force Strict Templates”Prevent destroy / CanDeactivate
Ý tưởng là muốn warning trước khi destroy → nếu không thoả thì ko cho destroy! (This SO)
1// Don't wanna add extra DOM
2<ng-container *ngIf="store.products">
3 <p>Content</p>
4</ng-container>
(select)
eventNot like
input
element who has an (select)
event. On a div.contenteditable
, we don’t have this kind of event. 1<div (click)="checkSelection()" (keyup)="checkSelection()"></div>
1checkSelection() {
2 var selection = window.getSelection();
3 if (selection.toString().length !== 0) {
4 console.log('you selected: ', selection.toString());
5 }
6}
Should always use
SimpleChanges
👉 Source.
1@Input() myFirstInputParameter: string;
2
3ngOnChanges(changes: SimpleChanges) {
4 if (changes.myFirstInputParameter && changes.myFirstInputParameter.currentValue) {
5 this.doSomething(this.myFirstInputParameter)
6 }
7}
Changes get called just because of EACH input.
Prevent changing route if there are changes not saved
Idea: In each component, cereate a method called
isDirty()
→ pass it in a guard which extends the CanDeactivate
→ pass it in the routing modules. Whenever a component return false
for isDirty
, it means there are some changes not saved.:host
with ViewEncapsulation.None
Note:
:host
doesn't work with ViewEncapsulation.None
!1/* With ViewEncapsulation.Emulated, use :host selector */
2:host {
3 color: red;
4}
5
6/* With ViewEncapsulation.None, use component selector */
7app-child-encapsulation-none {
8 color: green;
9}
Different ways to add CSS classes
1<div
2 class="default-class"
3 [class.class-A]="condition"
4>Content</div>
1<div
2 class="default-class"
3 [className]="'class-a'"
4>Content</div>
1<div
2 class="default-class"
3 [className]="condition ? 'class-a' : 'other-class'"
4>Content</div>
1<div
2 class="default-class"
3 [ngClass]="{
4 'class-a': condition-a,
5 'class-b': condition-b
6 }"
7>Content</div>
ngOnInit
child with base component@Input()
but child’s changes → parent’s changes?1<app-child [inputChild]="inputParent"></app-child>
Nếu trong
app-child
, cái inputChild
có thay đổi, tức là, ví dụ1// app-child
2this.inputChild = somethingElse // This will change also the inputParent
Bởi vì khi assign value giống trên, tức ta assign reference của nó!
👉 Cái này là pass by reference
Còn cái mình hiểu lúc đọc doc của angular là pass by value và dùng decor là
@Input()
và @Output()
@Input()
parent’s changes → child’s changes?Yes → Use
ngOnChanges
to see the updated value of the input! (Don’t use ngOnInit
to check)OnPush
change detectionchangeDetection: ChangeDetectionStrategy.OnPush
= auto change detection is deactivated. Tell angular that the component only depends on its@Input()
and need to be checked (ref).
changeDetection: ChangeDetectionStrategy.Default
(orCheckAlways
) = change detection is automatic.
Call children’s methods from parent
ngFor
and ngIf
the same time?It’s impossible if we wanna use them in the same
div
. Use ng-container
instead,1<ng-container *ngIf="show">
2 <div *ngFor="let thing of stuff">
3 {{log(thing)}}
4 <span>{{thing.name}}</span>
5 </div>
6</ng-container>
ng-template
, ng-container
and else
in html
1<p *ngIf="serverCreated; else noServer">Content</p>
2<ng-template #noServer>
3 <p>Other text</p>
4<ng-template>
1// Or both
2<ng-container *ngIf="store.products" else #noServer>
3 <p>Content</p>
4</ng-container>
5
6<ng-template #noServer>
7 <p>Other text</p>
8<ng-template>
Reuse an HTML block using
ng-template
1<ng-template #MsgRef >
2 {{ mycontent }}
3</ng-template>
4
5<ng-template [ngTemplateOutlet]="MsgRef"></ng-template> //reuse any number of times
Safer way to do
this.ref.nativeElement.innerHTML = newText
👉 Reference.
1import { ..., AfterViewInit, ElementRef, ViewChild, Renderer2, ... } from '@angular/core';
2...
3export class AdvertisementDirective implements AfterViewInit {
4 @ViewChild('templateRefName') el: ElementRef;
5
6 constructor(private renderer: Renderer2) {}
7
8 someFunction() {
9 this.renderer.setProperty(this.el.nativeElement, 'innerHTML', '<p>Hello World<p>');
10 }
11}
ngFor
and trackBy
👇 Source.
Without
trackBy
⇒ whole list changes. With trackBy
⇒ only the current modif item changes (the comparitor is the function given to trackBy
← angular will compare the previously returned value and currently returned value of this function)1array = [
2 { "id": 1, "name": "bill" },
3 { "id": 2, "name": "bob" },
4 { "id": 3, "name": "billy" }
5]
6
7const trackById = (_index: number, item: any) => item.id;
1<div *ngFor="let e of array; trackBy: trackById;">
2 {{e.id}} - {{e.name}}
3</div>
1// app.component.ts
2onEditCourse1() { // <-- change a property
3 this.courses[0].title = "New title";
4}
5onEditCourse2() { // <- change entire object
6 const newCourse = { title: "New title };
7 this.courses[0] = newCourse;
8}