@devslane/mobx-entity-manager

Mobx Store Entity Manager

Usage no npm install needed!

<script type="module">
  import devslaneMobxEntityManager from 'https://cdn.skypack.dev/@devslane/mobx-entity-manager';
</script>

README

DevsLane Mobx Entity Store Manager


Mobx Entity Store Manager is born from the need for an extensible yet easy-to-use solution that helps you manage your entities in Mobx store without writing any boilerplate code.

Table of Content

Features

  • Easily manage your entities.
  • Lesser boilerplate code.
  • Comes with a Basic Entity Store setup .
  • Support for Single Entity, Entity List and Paginated Entity List.

Getting Started

Install Mobx Entity Manager by running this command

$ yarn add @devslane/mobx-entity-manager

To finalize the setup, boot Mobx Entity Manager in your entry file, such as App.ts or index.ts, by adding the following code -

App.ts

import { ContextStatic } from '@devslane/mobx-entity-manager';
import { BaseApiService } from 'services';

ContextStatic.boot({
            api: BaseApiService.getInstance(),
        });

...

Now you are ready to use Mobx Entity Manager seamlessly.

Usage

Mobx Entity Manager provides multiple Model Classes that can be extended to create models of your entities. These Model classes provide helper methods that can be used out of the box.

Mobx Entity Flow Diagram

Example -

A basic User Model extending EntityBaseModel class will look like -

UserModel.ts

import { EntityBaseModel, ModelList, ModelItem, ModelJson } from '@devslane/mobx-entity-manager';
import { UserStore } from 'stores';
import { observable } from 'mobx';
import { OccupationModel, EducationModel } from 'models';

class UserModel extends EntityBaseModel {
  static _store: UserStore;
  
  @observable
  name: string;
  
  @observable
  email: string;
  
  @observable
  occupations: ModelList<OccupationModel>;
  
  @observable
  education?: ModelItem<EducationModel>;
  
  deserialize_occupations(data: any[]) {
        this.occupations = new ModelList<OccupationModel>(OccupationModel);
        this.occupations.deserialize(data);
    }
  
  deserialize_education(data: ModelJson) {
        this.education = new ModelItem<EducationModel>(EducationModel);
        this.education.deserialize(data);
    }  
  
}

Documentation

  • ModelItem

ModelItem wraps your single entity and provides you with all kind of basic methods.

Basic Usage -

import { ModelItem } from '@devslane/mobx-entity-manager';
import { UserModel } from 'models';

loggedInUser: ModelItem<UserModel> = new ModelItem<UserModel>(UserModel);

// Initializing value in ModelItem
await this.loggedInUser.load(`/your-api`, {
                param_key: param_value,
            });

// Accessing the entity stored in Model Item
console.log(loggedInUser.item);

// Accessing other helper properties
console.log('Is Item Loaded: ', loggedInUser.loaded);
console.log('Is Item Loading: ', loggedInUser.loading);

Methods available -

Methods Arguments Return Type Description
setItem() item: T void Sets the item received in argument in the ModelItem
deserialize() item: ModelJson void Superset of setItem that converts the JSON object into Model class itself.
load() url: string, params?: { [p: string]: any }, config?: { dataKey?: string; forceRefresh?: boolean; itemId?: number or string; useAuth?: boolean; } Promise<void> Loads your Model Item using response from a remote URL.
setLoading() loading: boolean void Sets the loading property.
setLoaded() loaded: boolean void Sets the loaded property.
setError() error: BaseError or null void Sets the error property.

Properties available -

Properties Return Type Description
item item or undefined If set, fetches the wrapped item or undefined otherwise
loaded boolean Indicates whether item has been loaded or not
loading boolean Indicates whether item is currently being loaded
error boolean Indicates whether some error has occurred while loading the item

load() and deserialize() methods handle loaded, loading and error internally.

  • ModelList

ModelList wraps your list of entities and provides you with all kind of basic methods to manage your list.

Basic Usage -

import { ModelList } from '@devslane/mobx-entity-manager';

users: ModelList<UserModel> = new ModelList<UserModel>(UserModel);

// Initializing value in ModelList
this.users.load('/your-api');

// Accessing the entity stored in Model List
users.items.map((item) => console.log(item));

