Morphdom and MVU, don't overlook this !
Tags: mvu, javascript
Published: 2022-09-08 21:06:40

If you haven't read the first article on MVU, I invite you to do so.

Let's continue our adventures with MVU.
This time we will code a very simple counter web component.

Without any ceremony here is the definition of our component. 
As you can see, there is very little stuff in it.

```js
class MyCounter extends HTMLElement {
	constructor() {
		super()
		this.state = {
			count: Number(this.getAttribute("init")) || 0
		}
		this.append(myCounter(this))
	}
	update() {
		render(this, myCounter(this))
	}
}

customElements.define('my-counter', MyCounter);
```
In fact the most 'heavy' part is the implementation of the 'myCounter' MVU component.

Let's see how it is coded :

First let's create some helpers using the **m** function from MVU

```js
const div = m("div") // div maker
let button = m("button") // button maker 

let styleCounter = `
  display:flex
`
let styleButton = `
  color:red
`
let styleValue = `
  font-size: 24px;
  margin-left: 10px;
  margin-right: 10px;
  user-select: none;
`
const styleButtons = {style:styleButton}
```
And now the actual implementation of our 'counter' using **dom**, **udom** functions from MVU and our previous helpers

```js
function myCounter(elt) {

	let state = elt.state;

    let inc = (incr) => () => {state.count += incr; elt.update()};

	let counter = dom();
    button("inc", styleButtons).onclick = inc(1);
    div(`<div>Counter : ${state.count}</div>`, {style:styleValue});
    button("dec", styleButtons).onclick = inc(-1);
	udom();

    counter.style = styleCounter;

	return counter;
}
```
You are certainly wondering where is **morphdom** in this piece of code ?

In fact **render** is an alias for **morphdom**. 

It's called whenever we click on the buttons through the **update** method.

Let us now use our newly web component :

```html
<my-counter init="27"></my-counter>
<my-counter init="13"></my-counter>
<my-counter init="9"></my-counter>
```
I hope you see how esay it is to create a simple web component using MVU functions, no hooks, no bindings, no need to modify directly the elements...

Of course, it is not complete, but for a first try it does the job.

Here is the full code :

```js
import "https://cdn.jsdelivr.net/gh/artydev/mvu@DMLMorph/dist/mvu.es.js";

const div = m("div")
let button = m("button")

let styleCounter = `
  display:flex
`

let styleButton = `
  color:red
`

let styleValue = `
  font-size: 24px;
  margin-left: 10px;
  margin-right: 10px;
  user-select: none;
`

const styleButtons = {style:styleButton}

function myCounter(elt) {
	let state = elt.state;
  let inc = (incr) => () => {state.count += incr; elt.update()};
	let counter = dom();
	  button("inc", styleButtons).onclick = inc(1);
	  div(`<div>Counter (${state.item}) : ${state.count}</div>`, {style:styleValue});
          button("dec", styleButtons).onclick = inc(-1);
	udom();
  counter.style = styleCounter;
	return counter;
}

class MyCounter extends HTMLElement {
	constructor() {
		super()
		this.state = {
      item: this.getAttribute("item"),
			count: Number(this.getAttribute("init")) || 0
		}
  }
  connectedCallback () {
		this.append(myCounter(this))
	}
  
	update() {
		render(this, myCounter(this))
	}
}

customElements.define('my-counter', MyCounter);
```

You can test it here : [WebComponentMorphDom](https://flems.io/#0=N4IgtglgJlA2CmIBcBWALAOgBxYDQgGcBjAJwHtZZkBtABlxQCYBOW7AZnbWYDZbn2AdhQBdfADMICAjVAA7AIZhESEBgAWAFzBV8RMnM3xDyEAB4wATwC0+gK6H4JAAQQ5ETQF4AOiACMjOy+rkZgPiB2BE4EvgB8ZgD0VrZkDkYksd5yFjb2ji5uHuG0wR7wYb6aEEQA1vCaMSDxSbmp+ZlyWV3ZxCQQAA6aHQiazgDm9QDCbenOns4AFGVgAJRzsc5Zzs5QZER2yoYYAI52TpYAyvAIRJpkJAsABtTLngAkwMsAviKPKwDc3QA7m5dkCMAoYABRABuxk0ABkIAQjHInAtfLAyJDfLhFmtPBtgFtnCNnHlZvMJpppml0b5ItFfACSWSUQojHNyTMnBh2UZAXJtvz4BgKc4ANTzPwkim8uz9KAc+ALNabORfFZZRK9AZDbrdED4KI3KoGGSqPy0JDsHggL64eRKFRqABWMj0BlRmlMEDA-Xuo18Wk0-QISASCSIUDkGHdUGuEBhJAwaM0CTG6gSChImksCZhSRhdgAAgARACyCIr936WagyPTYGLGHgBDjjUFWX0chROyTXLAGJADZhzKyZIARnZNHchfMh75p7ODOPOnI2XmELT8lzHiSGwR+rAFJYkOIEAAPLL79ebywIABCM7ne9lFHuSBI8CgN+694QAA1BRYDON8hWccQvWsAgIAAL3gJBnEYNB+kvQVtjAHMxjcawEHETQkKtNCMOcLCSBwuRrD6TNCOcYj0JJRkSBg654FuJC5AMeBBVvbtzVGFEH3gZ8V17LlgCEhAkCkkSXwML5unEBxbggAwyMsHd0gWa5NDWYlOk0TdlS5XS+U0ZVSLJNwiC5JY5FIAkNlVdZnEkiyjDFGZJXmGySH+ZwzIVJUjFVL4uyM+puTpFx5l2IcWUM7ZlznYcbNxZxZNEucCBWDADCIWBqhqLkbIWPxEu8UZ+xhJ4zFHWItKcRYPhFDBvjWJDWo80UKS+RIGsePF3OEmSt3gYDQPgTVSOS+S5GHBMiAyrL5ty-KHKK2pSochZrAqiK7Hi1VSLlFNZK5WSmv8rpNG-TQ7BIIUzsFRT10KhQCAIZwK00nkXHgS9USgb6AAkABUqyhBBDlGAyqp7FESDsW57hc+HNCqggFXRLVDKqzR1GRcyTPmAztgpkJyiQwniepABBWc+mXFVfGWZlcFuqqEZmJCADkDkndFafbBmmYgFm0vcTGQBWNYAB95ecEp8c0N7tnV7k5DRW4f0mEDYEnBRtvRrnZyJ9sFH6fpjCgBYrGuhYRbl27Ndu4LlVN1XvzkBMHhFvEHf+p2LZdwy3re7tIjuMBofKeF2wTSQ0QWAByZIztTvFfuugEjUINjVPNUxrVoawUD8JA0EEe1HRARRlFMMUvvzntvVMScyCgSw3JJI3ajGcgHCgJCKKNhZ6EYFA8SnxLtn0LESCQoEiYFEkoMMaxxCUKQz2cK4xjIeBnAAVQASVI8jKLw+ACKI2gSKySONwgXuIKv3DO5XMB77Q7Yn+6AoN+88PxL2cPcBQcgJgALkJOYBzgjBA2sEtCBZo5BIGHk4IqaIYH5xNOxNBFp-CCCQLQe0Yh67OlMBWQCJ99r2iAA)