Lightweight JavaScript Client Processing Library
Install with npm
npm install thematrix-entities
- Initialize Entities Object
let _baseUsers = [
{
id: 1,
name: "user1",
role_id: 1,
role_name: "admin",
country_id: 1,
country_name: "Country 1",
hourly_rate: 50,
hours: 180
},
{
id: 2,
name: "user2",
role_id: 2,
role_name: "operator",
country_id: 1,
country_name: "Country 1",
hourly_rate: 30,
hours: 120
}
];
let eUsers=new Entities({
list: _baseUsers,
key: "id", //add new custom key if id is not unique
init: function () {
//called on each object once when adding to list
this.icon = this._isAdmin()?<FaUserCircle />:<FaUser />; //jsx if supported by primary framework
this.salary=0; //initialize any custom field
},
calculateSalary: function () {
//custom function, need to be called with "_" prefix as eUsers._master[1]._callcuateSalary();
this.salary = "$ " + Entities._u._formatComma(this.hourly_rate * this.hours, 2);
},
isAdmin: function () {
//custom function, need to be called with "_" prefix as eUsers._master[1]._isAdmin();
return this.role_id === 1;
}
});
- Entities-Object is made up of Entity objects indexed by key. Entity objects can be accessed under "_master" branch of Entities object.
console.log(eUsers._master[1]._isAdmin());
- Entities can be updated with _refresh(NEW_LIST) method.
eUsers._refresh([
{},{},..
]);
//will call init method
- Entities can be appended with _append(NEXT_DATA) method.
eUsers._append([
{},{},..
]);
//will call init method for new entries
- Branches list supplied to an Entities objects are assigned as "master" branch with branch key "_master". Other branches can be folked or filtered with _folk() method and _where() method.
5.1 Folking as new branch (not cloned)
eUsers._folk('to_branch','from_branch');
5.2 Folking as new branch by _where() method (not cloned)
//args:rules object or function array, source branch (default branch master=""), key column for new branch, new branch name
eUsers._where({role_id:1},"","id","admins"); //listing only admin users as "admins" branch.
//with function array for advanced rules
eUsers._where([
function(me){
return me.role_id==1;
}
],"","id","admins"); //listing only admin users as "admins" branch with advanced filtering.
- Creating JSON object/string
let json=eUsers._toJson();
//with full arguments
//args: branch, rules, is_javascript_object, pre_object + post_object, sortby
let json=eUser._toJson('',[],true,null,'name')
- Get a field value by other field's value
//args: by field, by field's value, field to get, source branch (default master="")
let current_role_id=eUsers._getBy('id',1,'role_id',''); //get role_id where id=1
- Entities can be casted into an other model (with same columns, need to merge with _getColumnData() method.
//rules object or function array, unique key, source branch (default master="")
let roles=eUsers._model({},'role_id','');
//e.g. role model extracted with unique role_id
- Extracting sub model
7.1 Extracting a column data as sub model (with specified target fields)
//args: options object, source branch (default master=""), rules object or function array
let roles=eUsers._getColumnData(
{
columns: [
["role_id", "value"],
["role_name", "label"]
],
mode: "unique", //remove duplicates
orderBy: "label" //sort by sub-model-field
topping:{role_id:-1,role_name:"No Role"}, //inject first custom item
rottenEgg:{role_id:0,rolel_name:"Add New Role"} //append last custom item.
},
"", //source branch (default master="")
{} //AND - rules, {column1:"value1",colum2:"value2"}
);
7.2 Casting columns' data as sub model by custom rules
//args: options object, source branch (default master=""), rules object or function array
let roles=eUsers._getColumnData(
{
columns: [
["role_id", "value"],
["role_name", "label"]
],
mode: "unique", //remove duplicates
orderBy: "label" //sort by sub-model-field
topping:{role_id:-1,role_name:"No Role"}, //inject first custom item
rottenEgg:{role_id:0,rolel_name:"Add New Role"} //append last custom item.
},
"", //source branch "" or "_mmaster" for default
[
function(me){
return me.country_id=1;
},
function(me){
return me.id>2;
},
] //AND - rules
);
Sample: https://codesandbox.io/s/crazy-pascal-jv4vl
import "./styles.css";
import React, { useState, useEffect } from "react";
import { Entity, Entities } from "thematrix-entities";
import Select from "react-select";
import { FaUser, FaUserCircle } from "react-icons/fa";
import SimpleTableComponent from "reactjs-simple-table";
export default function App() {
const defC = []; //defC={value:0,label:'Select Countries'};
const defR = { value: 0, label: "Select Role" };
const defU = { value: 0, label: "Select User" };
const [eUsers, setEUsers] = useState(
new Entities({
list: [],
key: "id", //add new key if id is not unique
init: function () {
//called on each object once when adding to list
this.icon = this._isAdmin()?<FaUserCircle />:<FaUser />;
this.salary=0; //initialize any custom field
},
calculateSalary: function () {
this.salary = "$ " + Entities._u._formatComma(this.hourly_rate * this.hours, 2);
},
isAdmin: function () {
//custom function, need to be called with _ prefix
// eUser._master[1]._isAdmin()
return this.role_id === 1;
}
})
);
const [countries, setCountries] = useState([]);
const [roles, setRoles] = useState([]);
const [users, setUsers] = useState([]);
const [tableUserData, setTableUserData] = useState([]);
const [selCountries, setSelCountries] = useState(defC);
const [selRoles, setSelRoles] = useState(defR);
const [selUsers, setSelUsers] = useState(defU);
const [loading, setLoading] = useState(true);
const columns = [
{ field: "icon", headerName: "#" },
{ field: "name", headerName: "Name" },
{ field: "role_name", headerName: "Role" },
{ field: "country_name", headerName: "Country" },
{ field: "salary", headerName: "Salary" }
];
const getSelectedArray = (sel) => {
let _vals = [];
if (!sel) return _vals;
for (let i in sel) {
_vals.push(sel[i].value);
}
return _vals;
};
useEffect(() => {
//load data
let _baseUsers = [
{
id: 1,
name: "user1",
role_id: 1,
role_name: "admin",
country_id: 1,
country_name: "Country 1",
hourly_rate: 50,
hours: 180
},
{
id: 2,
name: "user2",
role_id: 2,
role_name: "operator",
country_id: 1,
country_name: "Country 1",
hourly_rate: 30,
hours: 120
},
{
id: 3,
name: "user3",
role_id: 3,
role_name: "user",
country_id: 2,
country_name: "Country 2",
hourly_rate: 20,
hours: 100
},
{
id: 4,
name: "user4",
role_id: 3,
role_name: "user",
country_id: 3,
country_name: "Country 3",
hourly_rate: 20,
hours: 75
}
];
eUsers._refresh(_baseUsers);
//call calculateSalary method on each entity in list
eUsers._calculateSalary();
//can access filed of inner object by key under master branch
//console.log(eUsers._master[1].salary);
setEUsers({ ...eUsers });
}, []);
useEffect(() => {
setCountries(
eUsers._getColumnData(
{
columns: [
["country_id", "value"],
["country_name", "label"]
],
mode: "unique",
orderBy: "label"
// topping:defC
},
"",
{}
)
);
}, [eUsers]);
useEffect(() => {
// console.log(selCountries);
let _rule = []; //(selCountries.value===0)?[]:{country_id:selCountries.value};
if (selCountries.length > 0) {
let _cts = getSelectedArray(selCountries);
_rule.push(function (me) {
return _cts.includes(me.country_id);
});
}
setRoles(
eUsers._getColumnData(
{
columns: [
["role_id", "value"],
["role_name", "label"]
],
mode: "unique",
orderBy: "label",
topping: defR
},
"",
_rule
)
);
setSelRoles(defR);
setSelUsers(defU);
}, [selCountries]);
useEffect(() => {
// let _rule=(selRoles.value===0)?[]:{role_id:selRoles.value};
let _rule = [];
if (selRoles.value > 0) {
_rule.push(function (me) {
return me.role_id == selRoles.value;
});
}
if (selCountries.length > 0) {
let _cts = getSelectedArray(selCountries);
_rule.push(function (me) {
return _cts.includes(me.country_id);
});
}
//alert(_rule);
setUsers(
eUsers._getColumnData(
{
columns: [
["id", "value"],
["name", "label"]
],
mode: "unique",
orderBy: "label",
topping: defU
},
"",
_rule
)
);
setSelUsers(defU);
}, [selRoles]);
useEffect(() => {
let _rules = [];
if (selCountries.length > 0) {
// console.log(selCountries);
let _cts = getSelectedArray(selCountries);
_rules.push(function (me) {
return _cts.includes(me.country_id);
});
}
if (selRoles.value > 0) {
_rules.push(function (me) {
return me.role_id === selRoles.value;
});
}
// console.log("rule", _rules);
if (selUsers.value > 0) {
_rules.push(function (me) {
return me.id === selUsers.value;
});
}
setLoading(true);
//fillter data
//approach 1: filter into a branch and convert json
// eUsers._where(_rules, "filter", "id", "");
// console.log('brs',eUsers._branches);
//setTableUserData(eUsers._toJson('filter');
//approach 2: convert json with filtering rule
//first argument source branch
setTableUserData(eUsers._toJson("", _rules));
}, [selUsers]);
useEffect(() => {
setTimeout(function () {
setLoading(false);
}, 20);
}, [tableUserData]);
return (
<>
<Select
id="countries_select"
isMulti
isSearchable
name="country"
value={selCountries}
options={countries}
onChange={(sel) => {
setSelCountries(sel);
}}
/>
<Select
id="roles_select"
isSearchable
name="role"
options={roles}
value={selRoles}
onChange={(sel) => {
setSelRoles(sel);
}}
/>
<Select
id="users_select"
isSearchable
name="user"
value={selUsers}
options={users}
onChange={(sel) => {
setSelUsers(sel);
}}
/>
{loading ? (
<></>
) : (
<>
<SimpleTableComponent columns={columns} list={tableUserData} />
</>
)}
</>
);
}