Performing CRUD Operations with Firebase
Environment
| Product | Progress® Kendo UI for Angular Grid |
Description
How can I use Google's Firebase as a data source for the Grid and perform CRUD operations?
Solution
The Kendo UI for Angular Grid can be easily integrated with Firebase, allowing you to perform CRUD operations on a real-time database. The following steps outline the process of setting up the integration and implementing CRUD functionality.
This article uses the AngularFire compatibility API (
@angular/fire/compat) which provides a migration path from older AngularFire versions. For new projects, consider using the modular API from@angular/fire/database.
Configuring the Firebase Database
-
Create a clean Angular project by using the Angular CLI tool.
-
Create a new Firebase project by using the Google instructions.
-
Install the @angular/fire NPM package by running
npm install @angular/fire firebase --save. -
Configure Firebase in your Angular project. For standalone components (recommended), add the Firebase configuration to
app.config.ts:tsimport { ApplicationConfig } from '@angular/core'; import { provideFirebaseApp, initializeApp } from '@angular/fire/app'; import { provideDatabase, getDatabase } from '@angular/fire/database'; const firebaseConfig = { apiKey: "AIzaSyD68ysdlWJT8yLB7kSUcCuxlrWBqUPX4Tg", authDomain: "kendo-grid-crud.firebaseapp.com", databaseURL: "https://kendo-grid-crud.firebaseio.com", projectId: "kendo-grid-crud", storageBucket: "kendo-grid-crud.appspot.com", messagingSenderId: "1005892024994", appId: "1:1005892024994:web:e74d331eb7cd46f13335fb" }; export const appConfig: ApplicationConfig = { providers: [ provideFirebaseApp(() => initializeApp(firebaseConfig)), provideDatabase(() => getDatabase()) ] };Alternatively, for NgModule-based projects, add the Firebase configuration to
app.module.ts:tsimport { AngularFireModule } from '@angular/fire/compat'; import { AngularFireDatabaseModule } from '@angular/fire/compat/database'; const firebaseConfig = { apiKey: "AIzaSyD68ysdlWJT8yLB7kSUcCuxlrWBqUPX4Tg", authDomain: "kendo-grid-crud.firebaseapp.com", databaseURL: "https://kendo-grid-crud.firebaseio.com", projectId: "kendo-grid-crud", storageBucket: "kendo-grid-crud.appspot.com", messagingSenderId: "1005892024994", appId: "1:1005892024994:web:e74d331eb7cd46f13335fb" }; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AngularFireModule.initializeApp(firebaseConfig), AngularFireDatabaseModule, GridModule, BrowserAnimationsModule, ButtonsModule ], providers: [EditService], bootstrap: [AppComponent] }) export class AppModule { } -
Add the Grid package to the project and follow the example on Reactive Forms editing.
-
Create a service that holds the functions for the CRUD operations.
tsimport { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { AngularFireDatabase, AngularFireList } from '@angular/fire/compat/database'; import { products } from './products'; @Injectable({ providedIn: 'root' }) export class EditService { private itemsRef: AngularFireList<any>; constructor(private db: AngularFireDatabase) { this.itemsRef = this.db.list('products'); } public get(): Observable<any[]> { return this.itemsRef.snapshotChanges().pipe( map(changes => changes.map(c => ({ key: c.payload.key, ...c.payload.val() as object })) ) ); } public save(data: any, isNew?: boolean): void { if (isNew) { this.itemsRef.push(data); } else { this.itemsRef.update(data.key, data); } } public remove(data: any): void { this.itemsRef.remove(data.key); } public resetData(): void { this.db.object('/').set(products); } } -
Whenever you want to perform a CRUD operation, call the respective
EditServicefunctions.tsimport { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { EditService } from './edit.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { public formGroup: FormGroup; private editedRowIndex: number; public view: Observable<any[]>; constructor(public editService: EditService) { this.view = this.editService.get(); } public addHandler({ sender }): void { this.closeEditor(sender); this.formGroup = new FormGroup({ 'ProductID': new FormControl(), 'ProductName': new FormControl('', Validators.required), 'UnitPrice': new FormControl(0), 'UnitsInStock': new FormControl('', Validators.compose([Validators.required, Validators.pattern('^[0-9]{1,3}')])), 'Discontinued': new FormControl(false) }); sender.addRow(this.formGroup); } public editHandler({ sender, rowIndex, dataItem }): void { this.closeEditor(sender); this.formGroup = new FormGroup({ 'ProductID': new FormControl(dataItem.ProductID), 'ProductName': new FormControl(dataItem.ProductName, Validators.required), 'UnitPrice': new FormControl(dataItem.UnitPrice), 'UnitsInStock': new FormControl( dataItem.UnitsInStock, Validators.compose([Validators.required, Validators.pattern('^[0-9]{1,3}')]) ), 'Discontinued': new FormControl(dataItem.Discontinued) }); this.editedRowIndex = rowIndex; sender.editRow(rowIndex, this.formGroup); } public cancelHandler({ sender, rowIndex }): void { this.closeEditor(sender, rowIndex); } public saveHandler({ sender, rowIndex, formGroup, isNew, dataItem }): void { const product = formGroup.value; product.key = dataItem.key; this.editService.save(product, isNew); sender.closeRow(rowIndex); } public removeHandler({ dataItem }): void { this.editService.remove(dataItem); } private closeEditor(grid: any, rowIndex = this.editedRowIndex): void { grid.closeRow(rowIndex); this.editedRowIndex = undefined; this.formGroup = undefined; } public resetData(): void { this.editService.resetData(); } }