/ Gists

Gists

On gists

Alpine reactivity like jQuery

Alpine.js

reactivity.js #

let button = document.querySelector('button')
let span = document.querySelector('span')
 
let proxy = Alpine.reactive({ color: ‘blue’ })
 
Alpine.effect(() => {
    span.textContent = proxy.color
})
 
button.addEventListener('click', () => {
    proxy.color = (proxy.color == ‘blue’) ? ‘green’ : ‘blue’
}) 

On gists

Fetch / async

Alpine.js

fetch-async-ways.js #

async function getItems() {
    let response = await fetch('/api/items/all')
    let json = await response.json()
    return json
}

<div x-text="JSON.stringify(getItems())"></div>

// or alternatively:
<div
    x-data="{
        items: {},

        async getItems() {
            this.items = await (await fetch('/api/items/all')).json();
        }
    }"
    x-init="getItems">
</div>

On gists

Alpine - magic (custom method)

Alpine.js

overlap.js #

// https://github.com/markmead/alpinejs-overlap/blob/main/src/index.js

export default function (Alpine) {
  Alpine.magic('overlap', (el, {}) => (targetId) => {
    const targetEl = document.querySelector(targetId)

    return checkOverlap(
      targetEl.getBoundingClientRect(),
      el.getBoundingClientRect()
    )
  })

  function checkOverlap(targetBounding, elBounding) {
    return !(
      targetBounding.top > elBounding.bottom ||
      targetBounding.right < elBounding.left ||
      targetBounding.bottom < elBounding.top ||
      targetBounding.left > elBounding.right
    )
  }
}

On gists

Alpine directive - slugify

Alpine.js

slugify.js #

// https://github.com/markmead/alpinejs-slug

import slugify from 'slugify'

export default function (Alpine) {
  Alpine.directive('slug', (el, { expression }, { evaluateLater, effect }) => {
    let setInputValue = evaluateLater(expression)

    effect(() => {
      setInputValue((string) => {
        el.value = slugify(string, {
          lower: true,
        })
      })
    })
  })
}

On gists

Alpine js - directive (example)

Alpine.js

example.js #

//  https://github.com/markmead/alpinejs-textarea-autogrow

export default function (Alpine) {
  Alpine.directive('grow', (el) => {
    el.addEventListener('input', () => {
      el.style.height = 'auto'

      el.style.height = `${el.scrollHeight}px`
    })
  })
}

On gists

TodoList

Alpine.js

index.html #

<!-- https://codepen.io/ryangjchandler/pen/qBOEgjg -->

<div x-data="toDoList()" class="max-w-2xl mx-auto px-12 py-8 rounded-lg shadow-lg bg-gray-200">
    <div class="flex flex-col items-center justify-center mb-8">
        <h1 class="text-3xl font-bold mb-8">
            To Do List
        </h1>
        <input type="text" x-model="newTodo" placeholder="I need to..." class="mx-auto px-4 py-2 rounded shadow text-lg min-w-full" @keydown.enter="addToDo">
    </div>
    <div class="bg-white w-full rounded shadow mb-8">
        <template x-for="(todo, index) in todos" :key="index">
            <div class="flex items-center py-4" :class="{ 'border-b border-gray-400': ! isLastToDo(index) }">
                <div class="w-1/12 text-center">
                    <input type="checkbox" @change="toggleToDoCompleted(index)" :checked="todo.completed">
                </div>
                <div class="w-10/12">
                    <p x-text="todo.todo" :class="{ 'line-through': todo.completed }"></p>
                </div>
                <div class="w-1/12 text-center">
                    <button class="bg-red-600 text-white px-2 py-1 rounded hover:bg-red-700" @click="deleteToDo(index)">
                        &cross;
                    </button>
                </div>
            </div>
        </template>
    </div>
    <div>
        <span x-text="numberOfToDosCompleted()"></span> / <span x-text="toDoCount()"></span> to dos completed
    </div>
</div>


<script>
  function toDoList() {
    return {
        newTodo: "",
        todos: [],
        addToDo() {
            this.todos.push({
                todo: this.newTodo,
                completed: false
            });

            this.newTodo = "";
        },
        toggleToDoCompleted(index) {
            this.todos[index].completed = !this.todos[index].completed;
        },
        deleteToDo(index) {
            this.todos = this.todos.filter((todo, todoIndex) => {
                return index !== todoIndex
            })
        },
        numberOfToDosCompleted() {
            return this.todos.filter(todo => todo.completed).length;
        },
        toDoCount() {
            return this.todos.length
        },
        isLastToDo(index) {
            return this.todos.length - 1 === index
        }
    };
}

  
</script>

