Need help with javel?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

lorisleiva
238 Stars 10 Forks MIT License 89 Commits 1 Opened issues

Description

🎁 Simple, lightweight and customisable Laravel models in your JavaScript

Services available

!
?

Need anything else?

Contributors list

No Data

Javel

🎁 Wrap your plain JavaScript objects into customizable Laravel-like models. Read introduction article.

cover

Installation

npm i javel -D

Overview

import Model from 'javel'

class Article extends Model {/* ... */}

await Article.all({ /* request / }) // => [ Article ] await Article.paginate({ query: { page: 2 } }) // => { data: [ Article* ], current_page: 2, ... } await Article.find(1) // => Article { id: 1, ... }

let article = await Article.create({ name: 'My article' }) // => Article { id: 2, name: 'My article' } await article.update({ name: 'My updated article' }) // => Article { id: 2, name: 'My updated article' } await article.delete() // => Deleted from the server

article = new Article({ name: 'My draft blog post' }) article.name = 'My new blog post' await article.save() // => Article { id: 3, name: 'My new blog post', ... }

Getting started

Start by creating your base model that all other models will extends from. In there you can override any logic you want or, even better, attach additional behavior using mixins (see below).

import { Model as BaseModel } from 'javel'

export default class Model extends BaseModel { // }

Typically, in this base model, you would set up how to reach your server by overriding the

baseUrl
and
makeRequest
methods like this:
export default class Model extends BaseModel {
    baseUrl () {
        return '/api'
    }
    makeRequest ({ method, url, data, query }) {
        return axios({ method, url, data, params: query })
    }
}

Note that

baseUrl
defaults to
/api
and that
makeRequest
will automatically use axios if it available in the
window
(which is the case by default in Laravel).

Next, create specific models for your application.

import Model from './Model.js'

export default class Article extends Model { // Your logic here... }

Finally you will likely want to configure which URL should be used for each actions (find, create, update, etc.). You might also want to add some behavior right before or after requests are made and customize how to handle the response. You can learn all about this in the documentation of the

MakesRequests
mixin.

A chain of mixins

Javel uses the mixwith library to separate each functionality of a Model into dedicated mixins (comparable to how Eloquent uses traits in Laravel). For the sake of convenience, Javel exposes the mixwith's API directly:

import { Model as BaseModel, Mixin, mix } from 'javel'

// Create a mixin const ImmutableModels = Mixin(superclass => class extends superclass { // })

// Use a mixin class Model extends mix(BaseModel).with(ImmutableModels) { // }

You can of course combine as many mixins as you want.

import { Model as BaseModel, mix } from 'javel'
import { MixinA, MixinB, MixinC } from './mixins'

// Use a mixin class Model extends mix(BaseModel).with(MixinA, MixinB, MixinC) { // }

Note that the order in which you use your mixins is important. The mixins will be applied using inheritance from right to left. Therefore the previous example is comparable to:

class MixinA extends BaseModel {}
class MixinB extends MixinA {}
class MixinC extends MixinB {}
class Model extends MixinC {}

Check out the lifecycle of a base model before creating your own mixins.

Mixins included in Javel's Model

By default, the base Model provided by javel includes the following mixins (in this order, i.e. the lower overrides the higher). You can learn more about each of them by reading their dedicated documentation.

  • HasAttributes Defines the basis of getting and setting attributes on a Model and provide some useful methods like
    primaryKey
    ,
    exists
    ,
    is
    ,
    clone
    , etc.
  • HasRelationships Enables models to configure their relationships with each other so that their attributes are automatically wrapped in the right model.
  • KeepsParentRelationship Ensures each child relationship keeps track of its parent and how to access itself from it. This enables models to climb up the relationship tree and even remove themselves from their parent when deleted.
  • MakesRequests Introduces async actions (
    find
    ,
    create
    ,
    update
    , etc.) to conveniently request the server and provides all the hooks necessary to customize how to handle your request/response proctol for each model.

Extra mixins available

Javel also provides some additional mixins that can be useful to plug in or to get inspired from when writing your own. Don't hesitate to PR your best mixins and share it with us.

  • GeneratesUniqueKey Attaches a unique key to every new model instanciated. If the model has a primary key available, the primary key will be used instead of generating a new unique key.
  • UsesMethodFieldWithFormData Transforms the
    update
    action to use the
    POST
    method with the
    _method=PATCH
    field when the provided data is an instance of FormData.
  • IntegratesQueryBuilder An easy way to build a query string compatible with "spatie/laravel-query-builder" (Has dependencies:
    js-query-builder
    )
    .

Optional dependencies

Some extra mixins have additional dependencies that need to be resolved. For example, some mixins could wrap a third party library to make it work with Javel out-of-the-box. Because these mixins are optional (you can choose not to add them), their dependencies must also be optional so that you don't end up loading lots of dependencies you don't need.

This means, when you do decide to pull in a mixin that has dependencies, you have to install them yourself and tell Javel how to access it, like this:

npm i third-party-library
import ThirdPartyLibrary from 'third-party-library'
import { Model as BaseModel, mix, SomeMixinThatUsesThirdPartyLibraries, registerModule } from 'javel'

registerModule('third-party-library', ThirdPartyLibrary)

class Model extends mix(BaseModel).with(SomeMixinThatUsesThirdPartyLibraries) { // }

Note: This behaviour has been designed as a workaround of webpack's optional

externals
which unfortunately creates warnings when optional dependencies are not present.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.