0.3.4 • Published 3 years ago

from-html v0.3.4

Weekly downloads
15
License
MIT
Repository
github
Last release
3 years ago

from-html

JavaScript Style Guide Coverage 100%

A utility function to get element references directly from a HTML string.

Why?

Creating nested DOM elements with JS can be tedious and verbose; you either have to create and assemble them manually, or set the .innerHTML of a container element and then query for its children so that you can add event listeners etc. With fromHTML() you can do both in one go:

const {
  modal,
  cancelBtn,
  confirmBtn
} = fromHTML(`
  <div ref="modal" class="modal__overlay">
    <div class="modal__container">
      <div class="modal__content">Some message</div>
      <button
        ref="cancelBtn"
        class="modal__cancel-btn"
      >Cancel</button>
      <button
        ref="confirmBtn"
        class="modal__confirm-btn"
      >Confirm</button>
    </div>
  </div>
`)

cancelBtn.addEventListener('click', /* ... */)
confirmBtn.addEventListener('click', /* ... */)
document.body.appendChild(modal)

Or actually add event listeners directly:

const { modal } = fromHTML(`
  <div ref="modal" class="modal__overlay">
    <div class="modal__container">
      <div class="modal__content">This site uses cookies.</div>
      <button
        on="click:accept"
        class="modal__confirm-btn"
      >Accept</button>
      <button
        on="click:reject"
        class="modal__cancel-btn"
      >Reject</button>
    </div>
  </div>
`, {
  accept () {
    document.cookie = 'cookies_accepted=1'
    modal.style.display = 'none'
  },
  reject () {
    throw 'We gotta get out of this place!'
  }
})

Installation

Install as usual:

yarn add from-html

And in your JS:

import fromHTML from 'from-html'

The script can also be downloaded or directly included from unpkg.com:

<script src="https://unpkg.com/from-html"></script>

Usage

fromHTML(htmlString [, controller [, options]])

References

The values of the ref attributes will get mapped to the property names of the returned object; you can also get an array of elements (not a node list!) by appending square brackets to the ref name:

const names = ['Jane', 'John', 'Jimmy']

const { list, items } = fromHTML(`
  <ul ref="list">
    ${names.map(name => `<li ref="items[]">${name}</li>`).join('')}
  </ul>
`)

Instead of a HTML string it's also possible to pass an ID selector of a template to use:

<script type="text/template" id="my-template">
  <ul ref="list">
    <li ref="items[]">Jane</li>
    <li ref="items[]">John</li>
    <li ref="items[]">Jimmy</li>
  </ul>
</script>
const { list, items } = fromHTML('#my-template')

Events

While at it, you can also add event listeners by providing a controller object and binding its methods with on attributes:

const { button } = fromHTML(`
  <button ref="button" on="click:sayHello">Click me!</button>
`, {
  sayHello () {
    window.alert('Hello HTML!')
  }
})

The part before the colon specifies the type of the event, the part after it the method of the controller to call. Multiple events can be bound with a space-separated list:

const { button } = fromHTML(`
  <button
    ref="button"
    on="mousedown:sayHello mouseup:sayGoodbye"
  >Click me!</button>
`, {
  sayHello () {
    window.alert('Hello HTML!')
  },
  sayGoodbye () {
    throw 'Goodbye!'
  }
})

If the method name is omitted, the controller object itself will be used to handle events (assuming of course it implements the EventListener interface):

const { button } = fromHTML(`
  <button ref="button" on="mousedown mouseup">Click me!</button>
`, {
  handleEvent ({ type }) {
    switch (type) {
      case 'mousedown':
        window.alert('Hello HTML!')
        break
      case 'mouseup':
        throw 'Goodbye!'
    }
  }
})

Options

The following options can be specified:

NameTypeDefaultDescription
refAttributestringrefThe attribute to get the element references from
eventAttributestringonThe attribute denoting event bindings
removeRefAttributebooleantrueWhether to remove the reference attribute afterwards
removeEventAttributebooleantrueWhether to remove the event attribute afterwards
assignToControllerboolean|stringfalseWhether to assign the element references to the controller, or to a given property of the controller if a string is provided

For example, if you want to keep the ref attribute you might use data-* attributes for HTML compliance:

const { button } = fromHTML(`
  <button data-ref="button">Click me!</button>
`, null, {
  refAttribute: 'data-ref',
  removeRefAttribute: false
})

Assigning to the controller

Instead of an options object you can also pass a boolean as a shorthand for assignToController:

class DisposableButton {
  constructor (text) {
    fromHTML(`
      <button ref="_el" on="click">${text}</button>
    `, this, true)
  }

  mount (target) {
    target.append(this._el)
  }

  handleEvent ({ type }) {
    if (type === 'click') {
      this._el.remove()
    }
  }
}

It is also possible to pass a string to specify a property to which the references should get assigned:

class SwitchButton {
  constructor () {
    fromHTML(`
      <span ref="container">
        <button ref="onBtn" on="click">on</button>
        <button ref="offBtn" on="click" hidden>off</button>
      </span>
    `, this, 'refs')
  }

  mount (target) {
    target.append(this.refs.container)
  }

  handleEvent ({ type }) {
    const toggleHidden = el => {
      el.hidden = !el.hidden
    }

    if (type === 'click') {
      toggleHidden(this.refs.onBtn)
      toggleHidden(this.refs.offBtn)
    }
  }
}

In both cases the object to which the references got assigned will be returned (i.e. the controller itself or its specified property).

License

MIT @ m3g4p0p 2018

0.3.4

3 years ago

0.3.3

6 years ago

0.3.2

6 years ago

0.3.1

6 years ago

0.3.0

6 years ago

0.2.1

6 years ago

0.2.0

6 years ago

0.1.0

6 years ago

0.1.1

6 years ago