NestJS Integration
ZingGrid works with your development stack, including NestJS! In this guide, we'll walk you through how to add ZingGrid to your NestJS CRUD app.
Usage
-
Include the following dependencies in the header of your HTML file:
<script src="path/to/zinggrid.min.js" defer></script>
-
Create a
<zing-grid>
component, like so:<zing-grid id="myGrid" caption="Hello Doggos"></zing-grid>
-
Use JavaScript to set or change your data, like so:
window.addEventListener(() => { let zgRef = document.querySelector('zing-grid'); zgRef.data = [ { "breed": "Dachshund", "name": "Sousage"}, { "breed": "Corgi", "name": "Plop"}, { "breed": "Pomeranian", "name": "Floof"} ]; });
Setting up a CRUD App
This walkthrough will guide you through setting up a CRUD app utilizing NestJS CRUD API and hook it up to your grid.
Setting up the Project
Install the Nest CLI, the create and navigate to the project:
npm i -g @nest/cli nest new project-name cd project-name
Generate CRUD API
Then generate the CRUD API using the command:
nest g resource
For this demo, enter the following for the prompt:
- "users" as the name for the resource
- Select "REST API" as the transport layer
- Select "Yes" to generate the CRUD entry points
When the command finish generating the CRUD API endpoints, you'll notice that all the methods are there except for "PUT". Since ZingGrid uses the "PUT" method for record editing, let's add the method and placeholder.
- Go to
src/users/users.controller.ts
- In line 1, include "PUT" in the import
import { Controller, Get, Post, Body, Patch, Put, Param, Delete } from '@nestjs/common';
- Add the placeholder for the "PUT" endpoint
@Put(':id') updateCell(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { return this.usersService.update(id, updateUserDto); }
With the endpoints created, let's prefix every registered route with "api" using setGlobalPrefix()
.
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.setGlobalPrefix('api'); await app.listen(3000); } bootstrap();
Create Docker/MongoDB to Run Database
In this step, you can either choose Docker or MongoDB to run the database.
Docker
Install Docker from their site.
After, create docker-compose.yml
file at the root level to specify the database and ports:
version: "3" services: mongodb: image: mongo:latest environment: - MONGODB_DATABASE="test" ports: - 27017:27017
Once that is complete, run the Docker container.
MongoDB
Install MongoDB from their site.
Once the installation is complete, run MongoDB through the command:
mongod
Note that if an error occurs, create a data/db
directory.
Then set that directory as the db path:
mongod --dbpath PATH_TO/data/db
Setup Mongoose, Configure the Database, and Implement API Endpoints
Install Mongoose through the command:
npm install --save @nestjs/mongoose mongoose
Then define a DTO class in src/users/dto/create-user.dto.ts
.
export class CreateUserDto { readonly name: string; readonly age: number; }
Next, define the schema in src/users/schemas/user.schema.ts
(Don't forget to create the schemas
folder and file!).
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; export type UserDocument = User & Document; @Schema() export class User { @Prop() name: string; @Prop() age: number; } export const UserSchema = SchemaFactory.createForClass(User);
Following that, implement the services in src/users/users.service.ts
.
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { User, UserDocument } from './schemas/user.schema'; @Injectable() export class UsersService { constructor( @InjectModel(User.name) private readonly userModel: Model<UserDocument>, ) {} async create(createUserDto: CreateUserDto): Promise<User> { const createdUser = await new this.userModel(createUserDto); return createdUser.save(); } async findAll(): Promise<User[]> { return this.userModel.find().exec(); } async findOne(id: string): Promise<User> { return this.userModel.findOne({_id: id}).exec(); } async update(id: string, updateUserDto: UpdateUserDto) { return this.userModel.findByIdAndUpdate(id, updateUserDto).exec(); } async updateCell(id: string, updateUserDto: UpdateUserDto) { return this.userModel.findByIdAndUpdate(id, updateUserDto).exec(); } async remove(id: string) { const deleted = await this.userModel .findByIdAndRemove({_id: id}) .exec(); return deleted; } }
Then implement the controller in src/users/users.controller.ts
.
import { Controller, Get, Post, Body, Patch, Put, Param, Delete } from '@nestjs/common'; import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() create(@Body() createUserDto: CreateUserDto) { return this.usersService.create(createUserDto); } @Get() findAll() { return this.usersService.findAll(); } @Get(':id') findOne(@Param('id') id: string) { return this.usersService.findOne(id); } @Patch(':id') update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { return this.usersService.update(id, updateUserDto); } @Put(':id') updateCell(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { return this.usersService.update(id, updateUserDto); } @Delete(':id') remove(@Param('id') id: string) { return this.usersService.remove(id); } }
After, add the Mongoose imports and specify the controllers and providers in src/users/users.module.ts
.
Make sure for the Mongoose module to match the port and database name specified in docker-compose.yml
.
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; import { User, UserSchema } from './schemas/user.schema'; @Module({ imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])], controllers: [UsersController], providers: [UsersService] }) export class UsersModule {}
Statically Serve Client Containing ZingGrid
Almost there! Now we'll build out the client-side. First, install static-serve:
npm install --save @nestjs/serve-static
Then add the static-serve import and specify the directory to serve in src/app.module.ts
.
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { UsersModule } from './users/users.module'; import { MongooseModule } from '@nestjs/mongoose'; import { ServeStaticModule } from '@nestjs/serve-static'; import { join } from 'path'; @Module({ imports: [ UsersModule, MongooseModule.forRoot('mongodb://localhost:27017/test'), ServeStaticModule.forRoot({rootPath: join(__dirname, '..', 'client'), exclude: ['/api*']}), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Create the client
folder at the root. This is the directly that will be served.
Afterwards, create a client/index.html
file and add ZingGrid!
The grid is configured to:
- Enable editing by adding
editor-controls
attribute to the ZingGrid tag - Set columns to display using ZGColgroup and ZGColumn (
_id
column is excluded) - Set
ZGParam[src]
to specify the CRUD endpoint - Set
ZGParam[idKey]
to configure the key from the default (id
) to the one MongoDB uses (_id
)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Basic</title> <script src="https://cdn.zinggrid.com/zinggrid.min.js"></script> </head> <body> <zing-grid caption="CRUD NestJS Demo" editor-controls> <zg-colgroup> <zg-column index="name"></zg-column> <zg-column index="age" type="number"></zg-column> </zg-colgroup> <zg-data> <zg-param name="src" value="http://localhost:3000/api/users"></zg-param> <zg-param name="idKey" value="_id"></zg-param> </zg-data> </zing-grid> </body> </html>
Create NestJS Config
Create the NestJS config file at the root level.
Name this file nest.config.ts
, and set the content to:
module.exports = { async headers() { return [ { source: '/:path*{/}?', headers: [ { key: 'Access-Control-Allow-Origin', value: 'http://localhost:8082', }, ], }, ] }, }
Run App
All that's left to do is run the app! To do so, run the command:
npm run start
View your demo at localhost:3000
.
NestJS Integrated Grid
Here is our complete grid that is successfully integrated with NestJS CRUD app:
Check out the full code here!
[integrations: nestJS]