Home Reference Source

scripts/libs/component.js

'use strict'

import { html } from './../utils/html.js'
import { uid } from './../utils/uid.js'
import { Router } from './router.js'

/**
 * This class is used to create web components
 */
export class Component {
  /**
   * The html string or HTMLElement that becomes the view for this component
   */
  get template () {
    return ''
  }

  /**
   * The method gets called whenever the state changes
   * @param {URL} url The current url
   */
  onStateChange ( url ) {}

  /**
   * The method gets called before the template is attached. This is useful for modifing the template before the MutationObserver starts tracking it or add dependencies for template elements
   */
  init () {}

  /**
   * The method gets called when the component gets created in the page. It is the main method of the class
   */
  execute () {}

  /**
   * The method gets called when the component calls destroy(). It can be used to remove handlers or clear timeouts
   */
  terminate () {}

  /**
   * Creates an instance of Component
   * @param {HTMLElement} parent The parent wrapper
   * @param {Module} module The parent module instance
   * @param {Store} store An instance of @crispcode/pushstore, see https://www.npmjs.com/package/@crispcode/pushstore
   */
  constructor ( parent, module, store ) {
    /**
     * A unique identifier
     * @type {String}
     * @public
     */
    this.uid = uid()

    /**
     * The parent wrapper
     * @type {HTMLElement}
     * @public
     */
    this.parent = parent

    /**
     * The parent module instance
     * @type {Module}
     * @public
     */
    this.module = module
    /**
     * The pushstore instance of the module parent
     * @type {Store}
     * @public
     */
    this.store = store

    /**
     * The component view
     * @type {HTMLElement}
     * @public
     */
    this.element = ( typeof this.template === 'string' ) ? html( this.template ) : this.template

    // Call the init method before the template is attached to the parent element
    this.init()

    // Append element to the dom
    this.parent.appendChild( this.element )

    /**
     * The __stateWatcher is a handler for the router, it gets destroyed when the component gets destroyed
     * @type {String}
     * @private
     */
    this.__stateWatcher = Router.onStateChange( ( url ) => {
      this.onStateChange( url )
    } )
  }

  /**
   * The method gets called when the component is destroyed
   * @private
   */
  __destroy () {
    this.__stateWatcher()
    this.terminate()
    try {
      this.element.remove()
    } catch ( e ) {}
    delete this.parent.moduxComponent
  }
}