Repository: DevExpress/devextreme-react (js)

Issue:
List groupComponent does not send key value from grouped dataSource
### Issue Type
bug report

### Description
The issue is related to grouped List

#### Current Behavior
key value is undefined in groupComponent  

#### Expected Behavior
key value has value from grouped dataSource

#### Demo
https://stackblitz.com/edit/devextreme-react-71rsvj?file=index.js


Pull request description:
Add `dxkey` prop
Fix #148 

Patch:
diff --git a/README.md b/README.md
index 441ace8..3ae8c35 100644
--- a/README.md
+++ b/README.md
@@ -272,6 +272,8 @@ ReactDOM.render(
 );
 ```
 
+**Note: You cannot use the `key` prop in template components because it is a special [React prop](https://reactjs.org/warnings/special-props.html ). Use `dxkey` instead.**
+
 Use the `render` property to specify a rendering function for a widget with `template` option:
 ```jsx
 import React from 'react';
diff --git a/example/app.tsx b/example/app.tsx
index 1313d35..0dd1fb3 100644
--- a/example/app.tsx
+++ b/example/app.tsx
@@ -12,15 +12,14 @@ import Example from "./example-block";
 import FormExample from "./form-example";
 import ListExample from "./list-example";
 import PopupExample from "./popup-example";
+import SchedulerExample from "./scheduler-example";
 import ScrollViewExample from "./scroll-view-example";
 import SlideOutViewExample from "./slide-out-view-example";
 import TextBoxExample from "./text-box-example";
 import ToolbarExample from "./toolbar-example";
 import ValidationExample from "./validation-example";
 
-import { Button, NumberBox, Scheduler } from "../src";
-
-import { appointments } from "./data";
+import { Button, NumberBox } from "../src";
 
 ReactDOM.render(
   <div>
@@ -59,15 +58,8 @@ ReactDOM.render(
 
     <DataGridExample/>
 
-    <Example title="DxScheduler">
-      <Scheduler
-        dataSource={appointments}
-        height={400}
-        startDayHour={9}
-        defaultCurrentView={"week"}
-        defaultCurrentDate={new Date(2017, 4, 25)}
-      />
-    </Example>
+    <SchedulerExample />
+
     <ChartExample />
 
     <Example title="Element attributes">
diff --git a/example/scheduler-example.tsx b/example/scheduler-example.tsx
new file mode 100644
index 0000000..80ea7bd
--- /dev/null
+++ b/example/scheduler-example.tsx
@@ -0,0 +1,38 @@
+import * as React from "react";
+import Example from "./example-block";
+
+import { Scheduler } from "../src/ui/scheduler";
+
+import { appointments } from "./data";
+
+class DateCell extends React.PureComponent<any> {
+    public render() {
+        const now = this.props.date;
+        const start = new Date(now.getFullYear(), 0, 0).getTime();
+        const dayNumber = Math.floor((now - start) / (1000 * 60 * 60 * 24));
+        return (
+            <div style={{ height: "50px", color: now.getDay() % 6 === 0 ? "red" : "" }}>
+                <h4>{this.props.text}</h4>
+                <h5>{dayNumber}</h5>
+            </div>
+        );
+    }
+}
+
+// tslint:disable-next-line:max-classes-per-file
+export default class extends React.Component<any, any> {
+    public render() {
+        return (
+            <Example title="DxScheduler">
+                <Scheduler
+                    dateCellComponent={DateCell}
+                    dataSource={appointments}
+                    height={400}
+                    startDayHour={9}
+                    defaultCurrentView={"week"}
+                    defaultCurrentDate={new Date(2017, 4, 25)}
+                />
+          </Example>
+        );
+    }
+}
diff --git a/src/core/template-helper.ts b/src/core/template-helper.ts
index 2c971f9..f56c9aa 100644
--- a/src/core/template-helper.ts
+++ b/src/core/template-helper.ts
@@ -111,8 +111,12 @@ function wrapTemplate(templateDescr: ITemplateDescr, stateUpdater: StateUpdater)
                     ? React.createElement.bind(null, propsGetter(templateDescr.propName))
                     : propsGetter(templateDescr.propName);
 
+                const model = data.model;
+                if (model && model.hasOwnProperty("key")) {
+                    model.dxkey = model.key;
+                }
                 return React.createElement<ITemplateWrapperProps>(TemplateWrapper, {
-                    content: contentProvider(data.model),
+                    content: contentProvider(model),
                     container,
                     onRemoved: () => stateUpdater((t) => delete t[templateId]),
                     onRendered: data.onRendered,
diff --git a/src/core/template-wrapper.ts b/src/core/template-wrapper.ts
index 39b0b7a..87c3927 100644
--- a/src/core/template-wrapper.ts
+++ b/src/core/template-wrapper.ts
@@ -12,7 +12,7 @@ interface ITemplateWrapperProps {
     key: string;
 }
 
-class TemplateWrapper extends React.PureComponent<ITemplateWrapperProps, object> {
+class TemplateWrapper extends React.PureComponent<ITemplateWrapperProps> {
 
     public render() {
         return ReactDOM.createPortal(this.props.content, this.props.container);


Test patch:
diff --git a/src/core/__tests__/template.test.tsx b/src/core/__tests__/template.test.tsx
index de1b91d..59e9da2 100644
--- a/src/core/__tests__/template.test.tsx
+++ b/src/core/__tests__/template.test.tsx
@@ -181,6 +181,17 @@ describe("component template", () => {
         expect(component.find(".template").html()).toBe('<div class="template">Template with data</div>');
     });
 
+    it("renders key prop", () => {
+        const ItemTemplate = (props: any) => <div className={"template"}>key: {props.key}, dxkey: {props.dxkey}</div>;
+        const component = mount(
+            <ComponentWithTemplates itemComponent={ItemTemplate} />
+        );
+
+        renderItemTemplate({ key: "key_1" });
+        component.update();
+        expect(component.find(".template").html()).toBe('<div class="template">key: , dxkey: key_1</div>');
+    });
+
     it("renders inside component", () => {
         const ItemTemplate = (props: any) => <div className={"template"}>Template {props.text}</div>;
         const component = mount(