Skip to content

Instantly share code, notes, and snippets.

@afiqiqmal
Last active November 7, 2019 07:51
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afiqiqmal/00d4df95e8ef9c18beaf3afbb015e399 to your computer and use it in GitHub Desktop.
Save afiqiqmal/00d4df95e8ef9c18beaf3afbb015e399 to your computer and use it in GitHub Desktop.
Boilderplate for JSGrid Library

Boilerplate for JSGrid

After Struggling to use this library, i came out a method chaining for easy use of JSGrid Library. There is certain part made to fit with bootstrap tempalate

Usage

set route for get, post, update, delete. just leave null if it is not use

var route = {
    get: "{{ route('app.user') }}", // use for get data
    post: "{{ route('app.user.store') }}", // create data
    update: "{{ route('app.user.update', ':id') }}", // update data
    delete: "{{ route('app.user.destroy', ':id') }}" // delete data
};

List of method can be use

canFilter: function (value) {},
canInsert: function (value) {},
canEdit: function (value) {},
canSorting: function (value) {},
canPaging: function (value) {},
canAutoload: function (value) {},
canPageLoading: function (value) {},
setPageSize: function (value) {},
setPageIndex: function (value) {},
setRoute: function (route) {},
setField: function (field) {},
customloadData: function (closure) {},
customInsertData: function (closure) {},
customUpdateData: function (closure) {},
customDeleteData: function (closure) {},
customEditRow: function (closure) {},
customRowClick: function(closure) {customOnError: function(onError) {},
customOnItemUpdated: function(method) {},
customOnItemInserted: function(method) {},
customOnItemDeleted: function(method) {},
customOnClearFilterClick: function(method) {},
primaryKey: function (value) {},

How to use

new CGrid().canInsert(false).setField(fields).setRoute(route).init("#appTable");
new CGrid().customRowClick(function (args) {
    //your code logic
}).setField(fields).setRoute(route).init("#appTable");

New Field Type

  • Date and File
  • File - Can upload / replace / remove file directly from the jsgrid column
  • Date - Custom date filtering easy to filter date range

File Usage in Backend Example for PHP

for file type, if there is no file selected, it will send as '0' means false

    if ($request->hasFile('card_image')) {
        $filePath = store_file($request->file('card_image'), 'media');
        $input['card_image'] = $filePath;
   } else {
        if ($input['card_image']) {
            unset($input['card_image']); // avoid the value to be replace
        } else {
            $input['card_image'] = null;
        }
  }

Warning

Please alter axios response according to your data return.

Credit

Please refer here -> https://github.com/tabalinas/jsgrid and http://js-grid.com/

$(function () {
"use strict";
jsGrid.setDefaults({
tableClass: "jsgrid-table table table-striped table-hover"
});
jsGrid.setDefaults("text", {
_createTextBox: function() {
return $("<input>").attr("type", "text").attr("class", "form-control input-sm")
},
});
jsGrid.setDefaults("number", {
_createTextBox: function() {
return $("<input>").attr("type", "number").attr("class", "form-control input-sm").attr('step', '0.01').attr('placeholder', '0.00')
}
});
jsGrid.setDefaults("textarea", {
_createTextBox: function() {
return $("<input>").attr("type", "textarea").attr("class", "form-control");
}
});
jsGrid.setDefaults("control", {
_createGridButton: function(cls, tooltip, clickHandler) {
let grid = this._grid;
return $("<button>").addClass(this.buttonClass).addClass(cls).attr({
type: "button",
title: tooltip
}).on("click", function(e) {
clickHandler(grid, e)
})
}
});
jsGrid.setDefaults("select", {
_createSelect: function() {
let $result = $("<select>").attr("class", "form-control input-sm"),
valueField = this.valueField,
textField = this.textField,
selectedIndex = this.selectedIndex;
return $.each(this.items, function(index, item) {
let value = valueField ? item[valueField] : index,
text = textField ? item[textField] : item,
$option = $("<option>").attr("value", value).text(text).appendTo($result);
$option.prop("selected", selectedIndex === index)
}), $result
}
});
let DateField = function(config) {
jsGrid.Field.call(this, config);
};
DateField.prototype = new jsGrid.Field({
itemTemplate: function(value) {
if (value != null)
return moment(value).format('DD MMMM YYYY, h:mm:ss a');
return null;
},
insertTemplate: function(value) {
return this._insertPicker = $("<input>")
.attr("type", "text")
.attr("class", "form-control input-sm")
.bootstrapMaterialDatePicker({
format: 'YYYY-MM-DD',
time: false,
});
},
editTemplate: function(value) {
let time = {
format: 'YYYY-MM-DD',
time: false
};
if (value != null) {
time.currentDate = moment()
}
return this._editPicker = $("<input>")
.attr("type", "text")
.attr("class", "form-control input-sm")
.bootstrapMaterialDatePicker(time);
},
insertValue: function() {
return this._insertPicker
.attr("type", "text")
.attr("class", "form-control input-sm")
.bootstrapMaterialDatePicker({
format: 'YYYY-MM-DD',
time: false,
}).val();
},
editValue: function() {
return this._editPicker
.attr("type", "text")
.attr("class", "form-control input-sm")
.bootstrapMaterialDatePicker({
format: 'YYYY-MM-DD',
time: false,
}).val();
},
filterTemplate: function(args) {
let grid = this._grid;
let now = new Date();
this._fromPicker = $("<input>")
.attr("type", "text")
.attr("class", "form-control input-sm")
.attr("placeholder", "Date From")
.bootstrapMaterialDatePicker({
format: 'DD-MM-YYYY',
time: false,
});
this._toPicker = $("<input>")
.attr("type", "text")
.attr("class", "form-control input-sm")
.addClass("mt-1")
.attr("placeholder", "Date To")
.bootstrapMaterialDatePicker({
format: 'DD-MM-YYYY',
time: false,
});
this._fromPicker.on("keypress", function(e) {
if(e.which === 13) {
grid.search();
e.preventDefault();
}
});
this._toPicker.on("keypress", function(e) {
if(e.which === 13) {
grid.search();
e.preventDefault();
}
});
return $("<div>").append(this._fromPicker).append(this._toPicker);
},
filterValue: function(args) {
return {
from: this._fromPicker.bootstrapMaterialDatePicker({
format: 'DD-MM-YYYY',
time: false,
currentDate: new Date().getDate()
}).val(),
to: this._toPicker.bootstrapMaterialDatePicker({
format: 'DD-MM-YYYY',
time: false,
currentDate: new Date().getDate()
}).val()
};
}
});
jsGrid.fields.date = DateField;
let UploadField = function(config) {
jsGrid.Field.call(this, config);
};
UploadField.prototype = new jsGrid.Field({
itemTemplate: function(value) {
if (value != null) {
if (this.fileType === undefined || this.fileType === 'image') {
let img = $('<img>').attr("class", "img img-responsive").attr('src', value).attr('style', "width: 150px");
return $('<a>').attr('href', value).attr('target', '_blank').append(img);
} else {
return $('<a>').attr('href', value).attr('target', '_blank').append("Open File");
}
}
return null;
},
insertTemplate: function(value) {
let input = $('<input>').attr('type', 'file');
if (this.fileType !== undefined) {
input = input.attr('accept', this.fileType);
}
return this._insertPicker = input;
},
insertValue: function() {
return this._insertPicker[0].files.length === 0 ? null : this._insertPicker[0].files[0];
},
editTemplate: function(value) {
let parent = $('<div>');
let input = $('<input>').attr('type', 'file').attr('style', 'width: inherit;').attr('data-src-exist', value != null ? 1 : 0);
let removeBtn = $('<a>').attr('class', 'jsgrid-rm-image-btn pull-right').attr('style', 'line-height: 30px').append($('<i>').attr('class', 'fa fa-close'));
let img = null;
if (value != null) {
if (this.fileType === undefined || this.fileType === 'image') {
img = $('<img>').attr("class", "img img-responsive").attr('src', value).attr('style', "width: 150px");
img = $('<a>').attr('href', value).attr('class', 'jsgrid-image-place').attr('target', '_blank').append(img);
} else {
img = $('<a>').attr('href', value).attr('target', '_blank').append("Open File");
}
}
return this._editPicker = parent.append(input).append(removeBtn).append(img);
},
editValue: function() {
let file = this._editPicker.find('input[type=file]');
return file[0].files.length === 0 ? file.attr('data-src-exist') : file[0].files[0];
},
});
jsGrid.fields.file = UploadField;
$('body').on('click', '.jsgrid .jsgrid-edit-row .jsgrid-cell .jsgrid-rm-image-btn', function () {
let parent = $(this).parent();
parent.find('input[type]').attr('data-src-exist', 0);
parent.find('.jsgrid-image-place').remove();
});
});
let CGrid = function () {
this.jsName = null;
this.isFilter = true;
this.isInsert = true;
this.isEdit = true;
this.isSorting = true;
this.isPaging = true;
this.isAutoload = true;
this.isPageLoading = true;
this.rowClick = function (args) {this.editItem(args.item);};
this.pageSize = 20;
this.pageIndex = 1;
this.page = 1;
this.add = 0;
this.primaryKeyId = 'id';
this.routes = {};
this.fields = [];
this.editRowClosure = function(item) {let $row = this.rowByItem(item);this._editRow($row);};
this.errorClosure = function (args) {console.log(args);};
this.onItemUpdated = function (args) {console.log(args);};
this.onItemInserted = function (args) {console.log(args);};
this.onItemDeleted = function (args) {console.log(args);};
this.onClearFilter = function (args) {
this._renderGrid();
};
this.callbackData = (data) => {
console.log(data);
};
this.reloadData = () => {
$(this.jsName).jsGrid("loadData");
};
this.loadData = (filter) => {
localStorage.setItem('report', JSON.stringify(filter));
return axios.get(this.routes.get, {
params: filter
})
.then(response => {
this.page = response.data.page;
this.callbackData(response.data);
response.data.data = $.map(response.data.data, (item, itemIndex) => {
this.add = this.page != 1 ? (this.page * this.pageSize) - this.pageSize : 0;
return $.extend(item, {
indexing: (itemIndex + 1) + this.add
})
});
return {
data: response.data.data,
itemsCount: response.data.records
};
}).catch(reason => {
$(this.jsName).jsGrid('onError', reason);
notifyError(reason.response.data);
});
};
this.insertItem = (insertingClient) => {
let formData = this.transformToFormData(insertingClient);
return axios.post(this.routes.post, formData)
.then(function (response) {
notifySuccess(response.data.message);
this.callbackData(response.data);
return response.data.data;
}).catch(reason => {
$(this.jsName).jsGrid('onError', reason);
notifyError(reason.response.data);
})
};
this.updateItem = (updatingClient) => {
let formData = this.transformToFormData(updatingClient);
formData.append('_method', 'PATCH');
return axios.post(this.fixUrl(this.routes.update, updatingClient[this.primaryKeyId]), formData)
.then(function (response) {
notifySuccess(response.data.message);
return response.data.data;
}).catch(reason => {
notifyError(reason.response.data);
$(this.jsName).jsGrid('onError', reason);
})
};
this.deleteItem = (deletingClient) => {
return axios.delete(this.fixUrl(this.routes.delete, deletingClient[this.primaryKeyId]))
.then(function (response) {
notifySuccess(response.data.message);
}).catch(reason => {
notifyError(reason.response.data);
$(this.jsName).jsGrid('onError', reason);
})
};
this.fixUrl = (url, id) => {
return url.replace(':id', id);
};
this.transformToFormData = (data) => {
let formData = new FormData();
for ( let key in data ) {
if (data.hasOwnProperty(key)) {
formData.append(key, data[key]);
}
}
return formData;
}
};
CGrid.prototype = {
canFilter: function (value) {
this.isFilter = value;
return this;
},
canInsert: function (value) {
this.isInsert = value;
return this;
},
canEdit: function (value) {
this.isEdit = value;
return this;
},
canSorting: function (value) {
this.isSorting = value;
return this;
},
canPaging: function (value) {
this.isPaging = value;
return this;
},
canAutoload: function (value) {
this.isAutoload = value;
return this;
},
canPageLoading: function (value) {
this.isPageLoading = value;
return this;
},
setPageSize: function (value) {
this.pageSize = value;
return this;
},
responseData: function (closure) {
this.callbackData = closure;
return this;
},
setPageIndex: function (value) {
this.pageIndex = value;
return this;
},
setRoute: function (route) {
this.routes = route;
return this;
},
setField: function (field) {
this.fields = field;
return this;
},
customloadData: function (closure) {
this.loadData = closure;
return this;
},
customInsertData: function (closure) {
this.insertItem = closure;
return this;
},
customUpdateData: function (closure) {
this.updateItem = closure;
return this;
},
customDeleteData: function (closure) {
this.deleteItem = closure;
return this;
},
customEditRow: function (closure) {
this.editRowClosure = closure;
return this;
},
customRowClick: function(closure) {
this.rowClick = closure;
return this;
},
customOnError: function(onError) {
this.errorClosure = onError;
return this;
},
customOnItemUpdated: function(method) {
this.onItemUpdated = method;
return this
},
customOnItemInserted: function(method) {
this.onItemInserted = method;
return this
},
customOnItemDeleted: function(method) {
this.onItemDeleted = method;
return this
},
customOnClearFilterClick: function(method) {
this.onClearFilter = method;
return this;
},
primaryKey: function (value) {
this.primaryKeyId = value;
return this;
},
init:function (name) {
this.jsName = name;
$(name).jsGrid({
width: "100%",
filtering: this.isFilter,
inserting: this.isInsert,
editing: this.isEdit,
sorting: this.isSorting,
paging: this.isPaging,
autoload: this.isAutoload,
pageLoading: this.isPageLoading,
pageSize: this.pageSize,
pageIndex: this.pageIndex,
noDataContent: "Data Not Available or No Record Exists",
editItem: this.editRowClosure,
rowClick: this.rowClick,
onError: this.errorClosure,
rowRenderer: function(item, rowIndex) {
let $row = $('<tr>');
$row.data('cid', item.id);
this._renderCells($row, item);
return $row;
},
onItemDeleting: function (args) {
if (!args.item.deleteConfirmed) {
args.cancel = true;
let destroyModal = $('#destroy-modal');
destroyModal.modal('show');
destroyModal.find('#destroy-form').submit(function (e) {
e.preventDefault();
args.item.deleteConfirmed = true;
$(name).jsGrid('deleteItem', args.item);
destroyModal.modal('hide');
finishAjaxFormSpinner();
});
}
},
onItemUpdated: this.onItemUpdated,
onItemInserted: this.onItemInserted,
onItemDeleted: this.onItemDeleted,
clearFilter: this.onClearFilter,
controller: {
loadData: this.loadData,
insertItem: this.insertItem,
updateItem: this.updateItem,
deleteItem: this.deleteItem
},
confirmDeleting: false,
fields: this.fields
});
$(this.jsName).find('.jsgrid-search-mode-button').click();
return this;
}
};
function startAjaxFormSpinner() {
$('.form-need-loading').find('button[type=submit]').addClass('disabled').attr('disabled', true);
$('.form-need-loading').find('button[type=submit] .fa-spinner').show();
}
function finishAjaxFormSpinner() {
$('.form-need-loading').find('button[type=submit]').removeClass('disabled').attr('disabled', false);
$('.form-need-loading').find('button[type=submit] .fa-spinner').hide();
}
<div id="appTable"></div>
<script>
var route = {
get: "{{ route('app.user') }}", // use for get data
post: "{{ route('app.user.store') }}", // create data
update: "{{ route('app.user.update', ':id') }}", // update data
delete: "{{ route('app.user.destroy', ':id') }}" // delete data
};
var fields = [
{
name: "username",
title: 'Username',
type: "text",
editing: false,
itemTemplate: function (value, item) {
return value !== null ? value : '-';
}
},
{
name: "email",
title: 'Email',
type: "text",
itemTemplate: function (value, item) {
return value !== null ? value : '-';
}
},{
name: "card_image",
title: 'Image',
type: "file",
}, {
name: "first_name",
title: 'First Name',
type: "text",
itemTemplate: function (value, item) {
return value !== null ? value : '-';
}
},{
type: "control"
}];
new CGrid()
.canInsert(false)
.setField(fields)
.setRoute(route)
.init("#appTable");
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment