LittleToDo

JavaScript HTML Components Without Frameworks

HTML

<div id="todos">

</div>

JavaScript

const Mixins = {
  // return attribute value
  getAttribute(name) {
    // if nothing on object itself, use built-in getAttribute
    if(typeof(this[name])==="undefined") {
      return HTMLElement.prototype.getAttribute.call(this,name);
    }
    return  this[name];
  },
  // set attribute on object
  // extra argument lazy=true if change should not be reactive
  setAttribute(name,value,lazy) {
    // auxiliary test function
    const equal = (a,b) => {
      const typea = typeof(a),
      typeb = typeof(b);
      // same type and one of
      return typea === typeb &&
         // identical
         (a===b ||
         // same length, size, order
        (Array.isArray(a) && Array.isArray(b) && a.length===b.length
         && a.every((item,i) => b[i]===item)) ||
         // all keys the same
         (a && b && typea==="object" &&
          Object.keys(a).every(key => equal(a[key],b[key])) &&
          Object.keys(b).every(key => equal(a[key],b[key]))));
    };
    
    let type = typeof(value),
    oldvalue = this.getAttribute(name);
    const neq = !equal(oldvalue,value);
    
    // only make changes if new and old value are not equal
    // or change is non-reactive
    if(neq || lazy) {
      // remove object property and attribute is value is null
      if(value==null) delete this[name]; this.removeAttribute(name);
      // add to object if type is object
      if(type==="object") this[name] = value;
      // otherwise, use built-in setAttribute
      else HTMLElement.prototype.setAttribute.call(this,name,value);
    }
    // render if !lazy (i.e. is reactive), renderable, value changed
    if(!lazy && this.render && neq) this.render();
  },
  // not a great id generator, but good enough for demo
  genId() {
    return "id" + (Math.random()+"").substring(2);
  } 
}
const ToDoView = function({title="",listid="",done=false},
                           el = document.createElement("todo")){
  const attributes = {title,listid,done,...arguments[0]};
 ...