Quick Note

We will introduce htmx through a series of changes and potential debugging, so there are intentional moments where you are suppose to feel confused.



I want you actively engaged in learning. So try to guess why things are not working or working oddly



I may mess up and accidentally correctly program something... if that happens i'll have to undo that part :)
















Forget you will

forget everything you have learned up until now, unless what you have learned PHP from 10 years ago, that will probably help you.

  • We will use URLs today... i know a bit scary
  • We will use HTTP Status Codes... HTTP Status Code Tom Foolery
  • We will even use HTTP Verbs, GET, POST, DELETE...
  • We will use as little dependencies as possible
    • i want this course about HTMX, not about other techs















Time to build server!

SIDE NOTE If you are adept and know how to launch a server in your favorite language and know how to:

  • produce HTML on the server
  • respond with various status codes
  • make routes with params in them (i.e.: /contacts/:id)
  • read query params
  • create verb based routes: GET, POST, DELETE


Then feel free to use the server/templating of your choice, because this isn't very complicated server activity. We will not be using even sqlite for storage.
















Where do we start?

I suppose the beginning would be good

Lets create a very simple http web server + an index page and then upgrade it to use htmx

mkdir views
touch views/index.html
vim . # or use whatever text editor that isn't cool


Side Note

I know templates are not sexy in todays world. They are simple, and can become annoying. Fully agree. I intentionally chose templates for the reason stated above, they are simple and require almost no understanding to follow along. This is an HTMX course, not a "here is a cool templating language and now lets learn that" course



Which also means i'll try to keep everything in one file and i will try to be as grug brain as possible while programming



If you want a cool templating feature with go that is typesafe, check out Templ. Super cool, allows for code like the following in go! And the typesafety is great, the auto complete is pretty dang good too.

package views

import "strconv"

templ Index(count int) {
    <html>
        <head>
            <title>Our First HTMX Site!</title>
        </head>
        <body>
            Count {strconv.Itoa(count)}
        </body>
    </html>
}


Ok back to our regularly scheduled programming, simple html site! First, just the html required! (views/index.html).



TASK

  • display a count that represents how many times the page has been requested.















In case I forget how to code in my favorite programming language: html

views/index.html

<html>
    <head>
        <title>Our First HTML Site!</title>
    </head>
    <body>
        Count {{ .Count }}
    </body>
</html>















Setting up the server

We will use echo... I know shut up, everyone has their favorite server, this one is just simple and is great to use for this

go get github.com/labstack/echo/v4
go get github.com/labstack/echo/v4/middleware
touch cmd/main.go

SIDE NOTE

if you see the following error, execute go mod tidy after importing echo

Common Go Error
















In case I forget

package main

import (
    "html/template"
    "io"

    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
)

type Template struct {
    tmpl *template.Template
}

func newTemplate() *Template {
    return &Template{
        tmpl: template.Must(template.ParseGlob("views/*.html")),
    }
}

func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
    return t.tmpl.ExecuteTemplate(w, name, data)
}

type Count struct {
    Count int
}

func main() {

    e := echo.New()

    count := Count{Count: 0}

    e.Renderer = newTemplate()
    e.Use(middleware.Logger())

    e.GET("/", func(c echo.Context) error {
        count.Count++
        return c.Render(200, "index.html", count)
    });

    e.Logger.Fatal(e.Start(":42069"))
}















s/html/htmx

Ok! Lets get into the ackshual course!



Lets do the following:

  • add an endpoint POST /count to that increments the count value and returns the index.html page
  • remove the incrementing in the GET / route
  • add a button to the html















Code Updates

    e.GET("/", func(c echo.Context) error {
        return c.Render(200, "index.html", count)
    });

    e.POST("/count", func(c echo.Context) error {
        count.Count++
        return c.Render(200, "index.html", count)
    });

views/index.html

<html>
    <head>
        <title>Our First HTML Site!</title>
        <script src="https://unpkg.com/htmx.org/dist/htmx.min.js"></script>
    </head>
    <body>
        Count {{ .Count }}
        <button hx-post="/count">Moar Count</button>
    </body>
</html>















What in the world has happened?

I don't think i like these results... What is going on?



I think its time to introduce HTMX in a more structured way... don't you think?
















Principle: HATEOAS

  • Hypermedia As The Engine Of Application State
  • Does that mean HTML is finally a programming language?
  • Does that mean I am an HTML Engineer?


Its existed for a long time HATEOAS Circa 2011
















Excalidraw how htmx works

The easiest way to understand htmx is to see it drawn out
















Common Arguments

Aren't servers suppose to respond with JSON?

  • What if I need a different view?
  • Why would my server understand the representation of the client?


1. Accept Header

You get your cake and you can eat it too.

Accept Header Accept MDN Headers Page

2. An important concept about state

In general, every time you take a state and interpret it you have a chance for business logic bug

Current Approach

  1. your server knows the state and produces a "view" into it (json being most popular)
  2. that view is transfered across the turtles
  3. that view is then decoded by the client (typically JSON.parse)
  4. reconcile current state to new state
  5. determine what views should be updated

HTMX Approach

  1. your server knows the state and produces a "view" (html)
  2. that view is transfered across the turtles
  3. that view is then decoded by the htmx and placed according to the rules set on the originating element
  • this contains a slight lie


Isn't producing HTML Slow?

  • No, its quite simple why


Seems like HTMX is for backend devs

  • No serious UI/UX engineer would use htmx.... right?















HTMXify: One more time

Any element can have attributes that trigger htmx interactivity.

<div hx-get="/some/resource">
</div>


What happens

  1. htmx will bind an onClick handler on the div above
  2. when the div is clicked a GET request will be made to /some/resource
  3. when the server responds the contents of div will be swapped out and replaced with the servers response















So what happened and lets fixed it!

  • lets debug what happened
  • lets fix the issue!















Do we like this?

Well... its not "efficient" ... lets make it efficient?

  • lets first remove all the extra html
  • lets reduce it down to just count