// Accessing other helper properties
console.log('Is List Loaded: ', users.loaded);
console.log('Is List Loading: ', users.loading);

Methods available -

Methods Arguments Return Type Description
setItems() items: T[] void Clears the existing list and sets the items received in argument in the ModelList
appendItems() items: T[] void Appends the items to already existing list
appendItem() item: T void Appends an item to the end of list
unshiftItem() item: T void Appends an item to the start of list
deserialize() items: ModelJson[] void Superset of setItems that converts the JSON objects into Model class itself.
clearItems() - void Clears all the existing items in the list and resets the loaded property.
setLoading() loading: boolean void Sets the loading property.
setLoaded() loaded: boolean void Sets the loaded property.
setError() error: BaseError or null void Sets the error property.
load() url: string, params?: { [p: string]: any }, config?: { dataKey?: string; forceRefresh?: boolean; itemId?: number or string; useAuth?: boolean; } Promise<void> Loads your Model List using response from a remote URL.

Properties available -

Properties Return Type Description
items item[] or undefined If set, fetches the wrapped list or undefined otherwise
loaded boolean Indicates whether list has been loaded or not
loading boolean Indicates whether list is currently being loaded
error boolean Indicates whether some error has occurred while loading the list
  • PaginatedModelList

PaginatedModelList extends basic ModelList with all its features and additional support for pagination. This proves to be really helpful when dealing with entities whose lists are not fully loaded initially. So you don't have to worry about maintaining variables like lastPage, totalPages etc.

Basic Usage -

import { PaginatedModelList } from '@devslane/mobx-entity-manager';

users: PaginatedModelList<UserModel> = new PaginatedModelList<UserModel>(UserModel);

// Load initial values in PaginatedModelList
this.users.load('/your-api');

// Load next page of entities
this.users.loadNext();

// Accessing the entity stored in List
users.items.map((item) => console.log(item));

// Accessing other helper properties
console.log('Is Last Page: ', users.isLastPage);
console.log('Total Pages: ', users.totalPages);

Methods available -

Methods Arguments Return Type Description
loadNext() - Promise<void> Loads next page of entity items from the remote URL you passed in load method.
setIsLoadingNextPage() loading: boolean void Sets the loading next page property.

Properties available -

Properties Return Type Description
isLoadingNextPage boolean Indicates whether next page is being loaded
totalPages number Returns total number of pages of entity
perPage number Returns number of items per page
lastPage number Returns last page number
currentPage number Returns current page number
nextPage number Returns next page number
prevPage number Returns previous page number
firstPageUrl string Returns url pointing to first page
lastPageUrl string Returns url pointing to last page
isFirstPage boolean Returns whether current page is the first page
isLastPage boolean Returns whether current page is the last page
isLoadedAll boolean Returns whether all the pages have been loaded

Since PaginatedModelList extends ModelList so all methods and properties of the latter are available in the former.

loadNext() method handles isLoadingNextPage internally.

  • EntityBaseModel

Extending EntityBaseModel class in your Entity Model classes provides you with multiple ready to use properties without writing repetitive properties in each of your model.

Basic Usage -

class UserModel extends ChildStore<UserModel> {
    @observable loggedInUser?: UserModel;
    
    setLoggedInUser(data: ModelJson) {
        this.loggedInUser = UserModel.fromJson(data) as UserModel;
    }
    
    updateName(name: string) {
        this.loggedInUser.name = name;
    }
}

Example of a UserModel extending EntityBaseModel is shown above.

If you have ModelItem, or ModelList wrapped property inside Model Class then you will have to write a deserializer method for it.

  • Deserializer method name must follow the convention deserializer_{property_name}

Check example for deserializer method above.

Static Methods -

Methods Arguments Return Type Description
fromJson() json: ModelJson, identifierKey?: string EntityBaseModel or null Create and returns a new entry in store if not already present, otherwise update and returns the existing entry.
getOrNew() id: EntityIdentifier EntityBaseModel It looks for the item in store based on id and creates a new entry in store if not found
get() id: EntityIdentifier EntityBaseModel or undefined Returns the item from store with same id or undefined if not found

Regular Methods -

Methods Arguments Return Type Description
updateFromJson() json: ModelJson void Updates the existing entry of item in the store.