https://www.npmjs.com/package/axette
Very simple and lightweight AJAX implementation for Nette. Axette = AJAX for Nette!
- Lightweight (1kb gzipped, 3kb minified)
- Blazingly Fast
- No dependencies (no jQuery!)
- Simple to use
- Just import it, call
const axette = new Axette()
and you're done!
- Just import it, call
- Supports links and forms (
<a>
and<form>
tags) to be handled by AJAX - Handles snippet updates (
$this->redrawControl()
) as well as redirects ($this->redirect()
) - Automatically executes JavaScript inside
<script>
tags in the snippets returned from AJAX requests - Get rid of
?_fid=6ge7
in the URL when using Flash Messages - Attach custom callbacks to various events (
beforeInit
,afterInit
,beforeAjax
, etc...)
npm install axette
pnpm install axette
yarn add axette
bun add axette
# or
bun install axette
Download the latest release, move axette.iife.js
from the dist/
folder somewhere to your project and include it in your HTML or Latte file via a <script>
tag.
<!DOCTYPE html>
<html>
<head>
<title>Axette - AJAX for Nette!</title>
</head>
<body>
...
<!-- Local version -->
<script src="./path/to/axette.iife.js"></script>
OR
<!-- Via CDN -->
<script src="https://unpkg.com/axette@latest/dist/axette.iife.js"></script>
<!-- Your other scripts here... -->
</body>
</html>
Axette 2.x is a partial rewrite of the original 1.x version. It tries to keep the same API as much as possible, but there are some breaking changes.
Axette
is now a class instead of an object and is a named export instead of default export. This means that you need to import it like this:
// Change this:
import axette from 'axette';
// To this:
import { Axette } from 'axette';
- You can now use any CSS selector for custom AJAX handlers and not just a class, so you can use for instance data-attributes instead. It's also not defined in the
init()
method anymore, but in theAxette
class constructor. So if you want to use[data-ajax]
instead of.ajax
class, you'd do it like this (no need to callinit()
as that's called automatically in the constructor):
import { Axette } from 'axette';
// Change this:
axette.init('ajax'); // note that here you can define only a class name
// To this:
const axette = new Axette('[data-ajax]'); // here you can define any CSS selector
// You can also use multiple selectors like this:
const axette = new Axette('.ajax, [data-ajax]');
<a n:href="update!" data-ajax>Update snippets</a>
Or call it empty to use the default class name .ajax
like before:
const axette = new Axette();
// Is equivalent to this in the 1.x version:
axette.init();
- It is now possible to change the CSS selector after the
Axette
instance is created. So if you want to use a different selector after already using the original one, you can do so like this:
import { Axette } from 'axette';
const axette = new Axette('.old-selector');
// Do some stuff...
axette.setSelector('.new-selector'); // Beware that this will call the `init()` method again, so your init hooks (beforeInit, afterInit) will be called again
- To remove the
?_fid=XXXX
in the URL when using Flash Messages, you now need to import thenoFlashUrl()
function without having to import Axette as well, instead of callingfixUrl()
method on the axette object:
// Change this:
axette.fixUrl();
// To this:
import { noFlashUrl } from 'axette';
noFlashUrl();
Add ajax
class to the links or forms that you would like to handle via AJAX:
<a n:href="update!" class="ajax">Update snippets</a>
And in your index.js
or other JavaScript file you just import Axette
and initialize it:
import { Axette } from "axette"
const axette = new Axette();
And that's it! The class constructor handles everything.
If you'd like to use some other class for your links, you just pass the name of the class as a parameter in the constructor. So if for instance you want your AJAX links to have custom-class
instead of ajax
, then you'd do it like so:
index.html
:
<a n:href="update!" class="custom-class">Update snippets</a>
index.js
:
import { Axette } from "axette"
const axette = new Axette('.custom-class'); // The selector can be any valid CSS selector
// You can also use multiple selectors like this:
const axette = new Axette('.custom-class, [data-ajax]');
If you have some event listeners that you're adding on the DOMContentLoaded
event or similar and you want them to work even after an AJAX request, you will have to wrap them in a function and pass it as a hook to axette
, to have them re-registered after the AJAX request is received. You can do that using the .on()
method. So if you have something like this:
document.addEventListener(`DOMContentLoaded`, () => {
const buttons = document.querySelectorAll(`.btn`)
buttons.forEach(button => {
button.addEventListener(`click`, e => {
e.preventDefault()
// ...
})
})
})
You'd wrap it in a function and pass that function as a parameter to the .on()
function like so:
import { Axette } from "axette"
function registerButtons() {
document.addEventListener(`DOMContentLoaded`, () => {
const buttons = document.querySelectorAll(`.btn`)
buttons.forEach(button => {
button.addEventListener(`click`, e => {
e.preventDefault()
// ...
})
})
})
}
const axette = new Axette()
axette.on(`afterAjax`, registerButtons)
Or you could directly call onBeforeAjax()
, onAfterAjax()
, onBeforeInit()
or onAfterInit()
with the function reference, optional arguments and optional ID like this:
axette.onAfterAjax(registerButtons)
// or with the ID and arguments:
axette.onAfterAjax(registerButtons, [arg1, arg2], 'my-id')
// or with the ID only:
axette.onAfterAjax(registerButtons, [], 'my-id')
And then you can remove the hook with the .off()
method:
// Either by passing the function reference:
axette.off(`afterAjax`, registerButtons)
// or with ID:
axette.off(`afterAjax`, 'my-id')
// or with the Hook object:
axette.off(hook)
Or you can call the method without any parameters to remove all hooks on that specific event:
axette.off(`afterAjax`)
Axette has several events you can attach hooks (callbacks) to. You can attach multiple hooks to the same event. The hooks are called in the order they were attached.
Called before the init()
method is called.
Called after the init()
method is called.
Called before the AJAX request is sent.
Called after the AJAX request is sent.
If you call fetch()
or XMLHttpRequest()
manually, the snippets won't be automatically updated. To update the snippets, you can call the sendRequest()
method on the Axette
instance instead of fetch()
or XMLHttpRequest()
:
axette.sendRequest("/url", "GET");
You can also send Body with the request and define headers. The method signature is like this:
axette.sendRequest(url, method = "POST", body?, headers?); // Only the URL is required
// Full signature:
Axette.sendRequest(url: string, method: string = `POST`, requestBody?: BodyInit|null, headers: {[key: string]: string} = {'Content-Type': `application/json`})
Nette by default appends ?_fid=XXXX
to the URLs if you call the flashMessage()
function. To remove the ?_fid=XXXX
from the URL when using Flash Messages, you need to import the noFlashUrl()
function:
import { noFlashUrl } from 'axette';
noFlashUrl();
Huge thanks to Matouš Trča from @Visualio who wrote the core logic for handling the HTTP response from Nette.
This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you'll be creating employment for local families and restoring wildlife habitats.
MIT License
Copyright (c) 2021 Matronator
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.