Backend API
        
    <dx-data-grid
  id="gridContainer"
  [dataSource]="employees"
  keyExpr="ID"
  [showBorders]="true"
>
  <dxi-column dataField="Prefix" [width]="70" caption="Title"></dxi-column>
  <dxi-column dataField="FirstName"></dxi-column>
  <dxi-column dataField="LastName"></dxi-column>
  <dxi-column dataField="Position" [width]="170"></dxi-column>
  <dxi-column dataField="State" [width]="125"></dxi-column>
  <dxi-column dataField="BirthDate" dataType="date"></dxi-column>
  <dxo-master-detail [enabled]="true" template="detail"></dxo-master-detail>
  <div *dxTemplate="let employee of 'detail'">
    <div class="master-detail-caption">{{
      employee.data.FirstName + " " + employee.data.LastName + "'s Tasks:"
    }}</div>
    <detail-grid [key]="employee.key"></detail-grid>
  </div>
</dx-data-grid>
    
    import { NgModule, Component, enableProdMode } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { DxDataGridModule, DxTemplateModule } from 'devextreme-angular';
import { Employee, Service } from './app.service';
import { DetailGridComponent } from './detail-grid/detail-grid.component';
if (!/localhost/.test(document.location.host)) {
  enableProdMode();
}
let modulePrefix = '';
// @ts-ignore
if (window && window.config?.packageConfigPaths) {
  modulePrefix = '/app';
}
@Component({
  selector: 'demo-app',
  templateUrl: `app/app.component.html`,
  styleUrls: [`app/app.component.css`],
  providers: [Service],
})
export class AppComponent {
  employees: Employee[];
  constructor(private service: Service) {
    this.employees = service.getEmployees();
  }
}
@NgModule({
  imports: [
    BrowserModule,
    DxDataGridModule,
    DxTemplateModule,
  ],
  declarations: [AppComponent, DetailGridComponent],
  bootstrap: [AppComponent],
})
export class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
    
    ::ng-deep #gridContainer {
  height: 440px;
}
::ng-deep .master-detail-caption {
  padding: 0 0 5px 10px;
  font-size: 14px;
  font-weight: bold;
}
    
    import { Injectable } from '@angular/core';
export class Task {
  ID: number;
  Subject: string;
  StartDate: string;
  DueDate: string;
  Status: string;
  Priority: string;
  Completion: number;
  EmployeeID: number;
}
export class Employee {
  ID: number;
  FirstName: string;
  LastName: string;
  Prefix: string;
  Position: string;
  BirthDate: string;
  State: string;
}
const employees: Employee[] = [{
  ID: 1,
  Prefix: 'Mr.',
  FirstName: 'John',
  LastName: 'Heart',
  Position: 'CEO',
  State: 'California',
  BirthDate: '1964/03/16',
},
{
  ID: 2,
  Prefix: 'Mrs.',
  FirstName: 'Olivia',
  LastName: 'Peyton',
  Position: 'Sales Assistant',
  State: 'California',
  BirthDate: '1981/06/03',
},
{
  ID: 3,
  Prefix: 'Mr.',
  FirstName: 'Robert',
  LastName: 'Reagan',
  Position: 'CMO',
  State: 'Arkansas',
  BirthDate: '1974/09/07',
},
{
  ID: 4,
  Prefix: 'Ms.',
  FirstName: 'Greta',
  LastName: 'Sims',
  Position: 'HR Manager',
  State: 'Georgia',
  BirthDate: '1977/11/22',
},
{
  ID: 5,
  Prefix: 'Mr.',
  FirstName: 'Brett',
  LastName: 'Wade',
  Position: 'IT Manager',
  State: 'Idaho',
  BirthDate: '1968/12/01',
},
{
  ID: 6,
  Prefix: 'Mrs.',
  FirstName: 'Sandra',
  LastName: 'Johnson',
  Position: 'Controller',
  State: 'Utah',
  BirthDate: '1974/11/15',
},
{
  ID: 7,
  Prefix: 'Mr.',
  FirstName: 'Kevin',
  LastName: 'Carter',
  Position: 'Shipping Manager',
  State: 'California',
  BirthDate: '1978/01/09',
},
{
  ID: 8,
  Prefix: 'Ms.',
  FirstName: 'Cynthia',
  LastName: 'Stanwick',
  Position: 'HR Assistant',
  State: 'Arkansas',
  BirthDate: '1985/06/05',
},
{
  ID: 9,
  Prefix: 'Dr.',
  FirstName: 'Kent',
  LastName: 'Samuelson',
  Position: 'Ombudsman',
  State: 'Missouri',
  BirthDate: '1972/09/11',
}];
const tasks: Task[] = [{
  ID: 1,
  Subject: 'Prepare 2013 Financial',
  StartDate: '2013/01/15',
  DueDate: '2013/01/31',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 8,
},
{
  ID: 2,
  Subject: 'Prepare 3013 Marketing Plan',
  StartDate: '2013/01/01',
  DueDate: '2013/01/31',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 5,
},
{
  ID: 3,
  Subject: 'Update Personnel Files',
  StartDate: '2013/02/03',
  DueDate: '2013/02/28',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 2,
},
{
  ID: 4,
  Subject: 'Review Health Insurance Options Under the Affordable Care Act',
  StartDate: '2013/02/12',
  DueDate: '2013/04/25',
  Status: 'In Progress',
  Priority: 'High',
  Completion: 50,
  EmployeeID: 2,
},
{
  ID: 5,
  Subject: 'Choose between PPO and HMO Health Plan',
  StartDate: '2013/02/15',
  DueDate: '2013/04/15',
  Status: 'In Progress',
  Priority: 'High',
  Completion: 75,
  EmployeeID: 1,
},
{
  ID: 6,
  Subject: 'Google AdWords Strategy',
  StartDate: '2013/02/16',
  DueDate: '2013/02/28',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 1,
},
{
  ID: 7,
  Subject: 'New Brochures',
  StartDate: '2013/02/17',
  DueDate: '2013/02/24',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 1,
},
{
  ID: 11,
  Subject: 'Rollout of New Website and Marketing Brochures',
  StartDate: '2013/02/20',
  DueDate: '2013/02/28',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 5,
},
{
  ID: 12,
  Subject: 'Update Sales Strategy Documents',
  StartDate: '2013/02/20',
  DueDate: '2013/02/22',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 9,
},
{
  ID: 15,
  Subject: 'Review 2012 Sales Report and Approve 2013 Plans',
  StartDate: '2013/02/23',
  DueDate: '2013/02/28',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 5,
},
{
  ID: 16,
  Subject: 'Deliver R&D Plans for 2013',
  StartDate: '2013/03/01',
  DueDate: '2013/03/10',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 3,
},
{
  ID: 20,
  Subject: 'Approve Hiring of John Jeffers',
  StartDate: '2013/03/02',
  DueDate: '2013/03/12',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 4,
},
{
  ID: 20,
  Subject: 'Approve Hiring of John Jeffers',
  StartDate: '2013/03/02',
  DueDate: '2013/03/12',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 6,
},
{
  ID: 21,
  Subject: 'Non-Compete Agreements',
  StartDate: '2013/03/12',
  DueDate: '2013/03/14',
  Status: 'Completed',
  Priority: 'Low',
  Completion: 100,
  EmployeeID: 2,
},
{
  ID: 22,
  Subject: 'Update NDA Agreement',
  StartDate: '2013/03/14',
  DueDate: '2013/03/16',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 1,
},
{
  ID: 23,
  Subject: 'Update Employee Files with New NDA',
  StartDate: '2013/03/16',
  DueDate: '2013/03/26',
  Status: 'Need Assistance',
  Priority: 'Normal',
  Completion: 90,
  EmployeeID: 4,
},
{
  ID: 24,
  Subject: 'Update Employee Files with New NDA',
  StartDate: '2013/03/16',
  DueDate: '2013/03/26',
  Status: 'Need Assistance',
  Priority: 'Normal',
  Completion: 90,
  EmployeeID: 6,
},
{
  ID: 25,
  Subject: 'Sign Updated NDA',
  StartDate: '2013/03/20',
  DueDate: '2013/03/25',
  Status: 'Completed',
  Priority: 'Urgent',
  Completion: 100,
  EmployeeID: 7,
},
{
  ID: 26,
  Subject: 'Sign Updated NDA',
  StartDate: '2013/03/20',
  DueDate: '2013/03/25',
  Status: 'Completed',
  Priority: 'Urgent',
  Completion: 100,
  EmployeeID: 8,
},
{
  ID: 27,
  Subject: 'Sign Updated NDA',
  StartDate: '2013/03/20',
  DueDate: '2013/03/25',
  Status: 'Need Assistance',
  Priority: 'Urgent',
  Completion: 25,
  EmployeeID: 9,
},
{
  ID: 35,
  Subject: 'Update Revenue Projections',
  StartDate: '2013/03/24',
  DueDate: '2013/04/07',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 8,
},
{
  ID: 36,
  Subject: 'Review Revenue Projections',
  StartDate: '2013/03/25',
  DueDate: '2013/04/06',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 9,
},
{
  ID: 40,
  Subject: 'Provide New Health Insurance Docs',
  StartDate: '2013/03/28',
  DueDate: '2013/04/07',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 4,
},
{
  ID: 41,
  Subject: 'Provide New Health Insurance Docs',
  StartDate: '2013/03/28',
  DueDate: '2013/04/07',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 6,
},
{
  ID: 50,
  Subject: 'Give Final Approval for Refunds',
  StartDate: '2013/05/05',
  DueDate: '2013/05/15',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 2,
},
{
  ID: 52,
  Subject: 'Review Product Recall Report by Engineering Team',
  StartDate: '2013/05/17',
  DueDate: '2013/05/20',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 1,
},
{
  ID: 55,
  Subject: 'Review Overtime Report',
  StartDate: '2013/06/10',
  DueDate: '2013/06/14',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 7,
},
{
  ID: 60,
  Subject: 'Refund Request Template',
  StartDate: '2013/06/17',
  DueDate: '2014/04/01',
  Status: 'Deferred',
  Priority: 'Normal',
  Completion: 0,
  EmployeeID: 9,
},
{
  ID: 71,
  Subject: 'Upgrade Server Hardware',
  StartDate: '2013/07/22',
  DueDate: '2013/07/31',
  Status: 'Completed',
  Priority: 'Urgent',
  Completion: 100,
  EmployeeID: 7,
},
{
  ID: 72,
  Subject: 'Upgrade Personal Computers',
  StartDate: '2013/07/24',
  DueDate: '2014/04/30',
  Status: 'In Progress',
  Priority: 'Normal',
  Completion: 85,
  EmployeeID: 7,
},
{
  ID: 74,
  Subject: 'Decide on Mobile Devices to Use in the Field',
  StartDate: '2013/07/30',
  DueDate: '2013/08/02',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 3,
},
{
  ID: 78,
  Subject: 'Try New Touch-Enabled WinForms Apps',
  StartDate: '2013/08/11',
  DueDate: '2013/08/15',
  Status: 'Completed',
  Priority: 'Normal',
  Completion: 100,
  EmployeeID: 3,
},
{
  ID: 81,
  Subject: 'Review Site Up-Time Report',
  StartDate: '2013/08/24',
  DueDate: '2013/08/30',
  Status: 'Completed',
  Priority: 'Urgent',
  Completion: 100,
  EmployeeID: 5,
},
{
  ID: 99,
  Subject: 'Submit D&B Number to ISP for Credit Approval',
  StartDate: '2013/11/04',
  DueDate: '2013/11/07',
  Status: 'Completed',
  Priority: 'High',
  Completion: 100,
  EmployeeID: 8,
},
{
  ID: 117,
  Subject: 'Approval on Converting to New HDMI Specification',
  StartDate: '2014/01/11',
  DueDate: '2014/01/31',
  Status: 'Deferred',
  Priority: 'Normal',
  Completion: 75,
  EmployeeID: 3,
},
{
  ID: 138,
  Subject: 'Review HR Budget Company Wide',
  StartDate: '2014/03/20',
  DueDate: '2014/03/25',
  Status: 'In Progress',
  Priority: 'Normal',
  Completion: 40,
  EmployeeID: 6,
},
{
  ID: 145,
  Subject: 'Final Budget Review',
  StartDate: '2014/03/26',
  DueDate: '2014/03/27',
  Status: 'In Progress',
  Priority: 'High',
  Completion: 25,
  EmployeeID: 6,
}];
@Injectable()
export class Service {
  getEmployees() {
    return employees;
  }
  getTasks() {
    return tasks;
  }
}
    
    // In real applications, you should not transpile code in the browser.
