BsModel
A built-in data model class for working with entity object and remote API.
Overview
Vue MDBootstrap provides built-in data model class for working with entity object and remote API. BsModel represents an entity object that your application manages. For example, one might define a model for Users, Products, Cars, or other real-world object that we want to model in the system. Models also can be used for binding data by most of the input control components.
Usage Example
import { BsModel } from "vue-mdbootstrap";
const user = new BsModel({
uid: null,
username: null,
displayName: null,
email: null,
phoneNumber: null,
enabled: true
});
// assign a field with spesific value
user.username = 'John Doe';
// assign all fields value
user.assignValues({
uid: 123,
username: 'john.doe',
displayName: 'John Doe',
email: 'john@example.com',
phoneNumber: '061-430940',
enabled: true
});
Working with REST API
Sometimes we want to work with RESTful backend to load and save data. We can achieve this by configuring the RestProxy when creating the Model instance.
import { BsModel } from "vue-mdbootstrap";
const user = new BsModel({
schema: {
uid: null,
username: null,
displayName: null,
email: null,
phoneNumber: null,
enabled: true,
},
proxy: {
// do not change text: `{id}`
save: { url: './api/users', method: 'post' },
update: { url: './api/users/{id}', method: 'patch' },
delete: { url: './api/users/{id}', method: 'delete' },
fetch: './api/users/{id}',
}
}, null, 'uid');
Loading Data
Data can be load in the following ways:
user.fetch(123)
.catch(function (error) {
console.log(error);
});
Saving Data
After assigned all fields value, data can be save as new record to the RESTful backend in the following ways:
user.save()
.catch(function (error) {
console.log(error);
});
And to perform update via RESTful backend can be done in the following ways:
user.update()
.catch(function (error) {
console.log(error);
});
CSRF Token
If the RESTful backend needs CSRF token within the POST, PATCH, PUT or DELETE request, we can accomplish it with :
import { BsModel } from "vue-mdbootstrap";
const user = new BsModel({
schema: {
uid: null,
username: null,
displayName: null,
email: null,
phoneNumber: null,
enabled: true,
},
proxy: {
// do not change text: '{id}'
save: { url: './api/users', method: 'post' },
update: { url: './api/users/{id}', method: 'patch' },
delete: { url: './api/users/{id}', method: 'delete' },
fetch: './api/users/{id}',
},
csrfConfig: {
// do not change text: '{name}'
url: './api/token/{name}',
// 'token_name' is a keyword to identify the token.
// This keyword is used by the RESTful backend to create the CSRF token.
tokenName: 'token_name',
dataField: 'value',
// If 'suffix' is 'true' then the keyword will become: 'token_name-create', 'token_name-update', 'token_name-delete'
// when perfoming HTTP request to save, update or delete record.
suffix: false,
}
}, null, 'uid');
Working with Virtual Fields
Sometimes RESTful backend delivers a nested object, but we want our Model represents a simple object Model. We can solve this situation using virtual fields and combine them with onAfterFetch
event which is triggered after successfully loading or saving the object Model.
import { BsModel } from "vue-mdbootstrap";
import type { TModelOptions, TRecord } from 'vue-mdbootstrap';
export class ActivityModel extends BsModel{
constructor() {
const model: TModelOptions = {
schema: {
uid: null,
code: null,
status: null,
title: null,
periode: null,
year: null,
},
proxy: {
save: { url: './api/activity', method: 'post' },
update: { url: './api/activity/{id}', method: 'patch' },
delete: { url: './api/activity/{id}', method: 'delete' },
fetch: './api/activity/{id}',
}
};
super(model, null, 'uid');
// below is the virtual fields
this.set(this, 'budget', null);
this.set(this, 'realisasi', null);
this.set(this, 'programId', null);
this.set(this, 'programName', null);
this.set(this, 'batchId', null);
this.set(this, 'batchName', null);
}
// automatically called when fetching from remote API
onAfterFetch(data: TRecord): void {
// assigns values to the virtual fields
this.set(this, 'budget', data.budget);
this.set(this, 'realisasi', data.realisasi);
if (data.program) {
this.set(this, 'programId', data.program.id);
this.set(this, 'programName', data.program.title);
}
if (data.batch) {
this.set(this, 'batchId', data.batch.id);
this.set(this, 'batchName', data.batch.title);
}
}
};
import { ActivityModel } from "./ActivityModel";
const myModel = new ActivityModel();
myModel.fetch(123)
.catch(function (error) {
console.log(error);
});
Working with Nested Fields
There are use case when RESTful backend delivers a nested object and we want our Models to keep track those nested objects. But when performing save
or update
, we want to ignore those nested objects and some unneeded fields.
import { BsModel } from "vue-mdbootstrap";
import type { TModelOptions, TRecord } from 'vue-mdbootstrap';
import type { ISupplier } from './Supplier';
export class InventoryObat extends BsModel {
constructor() {
const model: TModelOptions = {
schema: {
id: null,
supplier: null, // nested object, ignore when performing save/update
supplierId: null, // ignore when performing save/update
tanggal: null,
invNum: null, // ignore when performing save/update
kodeObat: null,
namaObat: null,
satuan: null,
jenisObat: null,
kadaluarsa: null,
jumlahMasuk: null,
hargaDasar: null,
hargaObat: null,
jatuhTempo: null,
jumlahTerhutang: null, // ignore when performing save/update
jumlahBayar: null,
lunas: false,
catatan: null,
sisaStok: null, // ignore when performing save/update
createdAt: null, // ignore when performing save/update
},
proxy: {
fetch: './inventory/obat/{id}',
delete: './inventory/obat/{id}',
save: { url: './inventory/obat/masuk', method: 'post' },
update: { url: './inventory/obat/update/{id}', method: 'patch' },
},
};
super(model, null, 'id', 'content');
}
onAfterFetch(data: TRecord): void {
this.set('supplierId', (data.supplier as ISupplier)?.supplierId);
}
// this method is needed to convert our data to simple object
// and automatically called when performing 'save' or 'update'
toObject(): TRecord {
return {
id: this.get('id'),
supplier: this.get('supplierId'),
tanggal: this.get('tanggal'),
kodeObat: this.get('kodeObat'),
namaObat: this.get('namaObat'),
satuan: this.get('satuan'),
jenisObat: this.get('jenisObat'),
kadaluarsa: this.get('kadaluarsa'),
jumlahMasuk: this.get('jumlahMasuk'),
hargaDasar: this.get('hargaDasar'),
hargaObat: this.get('hargaObat'),
jatuhTempo: this.get('jatuhTempo'),
jumlahBayar: this.get('jumlahBayar'),
lunas: this.get('lunas'),
catatan: this.get('catatan'),
};
}
}
import { BsModel } from "vue-mdbootstrap";
import type { TModelOptions } from 'vue-mdbootstrap';
export class Supplier extends BsModel {
constructor() {
const schema: TModelOptions = {
schema: {
supplierId: null,
companyName: null,
officePhone: null,
contactPerson: null,
contactPhone: null,
department: null,
},
proxy: {
fetch: './inventory/suppliers/{id}',
delete: './inventory/suppliers/{id}',
save: { url: './inventory/suppliers', method: 'post' },
update: { url: './inventory/suppliers/{id}', method: 'patch' },
},
};
super(schema, adapter, 'supplierId', 'content');
}
}
export declare interface ISupplier extends Supplier {
supplierId?: string;
companyName?: string;
officePhone?: string;
contactPerson?: string;
contactPhone?: string;
department?: string;
}