GithubHelp home page GithubHelp logo

imacrayon / alpine-ajax Goto Github PK

View Code? Open in Web Editor NEW
369.0 3.0 7.0 2.69 MB

An Alpine.js plugin for building server-powered frontends.

Home Page: https://alpine-ajax.js.org

License: MIT License

JavaScript 97.87% HTML 2.13%
hacktoberfest ajax alpinejs fetch html javascript hateoas hypermedia forms utilites

alpine-ajax's Introduction

Alpine AJAX

A set of AlpineJS directives that enable forms and links to make asynchronous HTTP requests and render the response to the page.

Learn more at alpine-ajax.js.org.

Contributing

Clone this repo and run npm install to get started.

npm run build will build a fresh version of the library in /dist.

npm run watch will watch for file changes and rebuild the library.

Documentation

The documentation site is hosted at https://alpine-ajax.js.org, the source files are located in /docs.

npm run start will locally server the documentation site built with Eleventy. The site automatically bundles the latest Alpine AJAX build in /docs/js/main.js.

Testing

Tests are located in /tests.

npm run test will run the test suite in the Cypress CLI.

npm run cypress will open the Cypress browser UI.

Sponsors

Moonbase Labs

alpine-ajax's People

Contributors

adamchainz avatar bgilhome-now avatar hirasso avatar imacrayon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

alpine-ajax's Issues

like hyperscript that way to add

Hi @imacrayon

First picture is htmx + hyperscript.
image

Second picture is alpine + alpine ajax
image

I saw they have difference, hyperscript seems not use the openmodel function, and add class directly, and you have openmodal this function involved, just wondering whether you need to add modal library as well, just not sure where it comes from, and just wondering if I want to use add class that way, is it possible, if that works, how to do?

Thanks
Eric Xin

Inline Validation pattern

I'd like for this project to support a clean way to perform inline validation. I've got a prototype working but it requires some gnarly code in x-data. I think it will probably need to be handled with a new directive.

Use ajax:success to preload assets (js)

If the response is ok, the event ajax:success get's fired. I use this event to search in the markup for missing Alpine JS Plugins. As the plugins must have been loaded before the markup appears on the page, it would be nice to have a preventDefault option with a function in details who can be called to continue the work.

Pseudo-Code

window.addEventListener('ajax:success', (event) => {
   event.preventDefault();
   const html = event.detail.response.html
   // do the needed stuff

   
   event.detail.render();
})

Like that It would be even possible the alter the markup:

window.addEventListener('ajax:success', (event) => {
   event.preventDefault();
   const html = event.detail.response.html
   // do the needed stuff

   
   event.detail.render(html);
})

TypeError in latest version

Hi there, and thank you very much for all your effort on this great plugin!

Unfortunately i'm running into the following error on the latest version when using x-target, seems to be related to a recent feature.

TypeError: can't access property "hasAttribute", event.submitter is null

if (event.submitter.hasAttribute("formnoajax")) {
      return;
}

New links are not progressively enhanced

Links added to the DOM after an Ajax component is initialized are not progressively enhanced.

The work around for now is to add thex-ajax directive to new links. The directive will trigger an Alpine component to re-initialize.

Throw an error when targets are nested

Based off discussions in #28 it would be nice if Alpine AJAX warned developers when they are targeting two elements where one is nested within the other. Right now you'll see a confusing warning about the child target missing from the response.

Before logging a warning here we can check if the current target is a child of another target.

Can't self target on `<form>` when it has `x-merge`

I found out x-target cannot be blank (self-target) on <form> when there is x-merge. For example:

<form id=user x-init x-target x-merge=after method=post action=/create/users>
  <button>Create</button> <!-- Uncaught (in promise) Missing Target: #[object HTMLInputElement] was not found in the current document. -->
</form>

Is this intentional?

(I've not yet test for other x-merge pattern)

SSE

Maybe allow for a modifier only on GET like x-target.sse that setup an event source. I'm using SSE in htmx and would like to experiment with a similar approach in "pure"Alpine

SSE and websockets support

Hey, first of all I want to say that this is a great project. HTMX is great but this feels so easier to use especially if one is already using alpinejs.
I was wondering if there is a recommended way to handle sse and websockets just like there are extensions in HTMX ?
Another nice thing would be something like hx-boost so that no extra library is needed to create an spa like feel when navigating to different urls.

for reference:

Change focus default

Since v0.1 keyboard focus automatically moves to the first focusable element in a target when that target changes on the page. I think this default may be too heavy-handed.
You can disable focus behavior using initial-focus=“false” and I’ve found myself using that a lot so that I can have finer focus control.
Maybe the focus behavior should default to “false” and then when you want to focus something you can opt-in by setting initial-focus?

Document x-alpine-request header

I brought up headers whilst comparing alpine-ajax versus htmx with my team, but found nothing in the docs. However checking the source code reveals the x-alpine-request header:

headers: { 'X-Alpine-Request': 'true' },

It would be good to document it.

History push on x-target event

Hi, I was playing with this today, and I like it so far, so thank you :)