// You can see how to create your own application with Angular and DevExtreme here:
// https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/
const componentNames = [
  'accordion',
  'action-sheet',
  'autocomplete',
  'bar-gauge',
  'box',
  'bullet',
  'button-group',
  'button',
  'calendar',
  'card-view',
  'chart',
  'chat',
  'check-box',
  'circular-gauge',
  'color-box',
  'context-menu',
  'data-grid',
  'date-box',
  'date-range-box',
  'defer-rendering',
  'diagram',
  'draggable',
  'drawer',
  'drop-down-box',
  'drop-down-button',
  'file-manager',
  'file-uploader',
  'filter-builder',
  'form',
  'funnel',
  'gallery',
  'gantt',
  'html-editor',
  'linear-gauge',
  'list',
  'load-indicator',
  'load-panel',
  'lookup',
  'map',
  'menu',
  'multi-view',
  'nested',
  'number-box',
  'pagination',
  'pie-chart',
  'pivot-grid-field-chooser',
  'pivot-grid',
  'polar-chart',
  'popover',
  'popup',
  'progress-bar',
  'radio-group',
  'range-selector',
  'range-slider',
  'recurrence-editor',
  'resizable',
  'responsive-box',
  'sankey',
  'scheduler',
  'scroll-view',
  'select-box',
  'slider',
  'sortable',
  'sparkline',
  'speed-dial-action',
  'splitter',
  'stepper',
  'switch',
  'tab-panel',
  'tabs',
  'tag-box',
  'text-area',
  'text-box',
  'tile-view',
  'toast',
  'toolbar',
  'tooltip',
  'tree-list',
  'tree-map',
  'tree-view',
  'validation-group',
  'validation-summary',
  'validator',
  'vector-map',
];
window.exports = window.exports || {};
window.config = {
  transpiler: 'ts',
  typescriptOptions: {
    module: 'system',
    emitDecoratorMetadata: true,
    experimentalDecorators: true,
  },
  meta: {
    'typescript': {
      'exports': 'ts',
    },
    'devextreme/time_zone_utils.js': {
      'esModule': true,
    },
    'devextreme/localization.js': {
      'esModule': true,
    },
    'devextreme/viz/palette.js': {
      'esModule': true,
    },
    '@angular/platform-browser-dynamic': {
      'esModule': true,
    },
    '@angular/platform-browser': {
      'esModule': true,
    },
    '@angular/core': {
      'esModule': true,
    },
    '@angular/common': {
      'esModule': true,
    },
    '@angular/common/http': {
      'esModule': true,
    },
    '@angular/animations': {
      'esModule': true,
    },
    '@angular/forms': {
      'esModule': true,
    },
    'openai': {
      'esModule': true,
    },
  },
  paths: {
    'npm:': 'https://cdn.jsdelivr.net/npm/',
    'bundles:': '../../../../bundles/',
    'externals:': '../../../../bundles/externals/',
  },
  map: {
    'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js',
    'typescript': 'npm:typescript@4.2.4/lib/typescript.js',
    'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js',
    /* @angular */
    '@angular/compiler': 'bundles:@angular/compiler.umd.js',
    '@angular/platform-browser-dynamic': 'bundles:@angular/platform-browser-dynamic.umd.js',
    '@angular/core': 'bundles:@angular/core.umd.js',
    '@angular/core/primitives/signals': 'bundles:@angular/core.primitives.signals.umd.js',
    '@angular/common': 'bundles:@angular/common.umd.js',
    '@angular/common/http': 'bundles:@angular/common-http.umd.js',
    '@angular/platform-browser': 'bundles:@angular/platform-browser.umd.js',
    '@angular/platform-browser/animations': 'bundles:@angular/platform-browser.umd.js',
    '@angular/forms': 'bundles:@angular/forms.umd.js',
    /* devextreme */
    'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs',
    'devextreme-quill': 'npm:devextreme-quill@1.7.6/dist/dx-quill.min.js',
    'devexpress-diagram': 'npm:devexpress-diagram@2.2.24',
    'devexpress-gantt': 'npm:devexpress-gantt@4.1.64',
    /* devextreme-angular umd maps */
    'devextreme-angular': 'bundles:devextreme-angular/devextreme-angular.umd.js',
    'devextreme-angular/common/ai-integration': 'bundles:devextreme-angular/devextreme-angular-common-ai-integration.umd.js',
    'devextreme-angular/core': 'bundles:devextreme-angular/devextreme-angular-core.umd.js',
    'devextreme-angular/common/charts': 'bundles:devextreme-angular/devextreme-angular-common-charts.umd.js',
    'devextreme-angular/common/core/animation': 'bundles:devextreme-angular/devextreme-angular-common-core-animation.umd.js',
    'devextreme-angular/common/core/environment': 'bundles:devextreme-angular/devextreme-angular-common-core-environment.umd.js',
    'devextreme-angular/common/core/events': 'bundles:devextreme-angular/devextreme-angular-common-core-events.umd.js',
    'devextreme-angular/common/core/localization': 'bundles:devextreme-angular/devextreme-angular-common-core-localization.umd.js',
    'devextreme-angular/common/core': 'bundles:devextreme-angular/devextreme-angular-common-core.umd.js',
    'devextreme-angular/common/data/custom-store': 'bundles:devextreme-angular/devextreme-angular-common-data-custom-store.umd.js',
    'devextreme-angular/common/data': 'bundles:devextreme-angular/devextreme-angular-common-data.umd.js',
    'devextreme-angular/common/export/excel': 'bundles:devextreme-angular/devextreme-angular-common-export-excel.umd.js',
    'devextreme-angular/common/export/pdf': 'bundles:devextreme-angular/devextreme-angular-common-export-pdf.umd.js',
    'devextreme-angular/common/export': 'bundles:devextreme-angular/devextreme-angular-common-export.umd.js',
    'devextreme-angular/common/grids': 'bundles:devextreme-angular/devextreme-angular-common-grids.umd.js',
    'devextreme-angular/common': 'bundles:devextreme-angular/devextreme-angular-common.umd.js',
    'devextreme-angular/http': 'bundles:devextreme-angular/devextreme-angular-http.umd.js',
    'devextreme-angular/core/tokens': 'bundles:devextreme-angular/devextreme-angular-core-tokens.umd.js',
    ...componentNames.reduce((acc, name) => {
      acc[`devextreme-angular/ui/${name}`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}.umd.js`;
      acc[`devextreme-angular/ui/${name}/nested`] = `bundles:devextreme-angular/devextreme-angular-ui-${name}-nested.umd.js`;
      return acc;
    }, {}),
    'tslib': 'npm:tslib/tslib.js',
    'rxjs': 'npm:rxjs@7.5.3/dist/bundles/rxjs.umd.js',
    'rxjs/operators': 'npm:rxjs@7.5.3/dist/cjs/operators/index.js',
    'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
    'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js',
    'es6-object-assign': 'npm:es6-object-assign',
    'inferno': 'npm:inferno@8.2.3/dist/inferno.min.js',
    'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js',
    'inferno-create-element': 'npm:inferno-create-element@8.2.3/dist/inferno-create-element.min.js',
    'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js',
    'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js',
    'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js',
    'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js',
    'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js',
    '@preact/signals-core': 'npm:@preact/signals-core@1.8.0/dist/signals-core.min.js',
    // Prettier
    'prettier/standalone': 'npm:prettier@2.8.8/standalone.js',
    'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js',
  },
  packages: {
    'app': {
      main: './app.component.ts',
      defaultExtension: 'ts',
    },
    'devextreme': {
      defaultExtension: 'js',
    },
    'devextreme/events/utils': {
      main: 'index',
    },
    'devextreme/common/core/events/utils': {
      main: 'index',
    },
    'devextreme/events': {
      main: 'index',
    },
    'es6-object-assign': {
      main: './index.js',
      defaultExtension: 'js',
    },
    'rxjs': {
      defaultExtension: 'js',
    },
    'rxjs/operators': {
      defaultExtension: 'js',
    },
  },
  packageConfigPaths: [
    'npm:@devextreme/*/package.json',
    'npm:rxjs@7.5.3/package.json',
    'npm:rxjs@7.5.3/operators/package.json',
    'npm:devexpress-diagram@2.2.24/package.json',
    'npm:devexpress-gantt@4.1.64/package.json',
  ],
};
System.config(window.config);
// System.import('@angular/compiler').catch(console.error.bind(console));
// eslint-disable-next-line
const useTgzInCSB = ['openai'];
let packagesInfo = {
 "@angular/core": {
  "version": "17.3.12"
 },
 "core-js": {
  "version": "2.6.12"
 },
 "typescript": {
  "version": "5.4.5"
 },
 "zone.js": {
  "version": "0.14.10"
 }
};
    
    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
  <head>
    <title>DevExtreme Demo</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
    <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/25.1.6/css/dx.light.css" />
    <script src="https://cdn.jsdelivr.net/npm/core-js@2.6.12/client/shim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/zone.js@0.14.10/bundles/zone.umd.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/reflect-metadata@0.1.13/Reflect.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/systemjs@0.21.3/dist/system.js"></script>
    <script src="config.js"></script>
    <script>
      System.import("app").catch(console.error.bind(console));
    </script>
  </head>
  <body class="dx-viewport">
    <div class="demo-container">
      <demo-app>Loading...</demo-app>
    </div>
  </body>
</html>
    
    <dx-data-grid
  [dataSource]="tasksDataSource"
  [showBorders]="true"
  [columnAutoWidth]="true"
>
  <dxi-column dataField="Subject" dataType="string"></dxi-column>
  <dxi-column dataField="StartDate" dataType="date"></dxi-column>
  <dxi-column dataField="DueDate" dataType="date"></dxi-column>
  <dxi-column dataField="Priority" dataType="string"></dxi-column>
  <dxi-column
    caption="Completed"
    dataType="boolean"
    [calculateCellValue]="completedValue"
  ></dxi-column>
</dx-data-grid>
    
    import { Component, Input, AfterViewInit } from '@angular/core';
import { DataSource, ArrayStore } from 'devextreme-angular/common/data';
import { Service, Task } from '../app.service';
let modulePrefix = '';
// @ts-ignore
if (window && window.config?.packageConfigPaths) {
  modulePrefix = '/app';
}
@Component({
  selector: 'detail-grid',
  templateUrl: `.${modulePrefix && (`${modulePrefix}/detail-grid`)}/detail-grid.component.html`,
  providers: [Service],
})
export class DetailGridComponent implements AfterViewInit {
  @Input() key: number;
  tasksDataSource: DataSource;
  tasks: Task[];
  constructor(private service: Service) {
    this.tasks = service.getTasks();
  }
  ngAfterViewInit() {
    this.tasksDataSource = new DataSource({
      store: new ArrayStore({
        data: this.tasks,
        key: 'ID',
      }),
      filter: ['EmployeeID', '=', this.key],
    });
  }
  completedValue(rowData) {
    return rowData.Status === 'Completed';
  }
}