Skip to content

898669: GitHub sample of remote data topic #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# vue-data-grid-integration-with-custom-binding
The repository contains a professional demonstration of a custom binding with the Grid control. This application showcases essential functionalities such as filtering, searching, grouping, editing, and paging, all implemented using custom binding.
* Execute the following command to install the necessary dependencies:
`npm install`
* Update the port number in the `serve.js` file to load your data. Also, update the same port number in the `src/orderService.ts` file.
* Run the project using following command:
`npm run start`
Finally, the Syncfusion Vue Grid control will be rendered with custom binding.
![Grid with Custom Binding](image/custom-binding-grid-action.gif)
Binary file added image/custom-binding-grid-action.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "vite-js-cb",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"start-server": "node server.js",
"start-client": "vite",
"start": "concurrently \"npm run start-server\" \"npm run start-client\""
},
"dependencies": {
"@syncfusion/ej2-data": "^26.2.5",
"@syncfusion/ej2-vue-grids": "^26.2.8",
"axios": "^1.7.3",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.19.2",
"vue": "^3.4.31"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
"concurrently": "^8.2.2",
"vite": "^5.3.4"
}
}
1 change: 1 addition & 0 deletions public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import express from 'express';
import data from './src/data-source.js';
import bodyParser from 'body-parser';
import cors from 'cors';

const app = express();

app.use(cors({
origin: '*', // Update to the correct frontend origin
credentials: true
}));

app.use(bodyParser.json());

// Root route
app.get('/', (req, res) => {
res.send('Server is running');
});

// all records
app.get('/orders', function (req, res) {
res.json({ result: data, count:data.length });
});

// insert
app.post('/orders', function (req, res){
data.splice(0, 0, req.body.value);
res.status(200).send('Row Inserted');
});

// get specific records
app.get('/orders/:OrderID', (req, res) => {
const orderID = parseInt(req.params.OrderID, 10);
const order = data.find(d => d.OrderID === orderID);

if (order) {
res.json(order);
} else {
res.status(404).send('Order not found');
}
});
// Remove
app.delete('/orders/:OrderID', function (req, res) {
const orderID = parseInt(req.params.OrderID, 10);
const index = data.findIndex(x => x.OrderID === orderID);
if (index !== -1) {
data.splice(index, 1);
res.status(200).send('Row Deleted');
} else {
res.status(404).send('Order not found');
}
});

// Update
app.put('/orders/:OrderID', function (req, res) {
const orderID = parseInt(req.params.OrderID, 10);
const index = data.findIndex(x => x.OrderID === orderID);
if (index !== -1) {
// Assuming req.body.value contains the updated record with the same OrderID
data[index] = req.body.value;
res.status(200).send('Row Updated');
} else {
res.status(404).send('Order not found');
}
});

const port = xxxx; // Here xxxx denotes the port number.
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});
65 changes: 65 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<script setup>
import { ref, onMounted, provide } from "vue";
import { GridComponent as EjsGrid, ColumnsDirective as EColumns, ColumnDirective as EColumn, Page, Sort, Filter, Group, LazyLoadGroup, Toolbar, Edit, Search, } from '@syncfusion/ej2-vue-grids';
import { getOrders, addRecord, updateRecord, deleteRecord } from './orderService';

const data = ref([]);
const grid = ref([]);
const groupSettings = { enableLazyLoading: true, columns: ['ProductName'], showGroupedColumn: true, };
const filterSettings = { columns: [{ field: 'CustomerName', matchCase: false, operator: 'startswith', predicate: 'and', value: 'Maria' }] };
const sortSettings = { columns: [{ field: 'ProductID', direction: 'Descending' }] }
const state = { skip: 0, take: 12, group: groupSettings, sort: sortSettings, filter: filterSettings };
const editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true, newRowPosition: 'Top', };
const toolbar = ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search'];
const OrderIDRules = { required: true };

const dataStateChange = function (state) {
const query = grid.value.getDataModule().generateQuery();
getOrders(state, query).then(gridData => {
data.value = gridData.result; // Assign the result to the data property
});
}

const dataSourceChanged = function (state) {
if (state.action === 'add') {
addRecord(state.data, state); state.endEdit();
} else if (state.action === 'edit') {
updateRecord(state.data, state); state.endEdit();
} else if (state.requestType === 'delete') {
deleteRecord(state.data[0].OrderID, state); state.endEdit();
}
}

onMounted(() => {
dataStateChange(state);
});

provide('grid', [Page, Filter, Sort, Group, LazyLoadGroup, Toolbar, Edit, Search]);
</script>

<template>
<ejs-grid ref="grid" :dataSource='data' :allowPaging='true' :allowFiltering='true' :filterSettings='filterSettings'
:allowSorting='true' :sortSettings='sortSettings' :allowGrouping='true' :groupSettings='groupSettings'
:toolbar='toolbar' :editSettings='editSettings' :dataStateChange="dataStateChange"
:dataSourceChanged="dataSourceChanged">
<e-columns>
<e-column field='OrderID' headerText='Order ID' width='90' textAlign='Right' isPrimaryKey='true'
:validationRules="OrderIDRules"></e-column>
<e-column field="CustomerName" headerText="Customer Name" width="100"></e-column>
<e-column field='ProductID' headerText='Product ID' width=100></e-column>
<e-column field='ProductName' headerText='Product Name' format='C2' width=100></e-column>
</e-columns>
</ejs-grid>
</template>

