New to Kendo UI for AngularStart a free 30-day trial

Implementing CRUD Operations in Master and Detail Grid

Updated on Feb 25, 2026

Environment

ProductProgress® Kendo UI for Angular Grid

Description

I need to enable full CRUD (Create, Read, Update, Delete) operations in a master-detail Grid where both the master and the detail Grid support editing. How can I ensure that changes made in the detail Grid persist when collapsing and re-expanding the detail rows?

This Knowledge Base article also answers the following questions:

  • How to edit data in both master and detail Grids?
  • How to synchronize data between master and detail Grids?
  • How to ensure changes persist when collapsing/expanding detail rows?
  • How to use inline editing in a hierarchical Grid structure?

Solution

To implement CRUD operations in both the master and detail Grids with proper data synchronization, use custom editing services that implement the EditService interface. This approach ensures that changes persist across expand/collapse operations.

The following example demonstrates the full implementation of the suggested approach.

Change Theme
Theme
Loading ...

Follow these steps to achieve the implementation:

  1. Create custom editing services that implement the EditService interface for both the master and detail Grids.

    For complete details on implementing custom editing services, refer to the Custom Editing Service documentation.

  2. Declare the data collections outside the service classes so all instances share the same data. This ensures that when multiple service instances are created (one for each expanded detail row), they all reference and modify the same underlying data collections.

    typescript
    // Data storage
    const categories: Category[] = [];
    const products: Product[] = [];
    
    @Injectable()
    export class CategoryEditService extends BehaviorSubject<Category[]> implements EditService {
        // Service methods reference the categories array (master Grid)
    }
    
    @Injectable()
    export class ProductEditService extends BehaviorSubject<Product[]> implements EditService {
        // Service methods reference the products array (detail Grid)
    }
  3. Configure the master Grid with the kendoGridReactiveEditing directive to enable inline editing and bind the respective editing service using the editService input.

    typescript
    @Component({
        providers: [CategoryEditService],
        template: `
            <kendo-grid
                [kendoGridReactiveEditing]="createCategoryFormGroup"
                [editService]="categoryEditService"
                [data]="view | async"
            >
               ...
            </kendo-grid>
        `
    })
    export class AppComponent implements OnInit {
        public view: Observable<Category[]>;
    
        constructor(public categoryEditService: CategoryEditService) {}
    }
  4. Define a trackBy function for the master Grid to track changes by a unique field, thus ensuring proper detail Grid references during CRUD operations.

    TS
    public trackByItem(index: number, item: GridItem): any {
        return item.data['CategoryID'];
    }
  5. Add a detail template with a condition in the master Grid using the kendoGridDetailTemplateShowIf directive to display a detail Grid only when the parent row has related data.

    HTML
    <kendo-grid ...>
       <ng-template 
           kendoGridDetailTemplate 
           let-dataItem 
           [kendoGridDetailTemplateShowIf]="hasProducts">
           <category-details [category]="dataItem"></category-details>
       </ng-template>
    </kendo-grid>
  6. Create a separate component for the detail Grid that receives the parent row data as an input. Bind the input to the let-dataItem variable from the detail template.

    typescript
    @Component({
        selector: 'category-details',
        template: `
            <kendo-grid>
            </kendo-grid>
        `
    })
    export class CategoryDetailComponent {
        @Input() public category: Category;
    }
  7. Register the detail editing service at the component level to create a separate instance for each detail Grid. This allows each detail Grid to manage CRUD operations independently while all service instances reference the same underlying data collection.

    typescript
    @Component({
        selector: 'category-details',
        providers: [ProductEditService],
        ...
    })
    export class CategoryDetailComponent {
        constructor(public productEditService: ProductEditService) {}
    }
  8. In a similar way, enable inline editing in the detail Grid and use the editService input to bind the detail editing service.

    HTML
    <kendo-grid
        [kendoGridReactiveEditing]="createProductFormGroup"
        [editService]="productEditService"
        [data]="view | async"
    >
        ...
    </kendo-grid>
  9. Use the parent row data (received from the let-dataItem variable in the detail template) to load the detail data specific to that parent row.

    typescript
    ngOnInit(): void {
        this.view = this.productEditService;
        this.productEditService.setCategoryId(this.category.CategoryID);
        this.productEditService.read();
    }

See Also

In this article
EnvironmentDescriptionSolutionSee Also
Not finding the help you need?
Contact Support