YAGNI JS
This is just 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 buliding interactions
Notes
YAGNI JS stands for: You Ain't Gonna Need It JavaScript
Frameworks vs libraries and how I like librarys way more
Including code directly on the page with modules
Page should be able to render anywhere
Module approach vs web components
Using query selctors and data storage
Basic CRUD functions
You could totally make this a file that gets included and that's kida 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 YAGNI Foundation Example
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])
}
}
HTML
<div class="example-alfa"></div>
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>
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()
})