Our blazing fast Grid component built with pure JavaScript


Post by postman »

           let sendToPaymentSystemBtn = new Button({
                icon: "b-fa-plus",
                color: "b-blue",
                text: "Отправить",
                style: "margin-right: 15px",
                tooltip: "Отправить в платежную систему",
				cls: "send-to-payment-system-btn",
				onClick: () => {
                    console.log('button clicked');
                }
            })
	    let searchFilterField = new TextField({
				placeholder: "Search",
				style: "margin-right: 10px;",
				cls: "search-by-username",
				listeners: {
                    change: (elem) => {
                        this.filters.search = elem.value
                        this.getData();
                    }
                }
	   });
	   let statusFilterField = new Combo({
				items: this.statuses,
				placeholder: "Status",
				style: "margin-right: 10px;",
				value: "All statuses",
				cls: "filter-by-status-field",
				listeners: {
					action: (elem) => {
						if (elem.value === "All statuses") {
							this.filters.status = "";
						} else {
							this.filters.status = elem.value;
						}
						this.getData();
					}
				}
	   });
	   let departmentsFilterField = new Combo({
				items: this.departments,
				placeholder: "Departments",
				style: "margin-right: 10px;",
				value: "All departments",
				cls: "filter-by-department-field",
				listeners: {
					action: (elem) => {
						if (elem.value === "All departments") {
							this.filters.department = "";
						} else {
							this.filters.department = elem.value;
						}
						this.getData();
					}
				}
	   });
	   let dateRangeFilter = new Widget({
				cls: "filter-by-date-range-field",
				html: "<div id=\"period\" style=\"background: #fff; display: inline-block;\" class=\"ml-2 border pointer p-4\">" +
					"<i class=\"fa fa-calendar\"></i>&nbsp;" +
					"<span class=\"range\"></span> <i class=\"fa fa-caret-down\"></i>" +
					"</div>"
	    })
	    let toolbar = new Toolbar({
				items: [
					sendToPaymentSystemBtn,
					searchFilterField,
					statusFilterField,
					departmentsFilterField,
					dateRangeFilter
				]
	   });
	   let filtersPanel = new Panel({
				adopt: "filters",
				floating: true,
				centered: true,
				cls: "filters-panel",
				items: [
					toolbar,
				],
				tbar: []
	   });
	   

