Repository: DevExpress/devextreme-react
Pull request #160 (2018-07-19 08:15:51)

Support several nested templates


Patch:
diff --git a/example/data-grid-example.tsx b/example/data-grid-example.tsx
index fe0d470..6284a5c 100644
--- a/example/data-grid-example.tsx
+++ b/example/data-grid-example.tsx
@@ -25,6 +25,10 @@ const DetailComponent = (props: any) => {
     );
 };
 
+const CityComponent = (props: any) => {
+    return <i>{props.displayValue}</i>;
+};
+
 export default class extends React.Component<any, { expandAll: boolean, pageSize: number }> {
 
     constructor(props: any) {
@@ -68,7 +72,7 @@ export default class extends React.Component<any, { expandAll: boolean, pageSize
                     <Selection mode="multiple" />
 
                     <Column dataField="orderId" caption="Order ID" width={90} />
-                    <Column dataField="city" />
+                    <Column dataField="city" cellComponent={CityComponent}/>
                     <Column dataField="country" groupIndex={0} width={180} />
                     <Column dataField="region" />
                     <Column dataField="date" dataType="date" />
diff --git a/src/core/options-manager.ts b/src/core/options-manager.ts
index f099b4b..8d97d29 100644
--- a/src/core/options-manager.ts
+++ b/src/core/options-manager.ts
@@ -147,9 +147,9 @@ class OptionsManager {
     ): Record<string, any> {
         const nestedOptions: Record<string, any> = {};
 
+        let templates = {};
         Object.keys(optionsCollection).forEach((key) => {
             const nestedOption = optionsCollection[key];
-            let templates = {};
             const options = nestedOption.elementEntries.map((e, index) => {
                 const props = separateProps(e.element.props,
                     nestedOption.defaults,
@@ -174,15 +174,15 @@ class OptionsManager {
                     ...this._getNestedOptionsObjects(e.children, stateUpdater)
                 };
             });
-            if (Object.keys(templates).length) {
-                nestedOptions.integrationOptions = {
-                    templates
-                };
-            }
-
             nestedOptions[nestedOption.name] = nestedOption.isCollectionItem ? options : options[options.length - 1];
         });
 
+        if (Object.keys(templates).length) {
+            nestedOptions.integrationOptions = {
+                templates
+            };
+        }
+
         return nestedOptions;
     }
 


Test patch:
diff --git a/src/core/__tests__/template.test.tsx b/src/core/__tests__/template.test.tsx
index b0094ca..ff6a77e 100644
--- a/src/core/__tests__/template.test.tsx
+++ b/src/core/__tests__/template.test.tsx
@@ -236,7 +236,7 @@ describe("nested template", () => {
 describe("component/render in nested options", () => {
 
     // tslint:disable-next-line:max-classes-per-file
-    class NestedComponentWithTemplates extends ConfigurationComponent<{
+    class NestedComponent extends ConfigurationComponent<{
         item?: any;
         itemRender?: any;
         itemComponent?: any;
@@ -250,11 +250,26 @@ describe("component/render in nested options", () => {
         }];
     }
 
+    // tslint:disable-next-line:max-classes-per-file
+    class AnotherNestedComponent extends ConfigurationComponent<{
+        content?: any;
+        contentRender?: any;
+        contentComponent?: any;
+    }> {
+        public static OwnerType = TestComponent;
+        public static OptionName = "contentOption";
+        public static TemplateProps = [{
+            tmplOption: "content",
+            render: "contentRender",
+            component: "contentComponent"
+        }];
+    }
+
     it("pass integrationOptions options to widget", () => {
         const ItemTemplate = () => <div>Template</div>;
         mount(
             <TestComponent>
-                <NestedComponentWithTemplates itemComponent={ItemTemplate} />
+                <NestedComponent itemComponent={ItemTemplate} />
             </TestComponent>
         );
 
@@ -270,11 +285,30 @@ describe("component/render in nested options", () => {
         expect(typeof integrationOptions.templates.item.render).toBe("function");
     });
 
+    it("pass integrationOptions options to widget with several templates", () => {
+        const UserTemplate = () => <div>Template</div>;
+        mount(
+            <TestComponent>
+                <NestedComponent itemComponent={UserTemplate} />
+                <AnotherNestedComponent contentRender={UserTemplate} />
+            </TestComponent>
+        );
+
+        const options = WidgetClass.mock.calls[0][1];
+
+        expect(options.option.item).toBe("item");
+        expect(options.contentOption.content).toBe("content");
+
+        const integrationOptions = options.integrationOptions;
+
+        expect(Object.keys(integrationOptions.templates)).toEqual(["item", "content"]);
+    });
+
     it("renders templates", () => {
         const FirstTemplate = () => <div className={"template"}>First Template</div>;
         const component = mount(
             <TestComponent>
-                <NestedComponentWithTemplates itemComponent={FirstTemplate} />
+                <NestedComponent itemComponent={FirstTemplate} />
             </TestComponent >
         );
         renderItemTemplate();
@@ -283,7 +317,7 @@ describe("component/render in nested options", () => {
 
         const SecondTemplate = () => <div className={"template"}>Second Template</div>;
         component.setProps({
-            children: <NestedComponentWithTemplates itemComponent={SecondTemplate} />
+            children: <NestedComponent itemComponent={SecondTemplate} />
         });
         component.update();
         expect(component.find(".template").html()).toBe('<div class="template">Second Template</div>');