How to use MutationObserver.observe() instead of setTimeOut()
Tags: html, javascript, webdev, tutorial
Published: 2020-07-21 01:54:20

##Why not to use `setTimeOut`?
I used to use `setTimeOut` to wait until the entire JS codes are loaded so I can change the DOM.
But `setTimeOut` is unstable because JS loading time depends on browser type, internet speed and other factors. So how many seconds you should wait? It might work for your computer, but not for others...

##What is `MutationObserver`
`MutationObserver` is a useful api that can observe DOM changes, and it also supports IE11!
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v1rwa187xne53ovxrxqg.PNG)

##Basic Syntax - observer()

Here is a sample HTML - 
```html
  <ul class='myList'>
    <li>LCD writing board</li>
    <li>Paper</li>
    <li>
       Tablet
       <ul class='tabletList'>
          <li>IPAD</li>
          <li>Samsung Galaxy Tab </li>
       </ul>
    </li>
  </ul>
```

```javascript
//identity an element to observe
const myListObserver = document.querySelector(".myList");

//a callback that runs when the observer is triggered
const observer = new MutationObserver(function() {
    console.log('trigged');
});
//passing element to observer function, and `options`
observer.observe(myListObserver, {OPTIONS_OBJECT});

```
##`Options` Object
`Options` decides when to trigger the callback - 
Options List - 
```javascript
let Options = {
  childList: bool,
  attributes: bool,
  characterData: bool,
  subtree: bool,
  attributeFilter: array,
  attributeOldValue: bool,
  characterDataOldValue: bool,
}
```
**Note: One of childList, attributes, and/or characterData must be true when you call observe().**

###1. Options - `childList`
```javascript
observer.observe(myListObserver, {childList: true});
```
The callback is only triggered when immediate children nodes are added or removed.
In example HTML, if anything in `.tabletList`(nested list) is changed, then it **won't** trigger the callback.

###2. Options - `subtree`
```javascript
observer.observe(myListObserver, {childList: true, subtree: true});
```
The callback will be triggered when any child nodes inside `.myList` is added or removed.
### 3. Options - `attributes` and `attributeFilter`
```javascript
observer.observe(myListObserver, {attribute: true});
```
Execute callback when any attribute is changed
```javascript
observer.observe(myListObserver, {attribute: true, attributeFilter:['class', 'style']});
```
Execute callback when class name or style is changed.

For example, if `.tabeltList` changes name, then the callback will be triggered.

Here is the [attributes list](https://www.w3schools.com/tags/ref_attributes.asp) at w3schools.

###4. Options - `characterData`
```html
  <ul class='myList'>
    <li>LCD writing board</li>
    <li>Paper</li>
    <li>
       Tablet
       <ul class='tabletList'>
          <li>IPAD</li>
          <li>Samsung Galaxy Tab </li>
       </ul>
    </li>
  </ul>
```
```javascript
observer.observe(myListObserver, {childList: true, subtree: false, characterData: true});
```
It will execute callback if I change `Paper` text.

```javascript
observer.observe(myListObserver, {subtree: true, childList: false, characterData: true});
```
It will execute callback if I change `IPAD` text.

###5. Options - `attributeOldValue`, `characterDataOldValue`
Set to true to record previous value so callback can use.
**Note:**`attributes` will be automatically set to true if `attributeOldValue` is true.  `characterData` and `characterDataOldValue` are as same as the `attribute` ones.

##Callback
We can loop every element in mutations
```javascript
const observer = new MutationObserver(function(mutations) {
    for (let mutation of mutations) {
     case 'childList':
        break;
     case 'attributes':
        console.log(mutation.oldValue) //if attributeOldValue == true
        break;
     case: 'characterData':
        console.log(mutation.oldValue) //if characterDataOldValue == true
        break;
    }
});
```

##Using the disconnect() method
```javascript
observer.disconnect();
```
Stop to watch for mutations.
If we don't use `disconnect()`, then the watching will never stop, and might cause some memory problems.