All Components

Consuming Data from Azure Cosmos DB

This tutorial demonstrates how to create an application with Azure Cosmos DB through SQL .NET API and Azure Portal, and configure a Kendo UI Grid for Angular to display Cosmos DB data and perform CRUD operations.

The latest version of the Kendo UI for Angular components are compatible with Angular 6. To get your application running with Angular 6, refer to the Angular Update Guide and to the following sections.

Prerequisites

Creating Azure Cosmos DB Applications

  1. Follow the Build a .NET web app with Azure Cosmos DB using the SQL API and the Azure Portal quickstart guide. This guide demonstrates how to create an Azure Cosmos DB SQL API account, add data and a collection by using the Azure Portal, and build and deploy a sample To-Do List web application.

  2. After successfully completing the quickstart guide, add Kendo UI to the To-Do List sample application by implementing the endpoints for the CRUD operations and configuring the Grid to use these endpoints.

Implementing the Create, Read, Update, and Destroy Actions

  1. Add the following using statements to the ItemController.

    using System.Collections.Generic;
    using Newtonsoft.Json;
    using System.Linq;
  2. Implement the four actions in the ItemController which will be called by the Grid on performing CRUD operations. Provide names for the actions—for example, KendoRead, KendoCreate, KendoUpdate, and KendoDestroy.

The following example demonstrates the Read action.

[ActionName("KendoRead")]
public async Task<ActionResult> KendoRead()
{
    var items = await DocumentDBRepository<Item>.GetItemsAsync(d => !d.Completed);

    return this.Json(items, JsonRequestBehavior.AllowGet);
}

The following example demonstrates the Create action.

[ActionName("KendoCreate")]
public async Task<ActionResult> KendoCreate(string models)
{
    var items = JsonConvert.DeserializeObject<IEnumerable<Item>>(models);


    if (items != null && ModelState.IsValid)
    {
        Item item = items.FirstOrDefault();
        await DocumentDBRepository<Item>.CreateItemAsync(item);
    }

    return Json(items, JsonRequestBehavior.AllowGet);
}

The following example demonstrates the Update action.

[ActionName("KendoUpdate")]
public async Task<ActionResult> KendoUpdate(string models)
{
    var items = JsonConvert.DeserializeObject<IEnumerable<Item>>(models);

    if (items != null && ModelState.IsValid)
    {
        Item item = items.FirstOrDefault();
        await DocumentDBRepository<Item>.UpdateItemAsync(item.Id, item);
    }

    return Json(items, JsonRequestBehavior.AllowGet);
}

The following example demonstrates the Destroy action.

[ActionName("KendoDestroy")]
public async Task<ActionResult> KendoDestroy(string models)
{
    var items = JsonConvert.DeserializeObject<IEnumerable<Item>>(models);

    if (items != null && ModelState.IsValid)
    {
        Item item = items.FirstOrDefault();
        await DocumentDBRepository<Item>.DeleteItemAsync(item.Id, item.Category);
    }

    return Json(items, JsonRequestBehavior.AllowGet);
}

Consuming the Implemented CRUD Endpoints on the Client

To consume the data from the endpoints and display it in the Grid, configure the component and its data service.

If the client Angular application will be hosted on a different domain, the Cross-Origin Resource Sharing (CORS) mechanism has to be enabled on the server.

The following example demonstrates how to implement the data service.

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { switchMap } from "rxjs/operators";
import { Observable } from "rxjs/Observable";

@Injectable()
export class DataService {
    constructor(private httpClient: HttpClient) { }

    public getTodos(): Observable<any> {
        return this.httpClient
            .get("http://localhost:43605/Item/KendoRead/");
    }

    public operation(action: string, item: any): Observable<any[]> {
        return this.httpClient
            .get(`http://localhost:43605/Item/Kendo${action}?models=${JSON.stringify([item])}`)
            .pipe(
                switchMap(r => this.getTodos())
            );
    }
}

The following example demonstrates how to bind the Grid.

import { Component } from "@angular/core";
import { DataService } from "./data.service";
import { FormGroup, Validators, FormControl } from "@angular/forms";

@Component({
  selector: "app-root",
  template: `
    <kendo-grid
      [kendoGridBinding]="data"
      (edit)="editHandler($event)" (cancel)="cancelHandler($event)"
          (save)="saveHandler($event)" (remove)="removeHandler($event)"
          (add)="addHandler($event)">
      <ng-template kendoGridToolbarTemplate>
        <button kendoGridAddCommand>Add new</button>
      </ng-template>
      <kendo-grid-column field="Id" [editable]="false"></kendo-grid-column>
      <kendo-grid-column field="Name"></kendo-grid-column>
      <kendo-grid-column field="Description"></kendo-grid-column>
      <kendo-grid-column field="Completed" editor="boolean"></kendo-grid-column>
      <kendo-grid-column field="Category"></kendo-grid-column>
      <kendo-grid-command-column>
        <ng-template kendoGridCellTemplate let-isNew="isNew">
          <button kendoGridEditCommand [primary]="true">Edit</button>
          <button kendoGridRemoveCommand>Remove</button>
          <button kendoGridSaveCommand [disabled]="formGroup?.invalid">{{ isNew ? 'Add' : 'Update' }}</button>
          <button kendoGridCancelCommand>{{ isNew ? 'Discard changes' : 'Cancel' }}</button>
        </ng-template>
      </kendo-grid-command-column>
    </kendo-grid>
  `,
  styles: []
})
export class AppComponent {
  public data;
  public formGroup: FormGroup;
  private editedRowIndex: number;

  constructor(private dataService: DataService) {
    dataService.getTodos().subscribe(r => this.data = r);
  }

  public addHandler({sender}) {
    this.closeEditor(sender);

    this.formGroup = new FormGroup({
        "Id": new FormControl(null),
        "Name": new FormControl("", Validators.required),
        "Description": new FormControl(),
        "Completed": new FormControl(false),
        "Category": new FormControl("", Validators.required)
    });

    sender.addRow(this.formGroup);
  }

  public editHandler({sender, rowIndex, dataItem}) {
      this.closeEditor(sender);

      this.formGroup = new FormGroup({
          "Id": new FormControl(dataItem.Id),
          "Name": new FormControl(dataItem.Name, Validators.required),
          "Description": new FormControl(dataItem.Description),
          "Completed": new FormControl(dataItem.Completed),
          "Category": new FormControl(dataItem.Category)
      });

      this.editedRowIndex = rowIndex;

      sender.editRow(rowIndex, this.formGroup);
  }

  public cancelHandler({sender, rowIndex}) {
      this.closeEditor(sender, rowIndex);
  }

  public saveHandler({sender, rowIndex, formGroup, isNew}) {
    this.dataService.operation(isNew ? "CREATE": "UPDATE", formGroup.value).subscribe(items => this.data = items);
    sender.closeRow(rowIndex);
  }

  public removeHandler({dataItem}) {
    this.dataService.operation("DESTROY", dataItem).subscribe(items => this.data = items);
  }

  private closeEditor(grid, rowIndex = this.editedRowIndex): void {
      grid.closeRow(rowIndex);
      this.editedRowIndex = undefined;
      this.formGroup = undefined;
  }
}
In this article