Why listeners - onClick, change, action in widgets, not wotking in page? I used this code in same table and it works, but in new table don`t work.


Post by saki »

There is no obvious error in your code and it should work.

How can we reproduce the problem in any of our grid examples? Or, post please a code that will demonstrate the issue and that we can run locally.


Post by postman »

The fact of the matter is that there is no error, and they do not work. Do a trial library have a mechanism for broke his normal working if i not paid a premium?


Post by saki »

No, trial is fully workable during the trial period. Post please your code, so that we can find the reason why it doesn't work.


Post by postman »

Here is my code:

"use strict";

import API from "/static/js/api.js";
import Vue from "/static/js/vue.esm.browser.min.js";
import { Grid, Panel, Store, Toolbar, Toast, Button, Mask, TextField, Combo, Widget } from "/static/js/grid.module.js";


const api = new API("/api/");


new Vue({
	el: "#app",
	data: {
		api: api,
		store: {"instance": null},
		filtersPanel: {"instance": null},
		grid: {"instance": null},
		startDate: null,
		endDate: null,
		statuses: ["All statuses", "Active", "Inactive"],
		filters: {
			search: "",
			status: "",
			department: ""
		},
		sorters: {
			current: "",
			title: "",
			buyer: "",
			status: ""
		}
	},
	methods: {
		async updateFields(userId, newValue, action) {
			try {
				if (!newValue) return;
				let responseData = await api.request(
					"employees:update_fields", {
						"id": userId,
						"new_value": newValue,
						"action": action
					}
				)
				Toast.show({
					html: "Field updated",
					showProgress: true,
					color: "b-green"
				});
				await this.getData();
			} catch (e) {
				Toast.show({
					html: `${e.error}`,
					showProgress: true,
					color: "b-red"
				});
			}
		},
		/**
		 * Set to html element table filters panel
		 *
		 * @async
		 */
		async setFiltersPanel() {
			let sendToPaymentSystemBtn = new Button({
                icon: "b-fa-plus",
                color: "b-blue",
                text: "Отправить",
                style: "margin-right: 15px",
                tooltip: "Отправить в платежную систему",
				cls: "send-to-payment-system-btn",
				onClick: () => {
                    console.log('button clicked');
                }
            })
			let searchFilterField = new TextField({
				placeholder: "Search",
				style: "margin-right: 10px;",
				cls: "search-by-username",
				listeners: {
                    change: (elem) => {
                        this.filters.search = elem.value
                        this.getData();
                    }
                }
			});
			let statusFilterField = new Combo({
				items: this.statuses,
				placeholder: "Status",
				style: "margin-right: 10px;",
				value: "All statuses",
				cls: "filter-by-status-field",
				listeners: {
					action: (elem) => {
						if (elem.value === "All statuses") {
							this.filters.status = "";
						} else {
							this.filters.status = elem.value;
						}
						this.getData();
					}
				}
			});
			let departmentsFilterField = new Combo({
				items: this.departments,
				placeholder: "Departments",
				style: "margin-right: 10px;",
				value: "All departments",
				cls: "filter-by-department-field",
				listeners: {
					action: (elem) => {
						if (elem.value === "All departments") {
							this.filters.department = "";
						} else {
							this.filters.department = elem.value;
						}
						this.getData();
					}
				}
			});
			let dateRangeFilter = new Widget({
				cls: "filter-by-date-range-field",
				html: "<div id=\"period\" style=\"background: #fff; display: inline-block;\" class=\"ml-2 border pointer p-4\">" +
					"<i class=\"fa fa-calendar\"></i>&nbsp;" +
					"<span class=\"range\"></span> <i class=\"fa fa-caret-down\"></i>" +
					"</div>"
			})
			let toolbar = new Toolbar({
				items: [
					sendToPaymentSystemBtn,
					searchFilterField,
					statusFilterField,
					departmentsFilterField,
					dateRangeFilter
				]
			});
			let filtersPanel = new Panel({
				adopt: "filters",
				floating: true,
				centered: true,
				cls: "filters-panel",
				items: [
					toolbar,
				],
				tbar: []
			});
			this.filtersPanel.instance = filtersPanel;
		},
		/**
		 * Set table to html element
		 *
		 * @async
		 */
		async setTable() {
			let store = this.store.instance;
			let grid = new Grid({
				adopt: "container",
				fullRowRefresh: true,
				scrollable: true,
				listeners : {
					thisObj : this,
					finishCellEdit: ({ editorContext }) => {
						if (editorContext.cell.dataset.column === "bonus") {
							this.updateFields(editorContext.record.data.id, editorContext.record.data.bonus, "bonus");
						} else if (editorContext.cell.dataset.column === "debt") {
							this.updateFields(editorContext.record.data.id, editorContext.record.data.debt, "debt");
						}
					}
				},
				showRemoveRowInContextMenu: false,
				cls: "employees-table",
				// selectionMode : {
				// 	rowCheckboxSelection : true,
				// 	showCheckAll : true
				// },
                subGridConfigs : {
                    locked : {
                        width : 500
                    }
                },
				features: {
					cellEdit: true,
					summary : true,
					regionResize : true,
					columnPicker : {
						groupByRegion : true
					},
				},
				columns: [
					{ type : "rownumber", locked : true, sum : "count" },
					{
						text     : "Сотрудник",
                        locked   : true,
						children : [
						 	{ text : "id", field : "id", hidden: true },
							{ text : "Идентификатор", editor : false, field : "user__username", width : 150, locked : true },
							{ text : "Отдел", editor : false, field : "department__name", width : 150, locked : true },
							{ text : "Группа", editor : false, field : "user__user_member__team__name", width : 150, locked : true }
						]
					},
					{
						text     : "Общий расчет",
						children : [
							{ text : "Оклад", field : "salary", editor : false, width : 150, sum : true },
							{ text : "Бонус", field : "bonus", width : 150, sum : true },
							{ text : "Долг", field : "debt", width : 150, sum : true },
							{ text : "Итого", field : "total_amount", editor : false, width : 150, sum : true },
							{ text : "Итого выплачено", editor : false, field : "total_paid", width : 150, sum : true },
							{ text : "Осталось выплатить", editor : false, field : "left_to_pay", width : 150, sum : true },
							{ text : "Валюта", editor : false, field : "currency__code", width : 150 }
						]
					},
					{
						text     : "Аванс",
						children : [
							{ text : "Аванс", field : "advance_amount", width : 150, sum : true },
							{ text : "Бонус Аванс", field : "advance_bonus_amount", width : 150, sum : true },
							{ text : "Долг", field : "advance_debt", width : 150, sum : true },
							{ text : "Сумма", field : "advance", width : 150, sum : true },
							{
								text    : "Проверка",
								width   : 100,
								field   : "advance_checked",
								type    : "widget",
								widgets : [{
									type     : "checkbox",
									onAction : ({ source : checkbox }) => {
										console.log("checked");
										// let record = this.store.instance.getById(checkbox.cellInfo.record.data.id)
										// console.log(checkbox.input.checked)
										// console.log(checkbox.cellInfo.record.data.id)
										// record.last_advance_status = "Approved"
										// record["last_advance_status"] = "Approved";
										// record["advance_checked"] = true;
									// 	if (checkbox.input.checked) {
									// 		record["last_advance_status"] = "Approved";
									// 		record["advance_checked"] = true;
									// 	}
									}
								}]
							},
							{ text : "Статус", field : "last_advance_status", width : 150 }
						]
					},
					{
						text     : "Зарплата",
						children : [
							{ text : "Зарплата", field : "salary_amount", width : 150, sum : true },
							{ text : "Бонус Зарплата", field : "salary_bonus_amount", width : 150, sum : true },
							{ text : "Долг", field : "salary_debt", width : 150, sum : true },
							{ text : "Сумма", field : "salary_total", width : 150, sum : true },
							{
								text    : "Проверка",
								width   : 100,
								type    : "widget",
								widgets : [{
									type     : "checkbox",
									onAction : ({ source : checkbox }) => {
										console.log("checked");
									}
								}]
							},
							{ text : "Статус", field : "last_salary_status", width : 150 }
						]
					},
				],
				store
			});
			this.grid.instance = grid;
		},
		/**
		 * Set date range picker handler
		 */
		setDateRangePicker() {
			const start = moment().startOf("month");
			const end = moment().endOf("month");
			const that = this;
			$("#period").daterangepicker({
				startDate: start,
				endDate: end,
				ranges: {
					"Last Month"  : [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")]
				}
			}, that.period_cb);
			that.period_cb(start, end);
		},
		/**
		 * Set date range to html element and get data with it dates
		 *
		 * @async
		 */
		async period_cb(start, end){
			this.startDate = start.startOf("month");
			this.endDate = end.endOf("month");
			$("#period span").html(start.format("MMMM D, YYYY") + " - " + end.format("MMMM D, YYYY"));
			await this.getData();
		},
		/**
		 * Get employees with filters
		 *
		 * @async
		 */
		async getData() {
			// try {
				const responseData = await api.request(
					"employees:salary_load", {
						date1: this.startDate.format("YYYY-MM-DD"),
						date2: this.endDate.format("YYYY-MM-DD"),
						filters: {
							search: this.filters.search,
							status: this.filters.status,
							department: this.filters.department
						}
					}
				)
				this.store.instance.data = responseData.items;
			// } catch (e) {
			// 	Toast.show({
			// 		html: `${e.error}`,
			// 		showProgress: true,
			// 		color: "b-red"
			// 	});
			// }
		},
	},
	computed: {
	},
	/**
	 * First time get and set data
	 *
	 * @async
	 */
	async created() {
		Mask.mask("Loading");
		this.store.instance = new Store({
			data: []
		});
		await this.setFiltersPanel();
		this.setDateRangePicker();
		await this.setTable();
		Mask.unmask();

	// const sendToPaymentSystemBtnElem = document.querySelector(".send-to-payment-system-btn")
	// sendToPaymentSystemBtnElem.addEventListener("click", event => {
	// 	console.log('from listener');
	// });
	// const searchByUsernameElem = document.querySelector(".search-by-username")
	// searchByUsernameElem.addEventListener("change", event => {
	// 	this.filters.search = event.target.value;
	// 	this.getData();
	// });
},
mounted() {
}
});


Post by saki »

Would you please post also you html and other relevant files zipped? The above is not directly runnable and we want to duplicate your environment as much as possible.


Post by postman »

I can not post all files, there is a python code, same code working in another table and it works good, but this code doesnt work

{% extends "adminapp/base.html" %}
{% load static %}
{% load random %}

{% block head %}
<link rel="stylesheet" href="{% static 'css/grid.stockholm.css' %}">
<link rel="stylesheet" href="{% static 'accountsapp/css/modal.css' %}">
<link rel="stylesheet" href="{% static 'css/daterangepicker.css' %}">
{% endblock %}

{% block content %}
<style>
    .content-wrapper {
        padding: 0 0 0 0 !important;
        max-width: 100% !important;
    }
    .b-grid-subgrid {
        background-image: none !important;
    }
</style>
	<div v-cloak id="app">
        {% verbatim %}
		<div class="card">
            <div id="filters"></div>
            <div id="container" class="medium-sized-tools"></div>
        </div>
        {% endverbatim %}
    </div>
{% endblock %}


{% block js %}
<script type="text/javascript" src="{% static 'js/moment.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/daterangepicker.min.js' %}"></script>
<script type="module" src="{% static 'employeesapp/js/salary-app.js' %}?rnd={% rnd %}"></script>
{% endblock %}

Post by saki »

Move your code from created() to mounted() and it should work.


Post Reply