Separation of Concerns
Tags: webcomponents
Published: 2022-12-31 18:26:26

One of the best things I've learned in my career is the [Separation of Concerns Principal](https://en.wikipedia.org/wiki/Separation_of_concerns) which guides us in setting up some rules for our web component (WC) library.

###Rules
Here's the first three rules we will follow:

- Use convention over configuration
- All functions or methods to have only one concern.
- Function or Method names must be carefully determined. This communicates what it does. It's a huge clue to developers down the road.

###Convention over Configuration

Our convention, in order:
 
- Declare a custom Element: <code>customElements.define(</code>
-  Define the tag name such as <code>bing-search</code> and remember it must have a hyphen. The tag name should always describe its sole function.

- Declare a class and extend from HtmlElement as shown:

```js
customElements.define(
  "bing-search",
  class extends HTMLElement {
    constructor() {
      super();
      this.initializeElements();
      this.addEventHandlers();

```
- Add a constructor with the first line being this: <code>super();</code> This is a requirement of WC.

- Create generic method names that will be used in all other WCs where needed. 

###Functions Have One Responsibility

Don't write [monolithic code](https://www.bing.com/search?q=the+problem+with+monolithic+code&cvid=309c6698340a4726820872372a61f9d1&aqs=edge..69i57j0l8.8035j0j1&pglt=297&FORM=ANNTA1&PC=EDGEDSE) unless you want a [new job](https://www.glassdoor.com/blog/things-to-do-if-you-get-fired/).

We can avoid this by using the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle);  which works at both the ECMA module layer as well as the class and function layers.

###The initializeElements Function

Notice this method initializes components by creating them and then adding them to the WC.

It does not do anything else!
```js
    initializeElements() {
      this.bingsearch = "bingsearch";
      this.input = document.createElement("input");
      this.input.id = this.bingsearch;
      this.input.title = this.bingsearch;
      this.input.type = "input";
      this.input.value = this.getAttribute("searchstring");

      this.button = document.createElement("input");
      this.button.type = "submit";
      this.button.value = "Submit";
      this.bingsearchsubmit = "bingSearchSubmit";
      this.button.id = this.bingsearchsubmit;
      
      this.appendChild(this.input);this.appendChild(this.button);
    }

```
###The addEventHandlers Function

```js
addEventHandlers() {
      this.addEventListener("change", function (ev) {
        let element = ev.target;
        if (ev.target.id == this.bingsearch) {
          this.OpenSearch();
          return;
        }
      });

      this.addEventListener("click", function (ev) {
        let element = ev.target;
        if (ev.target.id == this.bingsearchsubmit) {
          this.OpenSearch();
          return;
        }
      });
    }

```
Both of these methods are different ways of doing the same thing, that's why we have a function named OpenSearch.

###The OpenSearch Function

This function has a single responsibility, but was called in two different ways; therefore, it must be able to service both callers.

```js
    //searchPattern = "https://www.bing.com/search?q=";
    OpenSearch() {
      let searchtext = this.input.value;
      let replaced = searchtext.replace(" ", "+");
      let url = `${this.searchPattern}${replaced}`;
      let win = window.open(url);
    }
```
###The GUI

![Bing Search GUI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbkuh3a2ug5454u7k2kq.png)

###The Result

![Bing Search Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/369m2j4df1a3mt15skpz.png)

###How to Reuse this WC
In your HTML just import the bingsearch.js script, and make a reference to &lt;bing-search&gt;
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="bingsearch.js" defer></script>
    <title>Display Grid</title>
</head>
<body>
 
<h1>Bing Search</h1>
 <bing-search searchstring="single responsibility"></bing-search>
</body>
</html>
```

###The Element View

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iisjxyhpemk4zk7trnst.png)

Notice anything missing? Well yes we should always include ids and or names and titles on our custom elements.