On gists

No need remove event listener

JavaScript

examples.js #

// https://javascript.plainenglish.io/you-dont-need-removeeventlistener-to-remove-dom-event-listeners-12db93cd8bf6

// 1. once

document.querySelector('#btn').addEventListener('click', () => {
  console.log('clicked');
}, {once: true});


// 2. AbortController
const controller = new AbortController();

document.querySelector('#btn').addEventListener('click', () => {
  console.log('clicked');
}, { signal: controller.signal });

// abort the listener!
controller.abort();


// or
const controller = new AbortController();
const { signal } = controller;

document.querySelector('#btn').addEventListener('click', () => {
  console.log('clicked');
}, { signal });

document.querySelector('#btn').addEventListener('mouseenter', () => {
  console.log('mouseenter');
}, { signal })

window.addEventListener('scroll', () => {
  console.log('scroll');
}, { signal })

// Remove all listeners at once:
controller.abort();


// 3. clone element
const button = document.querySelector('#btn');
button.replaceWith(button.cloneNode(true));

On gists

Image from edge to container

Tailwind CSS CSS

index.html #

<!--
@sources
https://play.tailwindcss.com/om6YbfPx0J
https://www.setrimsmalinou.cz/
-->

<!-- FROM LEFT TO RIGHT -->
<div class="relative h-[500px] border-2 border-black">
  <!-- image -->
  <div class="absolute inset-y-0 w-1/2 bg-red-300">
    <img src="https://picsum.photos/id/237/1500/1500" class="h-full w-full object-cover object-center" alt="" />
  </div>

  <!-- container -->
  <div class="mx-auto flex h-full max-w-6xl justify-end border-2 border-green-500">
    <div class="w-1/2">Content ...</div>
  </div>
</div>

<!-- FROM RIGHT TO LEFT -->
<div class="relative h-[500px] border-2 border-black">
  <!-- image -->
  <div class="absolute inset-y-0 right-0 w-1/2 bg-red-300">
    <img src="https://picsum.photos/id/237/1500/1500" class="h-full w-full object-cover object-center" alt="" />
  </div>

  <!-- container -->
  <div class="mx-auto flex h-full max-w-6xl justify-start border-2 border-green-500">
    <div class="w-1/2">Content ...</div>
  </div>
</div>

On gists

prevAll, nextAll in pure jS (jQuery replacement)

JavaScript JS oneliners ES 6

index.html #

  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li id="selected">6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
  </ul>

On gists

Sort array by multiple values

Popular ⭐ PHP

sort.php #

<?php

// https://blog.martinhujer.cz/clever-way-to-sort-php-arrays-by-multiple-values/
// https://stackoverflow.com/questions/2699086/how-to-sort-a-multi-dimensional-array-by-value
// COMPLEX: https://stackoverflow.com/questions/17364127/how-can-i-sort-arrays-and-data-in-php
// https://stackoverflow.com/questions/44309585/properly-sorting-multidimensional-array-using-usort-and-spaceship-operator/44309755#44309755

// 1)
// order products by: price ASC, inStock DESC, isRecommended DESC, name ASC
usort($products, function (Product $a, Product $b): int {
    return
        ($a->getPrice() <=> $b->getPrice()) * 1000 + // price ASC
        ($b->isInStock() <=> $a->isInStock()) * 100 + // inStock DESC
        ($b->isRecommended() <=> $a->isRecommended()) * 10 + // isRecommended DESC
        ($a->getName() <=> $b->getName()); // name ASC
});


// 2) 
// order products by: price ASC, inStock DESC, isRecommended DESC, name ASC
usort($products, fn (Product $a, Product $b): int =>
    ($a->getPrice() <=> $b->getPrice()) * 1000 + // price ASC
    ($b->isInStock() <=> $a->isInStock()) * 100 + // inStock DESC
    ($b->isRecommended() <=> $a->isRecommended()) * 10 + // isRecommended DESC
    ($a->getName() <=> $b->getName()) // name ASC
);

// 3)
usort($products, fn (Product $a, Product $b): int =>
    [$a->getPrice(), $b->isInStock(), $b->isRecommended(), $a->getName()]
    <=>
    [$b->getPrice(), $a->isInStock(), $a->isRecommended(), $b->getName()]
);



usort($myArray, function($a, $b) {
    $retval = $a['order'] <=> $b['order'];
    if ($retval == 0) {
        $retval = $a['suborder'] <=> $b['suborder'];
        if ($retval == 0) {
            $retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
        }
    }
    return $retval;
});