diff --git a/Day038-dynamic-component.md b/Day038-dynamic-component.md
index 66ba6c3..e4bc9f8 100644
--- a/Day038-dynamic-component.md
+++ b/Day038-dynamic-component.md
@@ -13,6 +13,9 @@ Hay ở tình huống khác, chúng ta muốn người dùng phải là
Vậy việc load động 1 component khác trong lúc runtime được thực hiện như thế nào?
Điều đó dẫn ta đến bài hôm nay, **Dynamic Component** sẽ là câu trả lời phù hợp để làm việc này.
+Dưới đây là kết quả của project code hôm nay
+
+
## Coding Practice
### Step 1: Khởi tạo project
@@ -99,22 +102,38 @@ export class ExampleContainerComponent implements OnInit {
Flow chính:
1. Tạo 1 ViewChild trong template. Ở đây là thẻ div **#dynamicComponent**. Đây sẽ là nơi chúng ta load những components vào ở runtime.
-2. Connect **#dynamicComponent** thông qua @ViewChild. Chúng ta sẽ có 1 [ViewContainerRef](###ViewContainerRef)
+
+ ```html
+
+ ```
+
+2. Connect **#dynamicComponent** thông qua **@ViewChild**. Chúng ta sẽ có 1 [ViewContainerRef](###ViewContainerRef)
+
+ ```typescript
+ @ViewChild("dynamicComponent", { read: ViewContainerRef, static: true })
+ containerRef: ViewContainerRef;
+ ```
+
3. Inject [CompanyFactoryResolver](###ComponentFactoryResolver) của Angular vào component ExampleContainerComponent.
+
+ ```typescript
+ constructor(private cfr: ComponentFactoryResolver) {}
+ ```
+
4. Dùng Resolver connect với component nào chúng ta muốn load dynamic.
=> Kết quả sẽ trả về 1 [Component Factory](###ComponentFactory)
-```typescript
-const componentFactory = this.cfr.resolveComponentFactory(
- DynamicContentOneComponent
-);
-```
+ ```typescript
+ const componentFactory = this.cfr.resolveComponentFactory(
+ DynamicContentOneComponent
+ );
+ ```
-Dùng **ViewContainerRef** với Component Factory chúng ta vừa tạo ở trên để load **Dynamic Component**.
+5. Dùng **ViewContainerRef** với Component Factory chúng ta vừa tạo ở trên để load **Dynamic Component**.
-```typescript
-const componentRef = this.containerRef.createComponent(componentFactory);
-```
+ ```typescript
+ const componentRef = this.containerRef.createComponent(componentFactory);
+ ```
### Step 4: Add các dynamic components vào entryComponents
@@ -186,11 +205,11 @@ addDynamicCompOne() {
Hiện tại code sử dụng entryComponents đã cũ và với **Angular Ivy**, chúng ta hoàn toàn không cần sử dụng nữa. Ngoài ra chúng ta có thể sử dụng **Angular Ivy** để **lazy load** các components dynamic.
Code sẽ sửa như sau:
-### Step 7.1: Xóa entryComponents setting in app.module.ts
+#### Step 7.1: Xóa entryComponents setting in app.module.ts
Các bạn hãy vào file app.module.ts xóa đi config đã set ở step 4.
-### Step 7.2: Update code ở container component
+#### Step 7.2: Update code ở container component
- Remove 2 cái import components ở đầu file.
- Sửa 2 hàm addDynamicComp
@@ -216,8 +235,9 @@ Code sẽ như sau:
componentRef.instance.data = "INPUT DATA 2";
}
```
+
Vậy là đã xong, các bạn đã thực hiện thành công việc lazy load các dynamic components mà không phải add trực tiếp vào như ở những step đầu.
-**Lưu ý**: Đối với những bạn nào dùng Angular phiên bản cũ thì nhớ update angular để sử dụng tính năng Angular Ivy.
+**Lưu ý**: Đối với những bạn nào dùng Angular phiên bản cũ thì nhớ update angular để sử dụng tính năng Angular Ivy.
## Concepts
@@ -226,7 +246,7 @@ Vậy là đã xong, các bạn đã thực hiện thành công việc
Nó là một cái container từ đó có thể tạo ra Host View (component khi được khởi tạo sẽ tạo ra view tương ứng), và Embedded View (được tạo từ TemplateRef). Với các view được tạo đó sẽ có nơi để gắn vào (container).
Container có thể chứa các container khác (ng-container chẳng hạn) tạo nên cấu trúc cây. Hay hiểu đơn giản thì nó giống như 1 DOM Element, khi đó có thể add thêm các view khác (Component, Template) vào đó.
-
+[TiepPhan](https://www.tiepphan.com/angular-trong-5-phut-dynamic-component-rendering/)
### ComponentFactory
@@ -236,7 +256,7 @@ Container có thể chứa các container khác (ng-container chẳng hạn) t
Đây là 1 class nhận vào các component để load dynamic và tạo ra 1 component factory của component đó. ViewContainerRef sẽ dùng **ComponentFactory** đó để load dynamic các components.
-## Exercies
+## Exercise
### 1. Replace component, not Add
@@ -252,7 +272,7 @@ Cũng như thử emit event từ ViewChild và nhận, xử lý sự ki
Day 38 chúng ta đã học được những concepts liên quan đến Dynamic Component. Đây là 1 tính năng quan trọng có tính ứng dụng cao. Các bạn có thể thực hành nhiều hơn thông qua các bài tập mình đưa cũng như các nguồn tài liệu mình để dưới đây.
-Mục tiêu của ngày 39 sẽ là
+Mục tiêu của ngày 39 sẽ là **Custom Attribute Directive**.
## Code sample
diff --git a/Day039-custom-attribute-directive.md b/Day039-custom-attribute-directive.md
new file mode 100644
index 0000000..ca76668
--- /dev/null
+++ b/Day039-custom-attribute-directive.md
@@ -0,0 +1,231 @@
+# Day 39: Custom Attribute Directive trong Angular
+
+## Introduction
+
+Qua các bài trước, các bạn cũng biết những directives trong Angular như ngFor, ngIf, ngStyle.
+Trước khi bước vào bài mới hôm nay, mình xin tổng quát lại về các directives như sau:
+
+Có 3 loại directives trong Angular:
+
+**Components**: Đây là directive phổ biến nhất, cũng thường gặp nhất trong Angular. Directive này giúp chúng ta đóng gói (encapsulated), và tái sử dụng (reusable). Đây là directive với template, view.
+
+**Structural directives**: Đây là directive dùng để thay đổi cấu trúc của views bằng cách thêm hoặc ẩn, xóa bớt phần tử trong DOM. Ví dụ: ngFor, ngIf.
+
+**Attribute directives**: Đây là directive dùng để thay đổi diện mạo (style, appearance) hoặc hành vi (behavior) của các phần tử DOM hay components. Ví dụ: ngStyle, ngClass
+
+Và bài hôm nay của chúng ta sẽ là tạo 1 **Custom Attribute Directive** để chúng ta có thể tái sử dụng nhiều nơi trong ứng dụng.
+
+Dưới đây là kết quả của project code hôm nay
+
+
+
+## Coding Practice
+
+### Step 1: Khởi tạo project
+
+```sh
+ng new custom-attribute-directive-demo
+```
+
+### Step 2: Tạo các components và directives
+
+```sh
+ng g c example-component
+```
+
+```sh
+ng generate directive custom-directive-demo
+```
+
+Một lưu ý nhỏ ở đây như sau, để sử dụng được directive này chúng ta cần khai báo nó vào module giống như cách chúng ta khai báo component. Câu lệnh generate trên đã auto khai báo directive trên declarations của AppModule cho chúng ta.
+
+Sau đó chúng ta add example-component vào template của app.component.html như sau:
+
+```html
+
+```
+
+### Step 3: Code directive logic
+
+Chúng ta sẽ inject **ElementRef** vào constructor của directive như sau:
+
+```typescript
+constructor(private el: ElementRef) {
+ this.el.nativeElement.innerText = "DEMO TEXT";
+ this.el.nativeElement.style.color = "blue";
+}
+```
+
+Ở đây chúng ta dùng **ElementRef** để tương tác và thay đổi các properties của DOM element. Cụ thể là **innerText** hay **style.color**.
+
+### Step 4: Apply directive
+
+Chúng ta apply attribute directive bằng cách add nó vào như mọi attribute bình thường khác. Tên của attribute này sẽ nằm ở decorator @Directive. (Chúng ta hoàn toàn có thể sửa lại tên chúng ta muốn. Ở đây mình đã sửa từ appCustomDirectiveDemo -> appCustomDirective)
+
+```typescript
+@Directive({
+ selector: "[appCustomDirective]",
+})
+```
+
+Chúng ta vào file **example-component.component.html** sửa lại như sau để apply custom directive chúng ta vừa tạo vào component này.
+
+```html
+
+```
+
+Vậy là chúng ta đã hoàn thành cách tạo và sử dụng 1 custom attribute directive đơn giản.
+
+### Step 5: Using Render2
+
+Ở step 3, chúng ta đã dùng **ElementRef** để tương tác và thay đổi các properties của DOM element. Điều này đã được warning trong official doc của Angular là không nên vì nó sẽ tạo nguy cơ về cho XSS attacks.
+Và ở chính warning đó, Angular cũng giới thiệu đến **Render2** layer. **Render2** cung cấp những apis để dùng tương tác với DOM element 1 cách an toàn. Vậy nên chúng ta sẽ update code sử dụng **Render2** như sau:
+
+```typescript
+export class CustomDirectiveDemoDirective {
+ constructor(private el: ElementRef, private renderer: Renderer2) {
+ this.customContent("DEMO TEXT", "blue");
+ }
+ private customContent(text: string, color: string) {
+ this.renderer.setProperty(this.el.nativeElement, "innerText", text);
+ this.renderer.setStyle(this.el.nativeElement, "color", color);
+ }
+}
+```
+
+### Step 6: Interact with event of Host Element
+
+Khi chúng ta sử dụng 1 **Custom Directive** cho 1 HTML element, thì element đó sẽ được gọi là **Host Element**.( Ở trường hợp của chúng ta Host Element chính thẻ p ở template của example component )
+
+Vậy hiện tại chúng ta muốn xử lý event của Host Element ở directive thì chúng ta sẽ làm thế nào? Ví dụ, khi hover chuột thì đổi màu text. Ở trường hợp nào chúng ta sẽ tương tác thông qua **HostListener**.
+
+Code chúng ta sẽ update như sau để lắng nghe và xử lý 2 event **mouseenter** and **mouseleave** trên Host Element:
+
+```typescript
+export class CustomDirectiveDemoDirective {
+ constructor(private el: ElementRef, private renderer: Renderer2) {
+ this.customContent("DEMO TEXT", "blue");
+ }
+
+ @HostListener("mouseenter") onMouseEnter() {
+ this.customContent("ON MOUSE ENTER", "orange");
+ }
+
+ @HostListener("mouseleave") onMouseLeave() {
+ this.customContent("DEMO TEXT", "blue");
+ }
+
+ private customContent(text: string, color: string) {
+ this.renderer.setProperty(this.el.nativeElement, "innerText", text);
+ this.renderer.setStyle(this.el.nativeElement, "color", color);
+ }
+}
+```
+
+### Step 7: Pass values into the directive
+
+Tiếp theo, chúng ta sẽ truyền xử lý data truyền từ Host Element vào directive. Cụ thể ở case này chúng ta sẽ truyền màu sẽ thay đổi khi hover từ thẻ p vào.
+
+Ở thẻ p, chúng ta sẽ truyền vào như 1 attribute bình thường.
+
+```html
+
+```
+
+Ở directive, chúng ta sẽ dùng **@Input** để nhận và xử lý.
+
+```typescript
+import {
+ Directive,
+ ElementRef,
+ Renderer2,
+ HostListener,
+ Input,
+} from "@angular/core";
+
+@Directive({
+ selector: "[appCustomDirective]",
+})
+export class CustomDirectiveDemoDirective {
+ @Input() hoverColor: string;
+
+ constructor(private el: ElementRef, private renderer: Renderer2) {
+ this.customContent("DEMO TEXT", "blue");
+ }
+
+ @HostListener("mouseenter") onMouseEnter() {
+ this.customContent("ON MOUSE ENTER", this.hoverColor);
+ }
+
+ @HostListener("mouseleave") onMouseLeave() {
+ this.customContent("DEMO TEXT", "blue");
+ }
+
+ private customContent(text: string, color: string) {
+ this.renderer.setProperty(this.el.nativeElement, "innerText", text);
+ this.renderer.setStyle(this.el.nativeElement, "color", color);
+ }
+}
+```
+
+Vậy là đã xong, các bạn đã thực hiện thành công việc tạo và sử dụng 1 **Custom Attribute Directive** trong Angular.
+
+## Concepts
+
+### ElementRef
+
+Đây là 1 class trong **@angular/core** dùng để tương tác với các DOM element trong template. Tuy nhiên chúng ta không nên sử dụng trực tiếp vì vấn đề security.
+
+### Renderer2
+
+Đây là 1 class cung cấp những apis để tương tác với DOM Element 1 cách an toàn. Chúng ta sẽ dùng nó gọi đến ElementRef.
+
+### HostListener
+
+Đây là 1 decorator được định nghĩa cho việc lắng nghe 1 event của DOM. Chúng ta sẽ dùng để viết hàm xử lý khi event đó diễn ra.
+
+Example:
+
+```typescript
+constructor(private el: ElementRef, private renderer: Renderer2) {
+ this.renderer.setProperty(this.el.nativeElement, "innerText", "DEMO");
+}
+```
+
+## Exercise
+
+### 1. @Input and @Input alias
+
+Hiện tại code đang truyền vào thẻ p 2 attribute là **appCustomDirective** và **hoverColor** cho 2 mục đích khác nhau. Hãy sử dụng **property binding** để chỉ cần truyền 1 cái và làm gọn code đi.
+Tham khảo: [**Pass value into directive**](https://angular.io/guide/attribute-directives#pass-values-into-the-directive-with-an-input-data-binding)
+
+### 2. Interact more with Render2
+
+Hãy sử dụng các apis của Render2 để biến đổi nhiều properties và styles hơn.
+
+## Summary
+
+Day 39 chúng ta đã học được những concepts và cách làm liên quan đến cách **Custom attribute directive**.
+
+Mục tiêu của ngày 40 sẽ là **Custom structural directive**.
+
+## Code sample
+
+- https://github.com/januaryofmine/angular-custom-attribute-directive-example
+
+## References
+
+Các bạn có thể đọc thêm ở các bài viết sau
+
+- https://angular.io/guide/attribute-directives#build-a-simple-attribute-directive
+- https://medium.com/@nishu0505/custom-directives-in-angular-5a843f76bb96
+- https://angular.io/api/core/ElementRef
+
+## Author
+
+[Khanh Tiet](https://github.com/januaryofmine)
+
+`#100DaysOfCodeAngular` `#100DaysOfCode` `#AngularVietNam100DoC_Day39`
+
+[day34]: Day034-template-driven-forms-2.md
+[day38]: Day038-dynamic-component.md
diff --git a/Day040-custom-structural-directive.md b/Day040-custom-structural-directive.md
new file mode 100644
index 0000000..be7b7fd
--- /dev/null
+++ b/Day040-custom-structural-directive.md
@@ -0,0 +1,275 @@
+# Day 40: Custom Structural Directive trong Angular
+
+## Introduction
+
+Ở bài trước, chúng ta đã biết cách tạo và sử dụng 1 **Custom Attribute Directive**. Ở bài này, chúng ta sẽ tiếp tục tiếp hiểu cách tạo và sử dụng 1 **Custom Structural Directive**.
+
+Đây là project của bài hôm nay
+
+
+
+## Coding Practice
+
+### Step 1: Khởi tạo project
+
+```sh
+ng new custom-structural-directive-demo
+```
+
+### Step 2: Tạo các components và directives
+
+```sh
+ng g c example-container
+```
+
+```sh
+ng g d custom-loop
+```
+
+Sau đó chúng ta add example-container vào template của app.component.html như sau:
+
+```html
+
+```
+
+### Step 3: Code directive logic and apply to component
+
+Chúng ta sẽ tạo 1 **ngFor** cơ bản như sau. Đầu tiên các bạn hãy add những đoạn code sau vào và chạy project thử để có cái nhìn tổng quan.
+
+Add `FormsModule` vào app.module. (Vì chúng ta sẽ sử dụng `ngModel` cho project này).
+
+File `custom-loop.directive.ts`
+
+```typescript
+import { Directive, Input, ViewContainerRef, TemplateRef } from "@angular/core";
+
+@Directive({
+ selector: "[ngCustomLoop]",
+})
+export class CustomLoopDirective {
+ @Input("ngCustomLoopOf") itemList: Array;
+
+ constructor(
+ private containerRef: ViewContainerRef,
+ private template: TemplateRef
+ ) {}
+
+ ngOnChanges() {
+ this.containerRef.clear();
+
+ for (const item of itemList) {
+ this.containerRef.createEmbeddedView(this.template, {
+ $implicit: item,
+ index: this.itemList.indexOf(item),
+ });
+ }
+ }
+}
+```
+
+File `example-container.component.html`
+
+```html
+
+
+ {{ i + 1 }}. {{ city }}
+
+```
+
+File `example-container.component.ts`
+
+```typescript
+export class ExampleContainerComponent implements OnInit {
+ text = "";
+ cityList = ["Ha Noi", "Ho Chi Minh", "Da Nang", "Nha Trang", "Vinh Long"];
+
+ constructor() {}
+
+ ngOnInit() {}
+}
+```
+
+Khi chạy đoạn code trên, các bạn đã thấy được 1 cái input và 1 danh sách ngắn các thành phố.
+Mình đã dùng `Custom Loop Directive` của mình để generate ra.
+
+Bây giờ chúng ta đi vào quá trình đọc hiểu code.
+
+#### 3.1, Mình đã làm thế nào để sử dụng directive `CustomLoop` cho component `ExampleContainer`?
+
+Đầu tiên các bạn nhìn vào file html của component. Các bạn thấy thay vì là *ngFor như bình thường, mình đã thay thế bằng
+*ngCustomLoop.
+
+Các bạn vào file directive. Như bài 39 trước, tên directive nằm ở trong decorator **@Directive**, và các bạn sẽ dùng tên này mỗi khi muốn sẽ sử dụng directive có các HTML elements. (Ở đây mình sẽ sửa tên này ngCustomLoop)
+
+```typescript
+@Directive({
+ selector: "[ngCustomLoop]",
+})
+```
+
+#### 3.2, Mình đã truyền list các thành phố cho directive bằng cách nào?
+
+Các bạn thấy `Custom Loop directive` này mình nhận vào 1 Array như sau:
+
+```typescript
+@Input("ngCustomLoopOf") itemList: Array;
+```
+
+Mình đã dùng **@Input** alias để đổi tên lại thành _itemList_, dễ dùng hơn thay vì dùng tên _ngCustomLoopOf_ bên ngoài truyền vào. Nhưng mình đã truyền cái này vào ở đâu?
+
+Các bạn qua file html của `ExampleContainer` component.
+
+```html
+
+ {{ i + 1 }}. {{ city }}
+
+```
+
+Nhìn vào đây các bạn có thể đoán được biến mình truyền vào là `cityList`. Tuy nhiên, tại sao nó lại có tên `ngCustomLoopOf`.
+
+Đó là 1 micro syntax trong Angular. Angular đã kết hợp tên của directive (ở đây là **ngCustomLoop**) với tên identity cho biến truyền vào (ở đây là chữ **of**).
+
+> **ngCustomLoop + of = ngCustomLoopOf**
+
+(Nếu đoạn này các bạn vẫn cảm thấy chưa hiểu lắm thì đọc xuống xíu nữa, mình có giải thích tiếp)
+
+Các bạn sẽ còn gặp lại cách truyền value thế này vào directive ở tính năng tiếp theo của project này.
+
+#### 3.3, Mình đã dùng cái gì để generate ở `HTML` code từ file `Custom Loop directive`?
+
+Ở lifecycle _ngOnChange_ của directive này, mình dùng **ViewContainerRef** và gọi hàm **createEmbeddedView()** của nó như sau:
+
+```typescript
+constructor(
+ private containerRef: ViewContainerRef,
+ private template: TemplateRef
+) {}
+
+ngOnChanges() {
+ this.containerRef.clear();
+
+ for (const item of itemList) {
+ this.containerRef.createEmbeddedView(this.template, {
+ $implicit: item,
+ index: this.itemList.indexOf(item),
+ });
+ }
+ }
+```
+
+Đọc code này các bạn có thể hình dung cơ bản:
+
+1, Mình inject `TemplateRef` và `ViewContainerRef` vào directive này.
+Nói về `TemplateRef`, khi gặp directive có dấu \* (asterisk), Angular sẽ thực hiện cơ chế wrapper Host Element (ở đây là thẻ `p`) vào ``. Và điều này chúng ta khi inject template này vào directive để sử dụng cũng như thực hiện các thao tác trên nó.
+
+2, Mình dùng `ViewContainerRef` và gọi hàm `createEmbeddedView()` dùng để tạo views. Ở bài 38, mình cũng có nói `ViewContainerRef` sẽ được dùng để tạo những `EmbeddedView`.
+Đây là cơ chế chính trong việc tạo 1 **Custom Structural Directive**.
+
+#### 3.4, Hàm `createEmbeddedView()` và những điều cần biết.
+
+1, Hàm `createEmbeddedView()` nhận vào param thứ 1 là `TemplateRef` dùng để khởi tạo `EmbeddedView`.
+
+2, Hàm `createEmbeddedView()` nhận vào param thứ 2 là `Context Object`.Đây là Object định nghĩa cho những gì nó trả ra.
+
+> Nói về **\$implicit**, khái niệm này ở bài 5 đã giới thiệu qua. Nay mình nói lại cho cụ thể hơn. **\$implicit** là 1 property đặc biệt, như tên gọi của nó, mình tạm dịch nghĩa tiếng Việt của Implicit là `"Ngầm hiểu"`. Đây là property được mặc định sẽ trả ra trong hàm này.
+
+Để hiểu rõ hơn thì các bạn tạm thời các bạn sửa code như sau.
+
+File `example-container.component.html`
+
+```html
+
+ {{ i + 1 }}. {{ city }}
+
+```
+
+File `custom-loop.directive.ts`
+
+```typescript
+ export class CustomLoopDirective {
+ @Input("ngCustomLoopOf") itemList: Array;
+ @Input("ngCustomLoopFindingText") findingText: string;
+ ...
+ }
+```
+
+Nhìn lại project, vẫn hoạt động bình thường. Đến đây thì các bạn cũng hình dung ra rồi.
+
+Cấu trúc huyền thoại đã học `*ngFor="let item of itemList"`, thật ra `item` với `itemList` nó chẳng liên quan gì với nhau cả.
+
+Ở đây mình đã sửa thành `of: cityList` cho các bạn dễ hiểu, đây là truyền vào directive biến **of** có value là **cityList**.
+
+Tương tự như mình vừa truyền vào thêm 1 biến khác **findingText** có value là **text** (biến text này mình đã tạo sẵn trong file typescript của component).
+
+Tiếp đó cái **let city** bản chất là `let city = $implicit`. Đây là biến bắt buộc cần định nghĩa để Angular gán giá trị của **\$implicit** vào. Nếu không khai báo thì sẽ bị lỗi.
+
+Kết luận bản chất **let city** là cái hứng đầu ra. **of: cityList** là biến truyền đầu vào. 2 cái này không liên quan gì nhau hết. Việc mình biến đổi **cityList** thế nào để trả ra là quyền của mình, thậm chí mình trả cái **\$implicit** ra chẳng liên quan gì cái **cityList** cũng chẳng sao cả. Quyền của mình mà.
+
+Đến đây chắc các bạn cũng hiểu rồi. Ngoài ra nhìn lại đoạn
+
+```typescript
+ngOnChanges() {
+ for (const item of itemList) {
+ this.containerRef.createEmbeddedView(this.template, {
+ $implicit: item,
+ index: this.itemList.indexOf(item),
+ });
+ }
+ }
+```
+
+```html
+
+ {{ i + 1 }}. {{ city }}
+
+```
+
+Các bạn sẽ thấy ngoài trừ `$implicit`, mình còn thêm vào object trả ra 1 cái nữa tên là `index`. Ở đây mình đã xử lý để trả ra `index` là vị trí phần tử trong mảng
+
+```typescript
+ index: this.itemList.indexOf(item).
+```
+
+Vì biến này không phải `$implicit` nên muốn nhận biến này phải khai báo nhận đàng hoàng như sau trong file html `let i = index`. Ngoài ra các bạn cũng có thể dùng cách `index as i`.
+
+Vậy là đã xong, các bạn đã thực hiện thành công việc tạo và sử dụng 1 **Custom Structural Directive** trong Angular. Các bạn có thể dựa vào đây tiếp tục truyền thêm **@Input** vào, xử lý trả về `Object Context` nhiều và đa dạng hơn. Hoặc lắng nghe `event` ở directive này.
+
+Mấu chốt để tạo **Custom Structural Directive** xoay quanh ở hàm `createEmbeddedView()` của `ViewContainerRef`. Hiểu được input `TemplateRef` của hàm này từ đầu mà có, cũng như các kết quả trả ra của `Context Object`.
+
+## Concepts
+
+Bài này chủ yếu là các concepts cũ. Những concepts cần đọc như là **ViewContainerRef**, **TemplateRef**.
+
+## Exercise
+
+### 1. Implement Filter Feature like demo project
+
+Mình làm đến đây rồi, các bạn hãy thử code tiếp để hoàn thành tính năng filter theo chữ cái đầu như demo nhen. Không thì các bạn có thể tham khảo source code hoàn chỉnh ở dưới đây.
+
+## Summary
+
+Day 40 chúng ta đã học được những concepts và cách làm liên quan đến cách **Custom structural directive**.
+
+Mục tiêu của ngày 41 sẽ là những lệnh quen thuộc và các flag thường gặp trong **Angular CLI**.
+
+## Code sample
+
+- https://github.com/januaryofmine/angular-custom-structural-directive
+
+## References
+
+Các bạn có thể đọc thêm ở các bài viết sau
+
+- https://angular.io/guide/structural-directives#writing-your-own-structural-directives
+- https://medium.com/@kay.odenthal_25114/creating-a-custom-structural-directive-with-angular-7-3e85bcf88bdf
+- https://netbasal.com/understanding-angular-structural-directives-659acd0f67e
+- https://blog.cloudboost.io/creating-structural-directives-in-angular-ff17211c7b28
+
+## Author
+
+[Khanh Tiet](https://github.com/januaryofmine)
+
+`#100DaysOfCodeAngular` `#100DaysOfCode` `#AngularVietNam100DoC_Day40`
+
+[day38]: Day038-dynamic-component.md
+[day39]: Day039-custom-attribute-directive.md
diff --git a/Day041-angular-cli.md b/Day041-angular-cli.md
new file mode 100644
index 0000000..43e7c0a
--- /dev/null
+++ b/Day041-angular-cli.md
@@ -0,0 +1,230 @@
+# Day 41: AngularCLI
+
+## Introduction
+
+Hi, 40 ngày qua, các bạn đã đi chung với `Angular` 1 chặng đường rồi. Mình cảm ơn các bạn đã đồng hành với series đến đây, cũng như cùng học, đi qua những concepts khó nhằn trong Angular, Typescript, RxJS,...
+
+Hôm nay bài này sẽ là 1 trạm dừng chân, nghỉ ngơi chút, nhìn lại những gì đã học, đã làm. Nhiều câu lệnh ở đây đã được nói qua ở những bài trước, hôm nay mình sẽ tổng hợp lại.
+
+Đây sẽ là 1 cái `cheat sheet` để tham khảo nhanh, cũng như đâu đó sẽ có những flag, những cách sử dụng CLI một cách hiệu quả và tăng performance trong công việc.
+
+Chúng ta bắt đầu thôi.
+
+## Cheat Sheet
+
+### ng new
+
+Khởi tạo project mới
+
+```sh
+ ng new [options]
+ ng n [options]
+```
+
+Options:
+
+--directory=directory: Tạo project mới trong folder chỉ định.
+
+--skipInstall=true|false: Tạo project mà không install dependency (hữu ích khi mạng yếu).
+
+--packageManager=npm|yarn|pnpm|cnpm: Chọn package manager cho project.
+
+### ng generate
+
+Generate files
+
+```sh
+ ng generate [options]
+ ng g [options]
+```
+
+Shematic:
+
+> Chúng ta có thể chỉ định generate những files này bằng cách thêm tên folder vào sau. Ví dụ chúng ta muốn generate 1 component trong folder `demo\demolist`:
+
+`` sh `ng g c demo\demo-list` ``
+
+Ngoài ra generate mấy files này, các bạn nên dùng alias để gõ command cho nhanh. Đa số alias là chữ cái đầu của nó.
+
+Ví dụ: `module` là `m`.
+
+#### 1. Module
+
+`` sh `ng g module ` `ng g m ` ``
+
+Options:
+
+--routing=true|false: Tạo module với routing module.
+
+#### 2. Component
+
+`` sh `ng g component ` `ng g c ` ``
+
+Options:
+
+--export=true|false: Export component vừa tạo.
+
+--inlineStyle=true|false: Chỉ định Style nằm chung trong file.
+
+--inlineTemplate=true|false: Chỉ định HTML nằm chung trong file.
+
+--selector=selector: Tên của selector của component.
+
+--skipTests=true|false: Không generate file spec.
+
+#### 3. Service
+
+`` sh `ng g service ` `ng g s ` ``
+
+Options:
+
+--skipTests=true|false
+
+#### 4. Class
+
+`` sh `ng g class ` `ng g cl ` ``
+
+Options:
+
+--skipTests=true|false
+
+#### 5. Interface
+
+`` sh `ng g interface ` `ng g i ` ``
+
+#### 6. Directive
+
+`` sh `ng g directive ` `ng g d ` ``
+
+Options:
+
+--export=true|false
+
+--selector=selector
+
+--skipTests=true|false
+
+#### 7. Guard
+
+`` sh `ng g guard ` `ng g g ` ``
+
+Options:
+
+--skipTests=true|false
+
+#### 8. Pipe
+
+`` sh `ng g pipe ` `ng g p ` ``
+
+Options:
+
+--export=true|false
+
+--skipTests=true|false
+
+#### 9. Enum
+
+`` sh `ng g enum ` `ng g e ` ``
+
+### ng build
+
+Compile code và đưa vào thư mục `/dist`
+
+```sh
+ ng build [options]
+ ng b [options]
+```
+
+Options:
+
+--prod=true|false: Build project với production mode.
+
+--aot=true|false: Sử compiler ahead of time. (Khái niệm này sẽ nói ở những bài sau)
+
+--baseHref=baseHref: Chỉ định baseHref sẽ dùng.
+
+--deployUrl=deployUrl: Chỉ định deployment url sẽ dùng.
+
+### ng serve
+
+Build và Serve code, tự động build lại khi có sự thay đổi file.
+
+```sh
+ ng serve [options]
+ ng s [options]
+```
+
+Options:
+
+-o: Tự động mở project trong browser.
+
+--port=port: Chỉ định port sẽ dùng (default là 4200).
+
+### ng test, ng lint
+
+Chạy unit tests trong project.
+
+```sh
+ ng test [options]
+ ng t [options]
+```
+
+Options:
+
+--watch=true|false: Tự động test lại khi có thay đổi ở file.
+
+--codeCoverage=true|false: Thêm test coverage report.
+
+Chạy những linting tools.
+
+```sh
+ ng lint [options]
+ ng l [options]
+```
+
+Options:
+
+--exclude: Chỉ định những file không lint.
+
+--typeCheck=true|false: Check type cho linting.
+
+### ng version
+
+Xem version của Angular CLI.
+
+```sh
+ ng version [options]
+ ng v [options]
+```
+
+### ng update
+
+Update packages
+
+```sh
+ ng update [options]
+```
+
+## Summary
+
+Day 41 chúng ta đã học được command và flag thường dùng với Angular CLI.
+
+Mục tiêu của ngày 42 sẽ là **Angular Schematics**.
+
+## References
+
+Các bạn có thể đọc thêm ở các bài viết sau
+
+- https://angular.io/cli
+- https://malcoded.com/posts/angular-fundamentals-cli/
+- https://baswanders.com/angular-cli-cheatsheet-an-overview-of-the-most-used-commands/
+- https://www.digitalocean.com/community/tutorials/angular-angular-cli-reference
+
+## Author
+
+[Khanh Tiet](https://github.com/januaryofmine)
+
+`#100DaysOfCodeAngular` `#100DaysOfCode` `#AngularVietNam100DoC_Day41`
+
+[day39]: Day039-custom-attribute-directive.md
+[day40]: Day040-custom-structural-directive.md
diff --git a/README.md b/README.md
index ebe37c1..4556adc 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,8 @@ Series độc quyền cung cấp bởi thành viên của Angular Vietnam về c
| [Day 34: Template-driven Forms Trong Angular Part 2][day34] | |
| [Day 35: Reactive Forms Trong Angular][day35] | |
| [Day 38: Dynamic Component][day38] |
+| [Day 39: Custom Attribute Directive][day39] |
+| [Day 40: Custom Structural Directive][day40] |
| |
## Youtube Playlist
@@ -53,6 +55,7 @@ https://www.youtube.com/playlist?list=PLVmX3uPQtp3vXOXUOl8gDIA_43_pmIdFN
- [Tiep Phan][tieppt]
- [Chau Tran][nartc]
- [Trung Vo][trungk18]
+- [Khanh Tiet][khanhtiet]
[day1]: Day001-Installation.md
[day2]: Day002-AngularApp.md
@@ -90,6 +93,8 @@ https://www.youtube.com/playlist?list=PLVmX3uPQtp3vXOXUOl8gDIA_43_pmIdFN
[day34]: Day034-template-driven-forms-2.md
[day35]: Day035-reactive-forms.md
[day38]: Day038-dynamic-component.md
+[day39]: Day039-custom-attribute-directive.md
+[day40]: Day040-custom-structural-directive.md
[day1-video]: https://youtu.be/NS6P1fpU77o
[day2-video]: https://youtu.be/jgFw8tAgKNs
[day3-video]: https://youtu.be/WrMywdbnQfk
@@ -121,3 +126,4 @@ https://www.youtube.com/playlist?list=PLVmX3uPQtp3vXOXUOl8gDIA_43_pmIdFN
[tieppt]: https://github.com/tieppt
[nartc]: https://github.com/nartc
[trungk18]: https://github.com/trungk18
+[khanhtiet]: (https://github.com/januaryofmine)
\ No newline at end of file
diff --git a/assets/day038.gif b/assets/day038.gif
new file mode 100644
index 0000000..7b42421
Binary files /dev/null and b/assets/day038.gif differ
diff --git a/assets/day039.gif b/assets/day039.gif
new file mode 100644
index 0000000..955d9ec
Binary files /dev/null and b/assets/day039.gif differ
diff --git a/assets/day040.gif b/assets/day040.gif
new file mode 100644
index 0000000..338422d
Binary files /dev/null and b/assets/day040.gif differ