home ~ projects ~ socials

Introducing YAGNI JS

Head's Up

This post was from an earlier design of the site. It may or may not work as expected

This is an idea I'm playing around with. The core is that instead of a framework or a library to have a copy/pastable piece of code you can just drop on a page and get a solid foundation for building interactions

Notes

  • YAGNI JS stands for: You Ain't Gonna Need It JavaScript
  • Frameworks vs libraries and how I like libraries way more
  • Including code directly on the page with modules
  • Page should be able to render anywhere
  • Module approach vs web components
  • Using query selectors and data storage
  • Basic CRUD functions
  • You could totally make this a file that gets included and that's kinda inevitable, but the point is that it doesn't have to be. (And with the way I'm working with Neopoligen I just throw it in the content files for now and things work great and I can tweak as needed.)
  • NOTE: it looks like errors don't really show up right because of the way the blob is loaded if it's an inline module. TODO is to play around with that.

A Basic Idea

JavaScript

function addToF(parent, tag, attrs = {}) {
  const target = getElF(parent)
  if (target) {
    const el = document.createElement(tag)
    updateAttrsF(attrs, el)
    target.appendChild(el)
    return el
  }
}

function errorF(msg) {
  console.error(`${Date.now()} - ERROR: ${msg}`)
}

function getElF(target) {
  if (typeof target === "string") {
    const el = document.querySelector(target)
    if (el) { return el } 
    else { 
      errorF(`Could not find querySelector for: ${target}`)
      return undefined 
    }
  } 
  else if (target) { 
    return target 
  } 
  else { 
    errorF(`Could not get element: ${target}`)
    return undefined 
  }
}

function getStorageF(key, defaultValue = undefined) {
  return localStorage.getItem(key) 
    ? JSON.parse(localStorage.getItem(key)).payload
    : defaultValue
}

function logF(msg) {
  console.log(`${Date.now()} - INFO: ${msg}`)
}

function setStorageF(key, value) {
  localStorage.setItem(key, JSON.stringify({ payload: value }))
}

function updateF(target, attrs = {}) {
  const el = getElF(target)
  if (el) {
    updateAttrsF(attrs, el)
  }
  return el
}

function updateAttrsF(attrs, el) {
  const nonAttrs = ['classes', 'data', 'listeners'] 
  for (let key in attrs) {
    if (!nonAttrs.includes(key)) {
      el[key] = attrs[key]
    }
  }
  for (let index in attrs.classes) {
    el.classList.add(attrs.classes[index])
  }
  for (let index in attrs.data) {
    el.dataset[attrs.data[index][0]] = attrs.data[index][1]
  }
  for (let index in attrs.listeners) {
    el.addEventListener(attrs.listeners[index][0], attrs.listeners[index][1])
  }
}

Basic Example

HTML

<div class="example-alfa"></div>

Output

JavaScript

function initAlfaF() {
  addToF('.example-alfa', 'button', {
    innerHTML: "0",
    classes: ['green'],
    data: [ ['current', 0] ],
    listeners: [['click', (event) => {
      let value = parseInt(event.target.dataset.current, 10)
      value += 1
      event.target.dataset.current = value
      event.target.innerHTML = value
    } ]]
  })
}

document.addEventListener("DOMContentLoaded", async () => {
  initAlfaF()
})

More Complicated Example

Here's a more complicated example that shows interaction between elements and using local storage.

HTML

<div class="example-bravo"></div>

Output

JavaScript

function initBravoF() {
  const defaultValue = 0

  addToF('.example-bravo', 'button', {
    innerHTML: "-",
    listeners: [['click', (event) => {
      setStorageF('counter', getStorageF('counter', defaultValue) - 1)
      updateF(getElF('.counter'), { 
        innerHTML: getStorageF('counter'), 
      })
    }]]
  })

  addToF('.example-bravo', 'button', {
    classes: ['counter'],
    innerHTML: getStorageF('counter', defaultValue)
  })

  addToF('.example-bravo', 'button', {
    innerHTML: "+",
    listeners: [['click', (event) => {
      setStorageF('counter', getStorageF('counter', defaultValue) + 1)
      updateF(getElF('.counter'), { 
        innerHTML: getStorageF('counter'), 
      })
    }]]
  })
}

document.addEventListener("DOMContentLoaded", async () => {
  initBravoF()
})
-- end of line --