<style>
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-calendars/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-splitbuttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-vue-grids/styles/tailwind.css";
</style>
1 change: 1 addition & 0 deletions src/assets/vue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/components/HelloWorld.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script setup>
import { ref } from 'vue'

defineProps({
msg: String,
})

const count = ref(0)
</script>

<template>
<h1>{{ msg }}</h1>

<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>

<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>

<style scoped>
.read-the-docs {
color: #888;
}
</style>
56 changes: 56 additions & 0 deletions src/data-source.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const data = createLazyLoadData();

function createLazyLoadData() {
let lazyLoadData = [];
let customerid = ['VINET', 'TOMSP', 'HANAR', 'VICTE', 'SUPRD', 'HANAR', 'CHOPS', 'RICSU', 'WELLI', 'HILAA', 'ERNSH', 'CENTC',
'OTTIK', 'QUEDE', 'RATTC', 'ERNSH', 'FOLKO', 'BLONP', 'WARTH', 'FRANK', 'GROSR', 'WHITC', 'WARTH', 'SPLIR', 'RATTC', 'QUICK', 'VINET',
'MAGAA', 'TORTU', 'MORGK', 'BERGS', 'LEHMS', 'BERGS', 'ROMEY', 'ROMEY', 'LILAS', 'LEHMS', 'QUICK', 'QUICK', 'RICAR', 'REGGC', 'BSBEV',
'COMMI', 'QUEDE', 'TRADH', 'TORTU', 'RATTC', 'VINET', 'LILAS', 'BLONP', 'HUNGO', 'RICAR', 'MAGAA', 'WANDK', 'SUPRD', 'GODOS', 'TORTU',
'OLDWO', 'ROMEY', 'LONEP', 'ANATR', 'HUNGO', 'THEBI', 'DUMON', 'WANDK', 'QUICK', 'RATTC', 'ISLAT', 'RATTC', 'LONEP', 'ISLAT', 'TORTU',
'WARTH', 'ISLAT', 'PERIC', 'KOENE', 'SAVEA', 'KOENE', 'BOLID', 'FOLKO', 'FURIB', 'SPLIR', 'LILAS', 'BONAP', 'MEREP', 'WARTH', 'VICTE',
'HUNGO', 'PRINI', 'FRANK', 'OLDWO', 'MEREP', 'BONAP', 'SIMOB', 'FRANK', 'LEHMS', 'WHITC', 'QUICK', 'RATTC', 'FAMIA'];

let product = ['Chai', 'Chang', 'Aniseed Syrup', 'Chef Anton\'s Cajun Seasoning', 'Chef Anton\'s Gumbo Mix', 'Grandma\'s Boysenberry Spread',
'Uncle Bob\'s Organic Dried Pears', 'Northwoods Cranberry Sauce', 'Mishi Kobe Niku', 'Ikura', 'Queso Cabrales', 'Queso Manchego La Pastora', 'Konbu',
'Tofu', 'Genen Shouyu', 'Pavlova', 'Alice Mutton', 'Carnarvon Tigers', 'Teatime Chocolate Biscuits', 'Sir Rodney\'s Marmalade', 'Sir Rodney\'s Scones',
'Gustaf\'s Knäckebröd', 'Tunnbröd', 'Guaraná Fantástica', 'NuNuCa Nuß-Nougat-Creme', 'Gumbär Gummibärchen', 'Schoggi Schokolade', 'Rössle Sauerkraut',
'Thüringer Rostbratwurst', 'Nord-Ost Matjeshering', 'Gorgonzola Telino', 'Mascarpone Fabioli', 'Geitost', 'Sasquatch Ale', 'Steeleye Stout', 'Inlagd Sill',
'Gravad lax', 'Côte de Blaye', 'Chartreuse verte', 'Boston Crab Meat', 'Jack\'s New England Clam Chowder', 'Singaporean Hokkien Fried Mee', 'Ipoh Coffee',
'Gula Malacca', 'Rogede sild', 'Spegesild', 'Zaanse koeken', 'Chocolade', 'Maxilaku', 'Valkoinen suklaa', 'Manjimup Dried Apples', 'Filo Mix', 'Perth Pasties',
'Tourtière', 'Pâté chinois', 'Gnocchi di nonna Alice', 'Ravioli Angelo', 'Escargots de Bourgogne', 'Raclette Courdavault', 'Camembert Pierrot', 'Sirop d\'érable',
'Tarte au sucre', 'Vegie-spread', 'Wimmers gute Semmelknödel', 'Louisiana Fiery Hot Pepper Sauce', 'Louisiana Hot Spiced Okra', 'Laughing Lumberjack Lager', 'Scottish Longbreads',
'Gudbrandsdalsost', 'Outback Lager', 'Flotemysost', 'Mozzarella di Giovanni', 'Röd Kaviar', 'Longlife Tofu', 'Rhönbräu Klosterbier', 'Lakkalikööri', 'Original Frankfurter grüne Soße'];

let customername = ['Maria', 'Ana Trujillo', 'Antonio Moreno', 'Thomas Hardy', 'Christina Berglund', 'Hanna Moos', 'Frédérique Citeaux', 'Martín Sommer', 'Laurence Lebihan', 'Elizabeth Lincoln',
'Victoria Ashworth', 'Patricio Simpson', 'Francisco Chang', 'Yang Wang', 'Pedro Afonso', 'Elizabeth Brown', 'Sven Ottlieb', 'Janine Labrune', 'Ann Devon', 'Roland Mendel', 'Aria Cruz', 'Diego Roel',
'Martine Rancé', 'Maria Larsson', 'Peter Franken', 'Carine Schmitt', 'Paolo Accorti', 'Lino Rodriguez', 'Eduardo Saavedra', 'José Pedro Freyre', 'André Fonseca', 'Howard Snyder', 'Manuel Pereira',
'Mario Pontes', 'Carlos Hernández', 'Yoshi Latimer', 'Patricia McKenna', 'Helen Bennett', 'Philip Cramer', 'Daniel Tonini', 'Annette Roulet', 'Yoshi Tannamuri', 'John Steel', 'Renate Messner', 'Jaime Yorres',
'Carlos González', 'Felipe Izquierdo', 'Fran Wilson', 'Giovanni Rovelli', 'Catherine Dewey', 'Jean Fresnière', 'Alexander Feuer', 'Simon Crowther', 'Yvonne Moncada', 'Rene Phillips', 'Henriette Pfalzheim',
'Marie Bertrand', 'Guillermo Fernández', 'Georg Pipps', 'Isabel de Castro', 'Bernardo Batista', 'Lúcia Carvalho', 'Horst Kloss', 'Sergio Gutiérrez', 'Paula Wilson', 'Maurizio Moroni', 'Janete Limeira', 'Michael Holz',
'Alejandra Camino', 'Jonas Bergulfsen', 'Jose Pavarotti', 'Hari Kumar', 'Jytte Petersen', 'Dominique Perrier', 'Art Braunschweiger', 'Pascale Cartrain', 'Liz Nixon', 'Liu Wong', 'Karin Josephs', 'Miguel Angel Paolino',
'Anabela Domingues', 'Helvetius Nagy', 'Palle Ibsen', 'Mary Saveley', 'Paul Henriot', 'Rita Müller', 'Pirkko Koskitalo', 'Paula Parente', 'Karl Jablonski', 'Matti Karttunen', 'Zbyszek Piestrzeniewicz'];

let customeraddress = ['507 - 20th Ave. E.\r\nApt. 2A', '908 W. Capital Way', '722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'4726 - 11th Ave. N.E.', '7 Houndstooth Rd.', '59 rue de l\'Abbaye', 'Luisenstr. 48', '908 W. Capital Way', '722 Moss Bay Blvd.', '4110 Old Redmond Rd.', '14 Garrett Hill', 'Coventry House\r\nMiner Rd.', 'Edgeham Hollow\r\nWinchester Way',
'7 Houndstooth Rd.', '2817 Milton Dr.', 'Kirchgasse 6', 'Sierras de Granada 9993', 'Mehrheimerstr. 369', 'Rua da Panificadora, 12', '2817 Milton Dr.', 'Mehrheimerstr. 369'];

let quantityperunit= ['10 boxes x 20 bags', '24 - 12 oz bottles', '12 - 550 ml bottles', '48 - 6 oz jars', '36 boxes', '12 - 8 oz jars', '12 - 1 lb pkgs.', '12 - 12 oz jars', '18 - 500 g pkgs.', '12 - 200 ml jars',
'1 kg pkg.', '10 - 500 g pkgs.', '2 kg box', '40 - 100 g pkgs.', '24 - 250 ml bottles', '32 - 500 g boxes', '20 - 1 kg tins', '16 kg pkg.', '10 boxes x 12 pieces', '30 gift boxes', '24 pkgs. x 4 pieces', '24 - 500 g pkgs.', '12 - 250 g pkgs.',
'12 - 355 ml cans', '20 - 450 g glasses', '100 - 250 g bags'];

let OrderID = 10248;
for (let i = 0; i < 20000; i++) {
lazyLoadData.push({
'OrderID': OrderID + i,
'CustomerID': customerid[Math.floor(Math.random() * customerid.length)],
'CustomerName': customername[Math.floor(Math.random() * customername.length)],
'CustomerAddress': customeraddress[Math.floor(Math.random() * customeraddress.length)],
'ProductName': product[Math.floor(Math.random() * product.length)],
'ProductID': i,
'Quantity': quantityperunit[Math.floor(Math.random() * quantityperunit.length)]
})
}
return lazyLoadData;
}

export default data;
4 changes: 4 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
Loading