PHPackages                             glaivepro/ajaxable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. glaivepro/ajaxable

ActiveLibrary[Database &amp; ORM](/categories/database)

glaivepro/ajaxable
==================

Laravel package that allows you to control models through ajax calls without bothering you on the PHP side.

0.10.9(6y ago)382MITPHPPHP &gt;=7.1CI failing

Since Apr 5Pushed 2y ago1 watchersCompare

[ Source](https://github.com/GlaivePro/Ajaxable)[ Packagist](https://packagist.org/packages/glaivepro/ajaxable)[ Docs](https://github.com/GlaivePro/Ajaxable)[ RSS](/packages/glaivepro-ajaxable/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (10)Dependencies (3)Versions (36)Used By (0)

Ajaxable
========

[](#ajaxable)

Ajaxable is a Laravel package that allows you to control (create, edit, delete) Eloquent models without bothering you on the backend. Or even frontend. Add markup to your html or use helpers and it works!

See docs at

Getting started - installation, setup and examples
--------------------------------------------------

[](#getting-started---installation-setup-and-examples)

Create ajaxable input in your view, add the CSRF token and the javascript library (this one depends on jQuery):

```

	Title
	{{$article->editor('title')}}

@include('ajaxable::jquery')
```

Now you have a field that saves any changes to database (if the user is authenticated).

If you need it a bit more custom, you can create the HTML controls yourself. For example this is how you delete `App\Tag` with the specified ID and remove the row (this is why it's wrapped in `.ajaxable-row`):

```

		 ID  Name  Controls

			1
			First tag

					Delete

			2
			Another tag

					Delete

```

Of course, you are not obliged to use the provided javascript. Here's how you could create an article with title "Test article 4" using plain javascript:

```
fetch("{{route('ajaxable.create')}}", {
  headers: {
	"Content-Type": "application/json",
	"Accept": "application/json",
	"X-Requested-With": "XMLHttpRequest",
	"X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').getAttribute('content')
  },
  method: "post",
  credentials: "same-origin",
  body: JSON.stringify({
	model: "App\Article",
	attributes: {title: "Test article 4"}
  })
});
```

Usage in details
----------------

[](#usage-in-details)

### Preliminaries

[](#preliminaries)

Make your model ajaxable.

```
use Illuminate\Database\Eloquent\Model;
use GlaivePro\Ajaxable\Traits\Ajaxable;

class Article extends Model
{
    use Ajaxable;
	//
}
```

In case you want fields to update models (i.e. you are not working with HTTP interface directly), include the CSRF token and JS library (it depends on jQuery) in your views.

```

@include('ajaxable::javascript')
```

### Generating HTML

[](#generating-html)

#### Editing models

[](#editing-models)

To obtain a field that synces changes to database, do this in your Blade template:

```

{{$tag->editor('name')}}
```

Some options can be supplied as well

```
{{$tag->editor('disabled', ['type' => 'checkbox'])}}

{{$tag->editor('group', ['type' => 'select', 'options' => [['value' => 1, 'text' => 'Group 1'], ['value' => 2, 'text' => 'Group 2']]])}}
```

List of supported options:

OptionDescription`type``select` or `textarea` will make the respective field, anything else sets the type attribute on input element`classes`adds classes (string or array) to element`attributes`adds attributes (array of `'attribute' => 'value'`); doesn't work for type or class`options`array of arrays (containing value and text keys) or strings, for select elements### Deleting models

[](#deleting-models)

To obtain a button that invokes deletion of element once clicked, use the `deleteButton` method and supply the content of the element.

```
{{$tag->deleteButton('Delete this item')}}
```

You can specify some options:

```
{{$tag->deleteButton('Remove', ['tag' => 'a'])}}
```

List of supported options:

OptionDescription`tag`HTML tag`classes`adds classes (string or array) to element`attributes`adds attributes (array of `'attribute' => 'value'`); doesn't work for classIf you need button (and maybe something else) removed on successful delete, wrap it (including the button) in `.ajaxable-row`.

### Creating models

[](#creating-models)

To create models, use the static `creatorButton()` method.

```
{{App\Comment::creatorButton('Add')}}
```

Set some initial attribute values

```
{{App\Comment::creatorButton('Post comment', ['values' => ['article_id' => $article->id]])}}
```

Add the fields so user could set some values before creation as well

```
{{App\Comment::creatorField('name')}}
{{App\Comment::creatorField('text', ['type' => 'textarea'])}}

{{App\Comment::creatorButton('Post comment')}}
```

If you need multiple creators with fields for same model on the same page, supply an ID to distinguish the sets.

```
{{App\Tag::creatorField('name', ['creator' => 'generic-tag-creator'])}}
{{App\Tag::creatorField('name', ['creator' => 'special-tag-creator'])}}

{{App\Tag::creatorButton('Create generic tag', ['creator' => 'generic-tag-creator'])}}
{{App\Tag::creatorButton('Crete special tag', ['creator' => 'special-tag-creator'])}}
```

In addition `creatorField` supports all the same methods that `editor` does and `creatorButton` supports all the options that `deleteButton` does.

### Writing your own HTML

[](#writing-your-own-html)

In many cases you'll want to write your own html but still want it to work with the included javascript library. You'll just have to add a little markup.

We'll start with editing as that's the simplest.

#### Editing model attributes

[](#editing-model-attributes)

Specify the model and add the `ajaxable-edit` class to your field.

```

```

In case of a [validation error](authorization-and-validation) user will get an alert. If you want to display it on html instead, wrap the input in `.form-group`. Error will be added in `span.error-block.help-block` and class `has-error` will be added to `.form-group`.

### Deleting models

[](#deleting-models-1)

A click on `.ajaxable-delete` will remove an item specified by `data-*` attributes. HTML will also get removed if you wrap it (including the button) in `.ajaxable-row`.

```

		 ID  Name  Controls

			1
			First tag

					Delete

			2
			Another tag

					Delete

```

#### Creating new models

[](#creating-new-models)

A click on `.ajaxable-creator` will make a request to create an object. Specify model in `data-model` attribute.

You may also supply any additional `data-attribute_*` attributes to be set on the new model.

```

		Create

```

#### User supplied values for new models

[](#user-supplied-values-for-new-models)

You can have an input that sets (on change) the value on creator:

```
Tag name:

		Create

```

In case of [validation error](#authorization-and-validation) user will get alerts. If you want to display alerts neatly instead, wrap input in `.form-group`:

```
Tag name:

```

This `.form-group` will then get class `has-error` added and `span.error-block.help-block` appended with the message.

#### Adding the created model to a list

[](#adding-the-created-model-to-a-list)

Often times you have a list of entries and need the new item appended to the list. We can do this if your models [return html](#returning-html-instead-of-json).

Creator should have the list specified in `data-ajaxable-list`.

```

	Existing tag 1
	Existing tag 2

		Create

```

The above example would append created html (using `ajaxable.tag` view) to `#tag-list` and add class `ajaxable-highlight` for 1.5 seconds (for highlighting purposes). If you want to prepend instead, specify `data-ajaxable-list-position="first"`. If you want the new item scrolled into view, specify `data-ajaxable-scroll="true"`.

### Using HTTP interface directly

[](#using-http-interface-directly)

Use your own JavaScript (or whatever else) to invoke stuff happening on your models. Here's what we provide:

RouteRequired parametersOptional parametersResponse`ajaxable.create``model`Initial values (key:value pairs in `attributes`)Model in JSON, optional HMTL.`ajaxable.update``model`, `id`, `key`, `value`Model in JSON, optional HTML`ajaxable.delete``model`, `id`Confirmation only`ajaxable.updateOrCreate``model`Constraints (key:value pairs in `wheres`) and values (key:value pairs in `attributes`)Model in JSON, optional HTML`ajaxable.control``model`, `id`, `action``parameters` - supply whatever to be passed to called action.Whatever you decide to return`ajaxable.addMedia``model`, `id`, `media``collection`, `name`Media object and URL`ajaxable.deleteMedia``model`, `id`, `media_id`Confirmation only**Example**. To update `title` to `New Title` on `App\Article` with ID 155 you'd POST `{model: 'App\Article', id: 155, key: 'title', value: 'New Title'}` to `{{route(ajaxable.update)}}`.

The `ajaxable.control` route could in theory call any method on your model. In practice the included checks refuse most actions and you should explicitly list what you want to allow in the model. Use sparingly!

The above routes will only work for POST requests and you must include XSRF token so Laravel would let you through.

Here are some get routes to retrieve data:

RouteRequired parametersOptional parametersResponse`ajaxable.retrieve``model`, `id`Confirmation, model in JSON, optional HTML`ajaxable.list``model``wheres` as key:value pairs, `scopes` as `scopeName` or `scopeName:parameter1,param2`Model in JSON, optional HTML`ajaxable.getMedia``model`, `id``collection`Media object and URL**Note**. The media routes will only work if your model uses [Laravel Medialibrary](https://docs.spatie.be/laravel-medialibrary).

### Returning HTML

[](#returning-html)

Some requests (`create`, `update`, `updateOrCreate`, `retrieve`) can include rendered HTML in the response if you specify `view: true` on the request.

To return rendered html you should create a view. By default `'ajaxable.'.camel_case(class_basename($model))` will be looked for. For example, `App\Tag` and `App\Stats\UserFault` will look for `ajaxable.tag` and `ajaxable.userFault` respectively so you should create `tag.blade.php` and `userFault.blade.php` inside `resources/views/ajaxable`.

This can be overriden by specifying `$rowView` property on the model or supplying `viewname` in the request.

Camel of basename will be passed to view. For example `$tags` or `$userFault`.

The `list` method is able to return HTML as well if you specify `view: true`. The response will be rendered through template selected in this order:

- Template specified in requests `viewname` (plural of camel of basename will be passed, i.e. `$tags` or `$userFaults`).
- Concatenation of template specified in requests `rowviewname`.
- Template specified in models `$listView`.
- Template `ajaxable.`.str\_plural(camel\_case(class\_basename($model))).
- Concatenation of template specified in models `$rowView`.
- Concatenation of template `ajaxable.`.camel\_case(class\_basename($model)).

### Authorization and validation

[](#authorization-and-validation)

By default the actions are allowed to all authenticated users. This is only appropriate when there is just a single class of users. In most cases you'd override the `allowAjaxableTo` method on your model

Here's an example that one might use for the contact form messages

```
public function allowAjaxableTo(string $action) : bool
{
	if ('create' == $action)
	{
		request()->validate([
			'name' => 'required',
			'email' => 'required|email',
			'message' => 'required',
		]);

		return true;
	}

	$allowedActionsForAuthorized = [ 'update', 'delete', 'retrieve', 'list', ];

	if (in_array($action, $allowedActionsForAuthorized))
		return auth()->check();

	return false;
}
```

### Customizing responses

[](#customizing-responses)

By default a successful request is responded with a JSON array that contains `"success": 1`. Something else like `object`, `collection`, `view` could also be set for the appropriate actions.

However, all of this can be overriden. The requests go through a `respondAfter` method on the model that will call try to call a specific method like `respondAfterDelete`, `respondAfterCreate`, `respondAfterRetrieve` etc, the last word corresponding to route name or the `action` value in case of `ajaxable.control` route. If the specific method is not found, `fallbackResponse` will be called which does some sensible defaults.

If you want to customize responses after retrieval, you overwrite the corresponding method on your model:

```
respondAfterDelete(bool $success)
{
	if ($success)
		return [
			'success' => 1,
			'deleted_on' => \Carbon\Carbon::now()->format('M d');
		];

	return 'Deletion was refused because of reasons.';
}
```

You may override all of the `respondAfter` method if you feel the need.

```
public function respondAfter(string $action, bool $success)
{
	return ['success' => 'uncertain'];
}
```

Tips &amp; Tricks
-----------------

[](#tips--tricks)

This section tells you how to do some stuff that the package doesn't explicitly implement.

### Value should be transformed before saving or retrieving

[](#value-should-be-transformed-before-saving-or-retrieving)

Use the Laravels mechanic of getters and setters (accessors).

### I must do something else when action is happening.

[](#i-must-do-something-else-when-action-is-happening)

Use [Laravel Events](https://laravel.com/docs/master/events). If you need to distinguish ajaxable events from other, check `request()`.

And remember that you can add small handlers directly in the model. For example, refuse deleting if the model is used and clean up otherwise:

```
protected static function boot()
{
    parent::boot();

    static::deleting(function($tag) {
		if ($tag->articles()->count())
			return false;

		$tag->synonyms()->detach();
    });
}
```

### Field name is uncertain or it's json or it's complicated...

[](#field-name-is-uncertain-or-its-json-or-its-complicated)

Usually this is a sign that you should ride on your own. This library makes the simple stuff simpler. If it's complicated, the overhead of making your own route and controller will be miniscule.

However, if you insist that you really want to use this and it's only this one time... well, there are a few paths to hack around.

You can do whatever you want in the `allowAjaxableTo` method before you allow ajaxable to work further.

```
public function allowAjaxableTo(string $action)
{
	if (!Gate::allows($action, $this))
		return false;

	if ('create' == request()->action
	     && isset(request()->attributes['user_id'])
		 && 'self' == request()->attributes['user_id'] )
	{
		// you can tinker with request here
		request()->attributes['user_id'] = auth()->id();

		// and you can also work with an object as it's already instantiated
		$object->updatedByJohn = 'probably';
	}
}
```

TODO, goals and possible goals
------------------------------

[](#todo-goals-and-possible-goals)

### Road to v1

[](#road-to-v1)

- Review routes; probably add support for more specific HTTP verbs as alternatives. And/or use JSON RPC?
- Review controller, simplify where possible.
- Create feature tests for all the requests.
- Simplify Traits/Ajaxable.
- Add events in the backend.
- Add exceptions in the backend.
- Rework frontend support. Rethink the direction, make it cleaner and less opinionated. Smaller, but extensible.
- Improve docs. Split the ReadMe into files?

### Random frontend ideas, needs general reconsideration

[](#random-frontend-ideas-needs-general-reconsideration)

- Develop the frontend helpers to support customization.
- Allow specifying the ajaxable list on `creatorButton` more easily.
- Maybe `type="text"` should be default on inputs? It matters if you query DOM by type attribute.
- Default classes/attributes for HTML.
- Support for option groups?
- Maybe HTML helpers should take any unrecognized options (i.e. not type, attributes, ..) and add them to attributes? It would make syntax lighter.
- It should be possible to set textarea value...
- Select should have a helper or something to make passing options simpler - should allow passing array/collection and specifying key names.
- Maybe an editor for a `belongsTo` relation should be possible and create a select with optionlist passed through `all()` on the linked model?
- Or maybe leave the frontend helpers for the simplest cases only?
- Add optional change confirmation?
- Make delete confirmation message customizable.
- Create more javascript libraries. Both `ajaxable::jquery` and `ajaxable::es6` should be available at least.
- Provide config to insert JS automatically. Something like `ajaxable.auto` config that accepts `jquery`, `es6` or falsy.
- JS library must be localizable. Currently it asks for the delete confirmation in English only. Mby a data attribute un delete-button?
- Introduce some javascript events and drop stuff like scroll, highlight, reseting inputs and reporting errors to user.
- Support uploads in javascript library.
- Write some frontend tests.
- Classes is the most often used option on HTML methods. Should implement approx "if second arg is array -&gt; do as now, if it's string -&gt; add to classes".
- Implement option to prepare responses through Eloquent resources?
- Retrieve single fields?
- BelongsToMany support?
- Refactor Traits/AjaxableHtml.
- Support upload field... with `ajaxable-file` and `ajaxable-files` classes?
- Blade helper to include the ajaxable routes in a global js variable.

### Random other ideas

[](#random-other-ideas)

- Opt-out of models in responses

Change log
----------

[](#change-log)

0.10 is a major rewrite of library. We intend to have less changes (especially less breaking changes) in the future and we are aiming to make this library production-ready.

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~69 days

Recently: every ~379 days

Total

33

Last Release

758d ago

Major Versions

0.10.8 → v10.x-dev2020-02-20

0.5.6 → v5.x-dev2024-04-16

PHP version history (2 changes)0.1.0PHP ~7.1

0.1.2PHP &gt;=7.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/6674d01479885d0c1929e0529fd4aa68aaf2ca8e4816c774b55ea584de900135?d=identicon)[tontonsb](/maintainers/tontonsb)

---

Top Contributors

[![tontonsb](https://avatars.githubusercontent.com/u/16481303?v=4)](https://github.com/tontonsb "tontonsb (124 commits)")

---

Tags

ajaxeloquenthacktoberfestlaravellaravel-packagelaraveleloquent

### Embed Badge

![Health badge](/badges/glaivepro-ajaxable/health.svg)

```
[![Health](https://phpackages.com/badges/glaivepro-ajaxable/health.svg)](https://phpackages.com/packages/glaivepro-ajaxable)
```

###  Alternatives

[cviebrock/eloquent-sluggable

Easy creation of slugs for your Eloquent models in Laravel

4.0k13.6M253](/packages/cviebrock-eloquent-sluggable)[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k302.7k1](/packages/cybercog-laravel-love)[cviebrock/eloquent-taggable

Easy ability to tag your Eloquent models in Laravel.

567694.8k3](/packages/cviebrock-eloquent-taggable)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
