imacrayon / alpine-ajax

An Alpine.js plugin for building server-powered frontends.
https://alpine-ajax.js.org
MIT License
558 stars 11 forks source link

`$ajax` on `<form method=GET>` send formData instead of queryParams #43

Closed DrSensor closed 4 months ago

DrSensor commented 8 months ago
<form method=GET @submit='
  $event.submitter.disabled = true
  $ajax("/user")
    .finally(() => $event.submitter.disabled = false)
'>
  <input type=text name=username value=myinput>
  <button>Submit</button>
</form>

It still send GET but it send FormData instead of /user?username=myinput (with empty body). https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#method

unrelevant side note try/catch didn't work on alpine
imacrayon commented 8 months ago

Dang, I thought we had a test to catch this, it might be broken. I’ll look into it tomorrow.

DrSensor commented 8 months ago

I just test the minimum example and it works. Gosh, I'm not sure what's wrong with my code. Gonna close this.

Here is the full snapshot before I refactor it to use `@ajax:{before,after,success}` ```html

Fasilitator

Durasi
```
imacrayon commented 8 months ago

I wonder if it could have something to do with that form using x-target and @submit together. x-target adds it's own submit handler, I think that could cause the form to fire off two ajax requests.

DrSensor commented 8 months ago

I tried to add x-target and yup, it perform 2 requests

  1. GET /?username=John+Smith (missing URL path)
  2. GET /user (missing URL params)

index.html

<!DOCTYPE html>
<script defer src=//cdn.jsdelivr.net/npm/@imacrayon/alpine-ajax/dist/cdn.min.js></script>
<script defer src=//cdn.jsdelivr.net/npm/alpinejs/dist/cdn.min.js></script>

<form x-init x-target=user method=GET @submit='
  $event.submitter.disabled = true
  $ajax("/user")
    .finally(() => $event.submitter.disabled = false)
'>
  <input type=text name=username value="John Smith">
  <button>Submit</button>
</form>
<div id=user></div>

server.js

#!/bin/env -S deno run -A
import { serveFile } from "https://deno.land/std/http/file_server.ts";

async function handler(request) {
  const params = new URL(request.url).searchParams;
  if (params.size == 0) return serveFile(request, "./index.html");
  return new Response(
    `<div id=user>${params.get("username")}</div>`,
    {
      headers: {
        "Content-Type": "text/html",
      },
    },
  );
}

Deno.serve({ port: 8000 }, handler);
DrSensor commented 8 months ago

That double request also happen when doing self-target https://github.com/imacrayon/alpine-ajax/issues/41

imacrayon commented 4 months ago

I tried to work out a way to support mixing x-target and $ajax, but I couldn't find a pattern that worked without negative tradeoffs. In v0.6.0 $ajax no long inherits settings from attributes, I think this implicit behavior was causing confusion for some newcomers. So you could structure the form example above to one of two ways:

With $ajax:

<form x-init @submit="
  $event.submitter.disabled = true
  $ajax('/user', { target: 'user' })
    .finally(() => $event.submitter.disabled = false)
">...</form>

Or with x-target:

<form x-init method="get"  action="/user" x-target="user">...</form>

I would recommend using x-target in this case because it will automatically handler the $event.submitter.disabled logic for you and it a bit more terse. Generally x-target works for 80% of use cases and $ajax is there when you need it.