If I enhance links (a la wire:navigate or htmx-boost) or use alpine ajax for filtering (involving get queries), is it on me to manually manage history / push/replace URLs, or do I have an error in the code? I haven't found anything about the history in the docs

Example using ChartJS

I have been trying to get ChartJS integration working to display host metrics using AJAX requests. However, I have not been able to find examples with this use case. Assume we make an API call that returns JSON data displaying CPU metrics in the following format when making a get request to /nodecpustats:

"KernelSet":true,"Kernel":501435,"UserSet":true,"User":443484,"IdleSet":true,"Idle":112996834,"IowaitSet":true,"Iowait":5197,"IntrSet":true,"Intr":0,"UtilizationSet":true,"Utilization":95011600}

How can we display the Utilization metric as time series data using Alpine+ChartJS? How can we make the chart reactive and smooth scroll? Any help would be appreciated.

x-ref replace x-target

Hi @imacrayon

Do you think you would have x-ref available to replace x-target in next version, since I may not have id for target element, but I would have x-ref for target element.

Thanks
Eric Xin

Could not find a declaration file for module '@imacrayon/alpine-ajax'

Could not find a declaration file for module '@imacrayon/alpine-ajax'. 'c:/Users/Michaylen/Desktop/laravel-app/node_modules/@imacrayon/alpine-ajax/dist/module.cjs.js' implicitly has an 'any' type.
Try npm i --save-dev @types/imacrayon__alpine-ajax if it exists or add a new declaration (.d.ts) file containing declare module '@imacrayon/alpine-ajax';ts(7016)

VS Code

Dropzone.js Usage?

Hi, is this something that could be used with Dropzone.js?

I have a Dropzone form that opens a modal when Dropzone fires the success event. Rather than returning JSON from my backend, parsing it, and updating the Modal info (which is my current approach, and rather tedious), I wanted to use this, to return an html snippet that would fill the modal.

Being a JS novice, I wasn't able to figure out a way to do this. Maybe it's a Dropzone limitation?

Thanks!

Bug when target is a tr

It seems that the current version of alpine-ajax doesn't work if the element to be replaced is a tr.

I believe this is because of this line:

let fragment = document.createRange().createContextualFragment(response.html)

Specifically, creating the fragment doesn't work:

document.createRange().createContextualFragment('<tr id="someid"></tr>').getElementById("someid")

return null.

So when we try to update a tr, we get "Target #someid not found in AJAX response."

Make a GitHub Action build step

I'm a JavaScript package noob and I've been manually building and committing the /dist directory with each release. I'd like some help with a GitHub Action to take care of the builds so we can add /dist to the .gitignore.

Redirects don't work

If a POST send a 302 it should support changing the window.location. This can happen for example with a validated form instead of returning an updated form with errors it sends the user to the newly created resource.

Apply different merge strategy per target

Hi there, first thanks for this library it is really nice to use and well made!

One of my use case is that, a response from the API would have multiple targets which this allows.
However one might be to replace the form with an empty one, and the other one to add an element to a list let's say.

I am currently returning the full list again then I don't have the issue but was wondering if there's a way with this library to say id X will merge and id Y will replace (default)

Thanks

Rename x-arrange to x-merge

Based on a conversation with @delaneyj renaming x-arrange to x-merge might make it more clear that the attribute is meant to be added to the target, not the initiator.

Question on passing CSRF tags for Django

Great project! Django creates a CSRF token that needs to be passed when sending POST requests from the client.

An example of how you might handle this with HTMX would something like the following:

<div class="article-page" hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>

Is there a way to do something similar with alpine-ajax?

web component solution

Hi @imacrayon

Just wondering whether you can provide me a suggestion, if I am using alpine, and I need web component for it, which framework or library I can use to build with?

Like web component as template, and I can use it together, something like that.

Thanks
Eric Xin

No cleanup on window

listenForSubmit(window) && listenForNavigate(window) both return cleanup functions that are never run.

Infinite Scroll pattern

Infinite scroll is tricky because it requires that we append new server content rather than replace it. In the interest of keeping things simple I intended to allow only replacing DOM content in Apline AJAX, but it looks like we might need to support additional ways to add content to the page.

`MissingIdError` error thrown when using `x-target.replace` without an ID

Hey @imacrayon,

thank you for all the work you put into this plugin! Really appreciate it!

I found a small bug – I have a form that looks like this:

<form x-init x-target="customer-table" x-target.replace></form>

Everything works as expected, but I get this error in the console:

Uncaught Missing ID: <form x-init="" x-target="customer-table" x-target.replace=""> is missing an ID to target.

When I add an id to the form, the error disappears. If the ID is required, the docs should probably tell this – but I don't think it's required, because everything works? 🤔

Maybe you can have a look.

TIA & Greetings from Germany!

Update the URL when form GET requests are made

A form issuing a GET request will change the query string in the current URL. It would be good if AJAX-enabled forms would also update the URL so pages work the same way with or without JavaScript.

Uncaught (in promise) Missing Target: #[object HTMLButtonElement] was not found in the current document.

I want to try out Alpine-ajax, but I can't get it to work. I have installed it by including it in the head of my HTML file. All seems to work until I interact with the page, and I get an error:

Uncaught (in promise) Missing Target: #[object HTMLButtonElement] was not found in the current document.
    E https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js:1
    j https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js:1
    j https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js:1
    r https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js:1
[cdn.min.js:1:8310](https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js)
    r https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js:1

Screenshot of the error:
Screenshot from 2024-03-19 19-23-12

I tried to reproduce the toggle example but this error has stumped me.

I am using Bun and Elysia for serving my code and i made a repository to reproduce this error:
https://github.com/hansaskov1/alpine-ajax-button

The entire source code is also here.

import { Elysia } from "elysia";
import { html } from "@elysiajs/html";

const Head = ({ children }: { children: undefined | {} }) => (
    <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>Document</title>

            {/* Alpine and Alpine Ajax */}
            <script defer src="https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js"></script>
            <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>

        </head>
        <body>
            {children}
        </body>
    </html>
);

const LikeButton = ({ id }: { id: string }) => (
    <form id="like" x-init x-target method="post" action={`/comments/${id}/like`}>
        <button name="id" value={id}>Like</button>
    </form>
)

const UnlikeButton = ({ id }: { id: string }) => (
    <form id="like" x-init x-target method="delete" action={`/comments/${id}/like`}>
        <button name="id" value={id} x-autofocus>Unlike</button>
    </form>
)

const app = new Elysia()
    .use(html())
    .get("/", () => (
        <Head>
            <LikeButton id={"1"} />
        </Head>
    ))
    .delete("/comments/:id/like", ({ params }) => (
        <LikeButton id={params.id} />
    ))
    .post("comments/:id/like", ({ params }) => (
        <UnlikeButton id={params.id} />
    ))

    .listen(3000);

console.log(
    `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`
);

Here is the rendered html from the browser

<html lang="en" class=" mrcjhi idc0_350">
   <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <script defer="" src="https://cdn.jsdelivr.net/npm/@imacrayon/[email protected]/dist/cdn.min.js"></script><script defer="" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
   </head>
   <body>
      <form id="like" x-init="" x-target="button" method="post" action="/comments/1/like">
          <button name="id" value="1">Like</button>
      </form>
   </body>
</html>

Could someone please help me understand and resolve this issue?

`x-target` - "forcing" the use of ID

Is there a reason the x-target is found via getElementById, rather than querySelector, this allowing use of body as the target (or even a class like js-whatever-target?

Add support for loading indicators

There's a need to add loading indicators when network requests are slow. I think this will require a new directive. My initial thoughts are that it would work like this:

<template x-busy>
<img src="loading.svg" alt="Loading">
</template>

This template content would show only when AJAX is processing a network request. I'm open to bikeshedding other attribute names other than x-busy.

Infinite scroll issue

Hi,

First, thank you for your work.

I am having trouble with infinite scroll implementation.

As it is, I get a Target #pagination not found in AJAX response.error logged, and the same page tow loaded again and again as I scroll…

<section id="articles"
    class="grid items-start sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6"
    x-data x-masonry.wait.100 x-arrange="append">

        {{ collection from="journal" sort="date:desc" paginate="25" as="billet" }}

            {{ billet }}
                {{ partial src="brick" preset="{view:glide_presets | shuffle | first}" }}
            {{ /billet }}

            {{ paginate }}
                <div class="" id="pagination" x-init x-intersect="$ajax('{{ next_page }}', {events: 'true'})"
                    x-target="articles pagination" @ajax:success="$dispatch('reload:masonry')">
                </div>
            {{ /paginate }}

        {{ /collection }}
</section>

I am using Statamic to display entries, and the way the pagination works, the pagination loop has to be inside the collection entries loop. Or, I have noticed that in your example https://alpine-ajax.js.org/examples/infinite-scroll/, the pagination is outside the target table body where the new elements are loaded and added.
I suppose this explains that, perhaps? But I do not understand why the plugin could not find the #pagination, wherever it is in the markup?

If I duplicate the {{ collection }} loop, once with the entries, and once with the pagination, outside of the target, it kinda works, but feels "messy".

Any inputs/ideas?

Thanks in advance for your thoughts.

Decouple Alpine.morph from package

The Alpine UI components required the Focus Plugin to be included separately. This project could follow the same pattern the Morph Plugin dependency:

<script defer src="https://unpkg.com/@imacrayon/[email protected]/dist/cdn.min.js"></script>
<script defer src="https://unpkg.com/@alpinejs/[email protected]/dist/cdn.min.js"></script>
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>

I feel like the Morph Plugin isn't as commonly used as the Focus Plugin and that was my initial reasoning for bundling it in Alpine AJAX, but I'm happy to decouple it if there's enough interest in that.

spa

Hi @imacrayon

Sorry for another question, I am too new to Alpine.

I used to use vue3, and I am tired of doing spc and webpack/vite, I have to use vue3 since SPA.
Alpine seems very similar to vue, but I am not sure how to use Alpine for spa way.

Would you please give me some instructions?

Thanks
Eric Xin

Calling $ajax from code outside of Alpine.js

Currently it is not possible to call the $ajax functions outside of Alpine.js

Would it technically be possible to have exported theese functions so that they will be usable outside of Alpine.js?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.