# View Encapsulation
Angular cung cấp tính năng `View Encapsulation` với mục đích đóng gói và làm tăng khả năng tái sử dụng của các components.
## Shadow DOM
Đây là một API của HTML, cho phép tạo ra các phần tử độc lập trên trang web. Chúng không thể bị can thiệp bởi stylesheet hay JS từ bên ngoài và ngược lại. Ví dụ thẻ `<video>`, `<iframe>`...là một trong những shadow DOM.
Một shadow DOM sẽ bao gồm các thành phần:
* **Shadow host**: Là một phần tử DOM thông thường, nơi mà shadow DOM được gắn vào.
* **Shadow tree**: Bao gồm toàn bộ nội dung HTML (DOM tree) của shadow DOM.
* **Shadow boundary**: Giới hạn phạm vi của một shadow DOM.
* **Shadow root**: Là root note của toàn bộ shadow tree.
### Create shadow DOM
Để tạo một shadow DOM chúng ta có thể sử dụng phương thức `attachShadow` được hỗ trợ trong HTML5.
* Định nghĩa template cho element:
```htmlembedded
<template id="my-element">
<style>
.inner {
color: red;
}
</style>
<div class="inner">
This content is inside the shadow DOM
</div>
</template>
```
* Tạo và attach shadow DOM:
```htmlmixed
<script>
class MyElement extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
const template = document.getElementById('my-element');
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('my-element', MyElement);
</script>
```
Ở đây, chúng ta tạo một [custom element ](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements), shadow DOM sẽ được attach trực tiếp lên element đó. Chúng ta cũng có thể attach shadow DOM lên một element bất kỳ thông qua phương thức `attachShadow` của nó:
```htmlmixed
<script>
const shadowHost = document.querySelector('#shadow-host');
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<span>Inside shadow DOM</span>';
</script>
```
### Using shadow DOM
Tương tự như các thẻ cơ bản khác của HTML, để sử dụng shadow DOM chúng ta chỉ cần gọi:
```htmlembedded
<my-element></my-element>
```
Trình duyệt sau đó sẽ render ra nội dung tương ứng:
```htmlembedded
<my-element>
#shadow-root
<style>
.inner {
color: red;
}
</style>
<div class="inner">
This is inside the shadow DOM
</div>
</my-element>
```
Shadow host trong trường hợp này là `<my-element></my-element>`, mỗi một phần tử sẽ có một `shadowRoot`, toàn bộ nội dụng HTML trong `template` sẽ được quản lý bởi shadow root này.
Nội dung của thẻ `div.inner` sẽ không bị tác động bởi stylesheet hay JS bên ngoài, nó chỉ chịu sự tác động bởi các thay đổi diễn ra bên trong `<my-element>`.
Qua ví dụ trên, chúng ta cũng phần nào hiểu được cơ chế attach directive trong Angularjs. Với các restrict: `A`, `E`, `C`, `M`, Angularjs sẽ xác định một directive sẽ được attach lên những phần tử nào trên trang web.
## Angular View Encapsulation
Trong Angular, chúng ta có thể đóng gói một component thông qua view encapsulation modes:
* `ViewEncapsulation.ShadowDom`: Angular sử dụng Shadow DOM API như đã nói ở trên. Đây là mức độ đóng gói cao nhất của component.
* `ViewEncapsulation.Emulated`: Với mode này, Angular sẽ add thêm attribute vào tất cả các element thuộc DOM tree của component:
```htmlembedded
<hero-details _nghost-pmm-5>
<h2 _ngcontent-pmm-5>Mister Fantastic</h2>
<hero-team _ngcontent-pmm-5 _nghost-pmm-6>
<h3 _ngcontent-pmm-6>Team</h3>
</hero-team>
</hero-details>
```
Từ đó đảm bảo việc apply stylesheet sẽ chỉ có tác động trong phạm vi của component:
```sass
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
}
h3[_ngcontent-pmm-6] {
background-color: white;
border: 1px solid #777;
}
```
Tuy nhiên, các phần tử trong component vẫn có thể bị tác động bởi các script JS bên ngoài.
* `ViewEncapsulation.None`: Component sẽ không được đóng gói, nghĩa là nó sẽ bị tác động bởi các stylesheet và JS bên ngoài. Ngược lại, stylesheet và JS bên trong component cũng có thể ảnh hưởng đến bất kỳ phần tử nào trên trang web.
### Mixing encapsulation modes
Khi có nhiều component lồng nhau, mỗi component lại có encapsulation mode khác nhau thì chúng sẽ hoạt động như thế nào? Hiểu đơn giản, encapsulation mode cũng có scope tương tự như variable scope trong JS.
Theo đó `block scope`, `function scope` và `global scope` sẽ tương ứng với 3 mode `ShadowDom`, `Emulated` và `None` ở trên. Từ đây có thể biết được, các mode sẽ có tác động lên nhau như thế nào trong từng trường hợp.