Cascading DropDownList with backing id field

Hi.
I looked at the example for a cascading dropdown list:
https://ej2.syncfusion.com/react/documentation/grid/how-to/cascading-drop-down-list-with-grid-editing/
and tried to implement it with backing fields. I couldn't really get it to work. Here an example of my attempt:

It shows the ids instead of customer name or location name. Somehow the dropdown list doesn't seem to be connected to the content. What am I doing wrong or is there a working example for this somewhere?
Thanks
Alexander


15 Replies 1 reply marked as answer

AG Ajith Govarthan Syncfusion Team January 20, 2021 12:28 PM UTC

Hi Alexander, 
 
Thanks for contacting Syncfusion support. 
 
Query: It shows the ids instead of customer name or location name. Somehow the dropdown list doesn't seem to be connected to the content. What am I doing wrong or is there a working example for this somewhere? 
 
Based on the attached sample we found that you have used the foreignkey column and edit template in your grid application. Before we proceed to your query, we need to confirm the below details to provide you the prompt solution the earliest.  
 
  1. Please let us know you want to show the customerName and the locationName in grid columns with foreign key column feature or you want to show the customerName and the locationName while perform the editing and updating the record.
 
  1. Share the screenshot or video demonstration of your requirement to understand clearly about your requirement.
 
Regards, 
Ajith G. 
 
 



AE Alexander Esser January 22, 2021 07:53 AM UTC

Hi.
In view mode it should show customerName and locationName. When editing a row it should show dropdown lists for Customer and Location where the underlying customerId and locationid are mapped correctly.
Ideally the grid datasource should only contain the customerId and locationId and the mapping is done in the Customer and Location columns.
Hope that makes sense
Best
Alexander



AE Alexander Esser January 22, 2021 08:30 AM UTC

Here a screenshot:
Example Grid
(https://1drv.ms/u/s!Appi7cLK7BVzjv5_ohdvazYTGqylZw?e=d3QtvB)


AG Ajith Govarthan Syncfusion Team January 25, 2021 12:13 PM UTC

Hi Alexander, 
 
Thanks for the update. 
 
Query: Query: It shows the ids instead of customer name or location name. Somehow the dropdown list doesn't seem to be connected to the content. What am I doing wrong or is there a working example for this somewhere? 
 
We have checked attached sample and in that sample we found that you have used the foreignkey column but you have not defined the dataSource for the foreignkey columns. By default, when you are not defined the datasource for the column then the columns will show only the grid dataSource values instead of foreignkey values.  
 
So, we suggest you use the dataSource for the columns to apply the foreignkey values properly based on the foreignkeyField and foreignkeyValue. For your convenience we have attached the sample and the documentation so please refer them for your reference. 
 
Code Example: 
Index.js 
 
export class ForeignKeyColumn extends SampleBase { 
    constructor() { 
        super(...arguments); 
        this.toolbarOptions = ['Add', 'Edit', 'Delete', 'Update', 'Cancel']; 
        this.validationRules = { required: true }; 
    } 
    render() { 
        return (<div className='control-pane'> 
                <div className='control-section'> 
                    <GridComponent dataSource={orderDetails} allowPaging={true} ref={grid => this.gridInstance = grid} allowFiltering={true} allowSorting={true} editSettings={{ allowEditing: true, allowDeleting: true, allowAdding: true }} filterSettings={{ type: 'Menu' }} toolbar={this.toolbarOptions}> 
                        <ColumnsDirective> 
                            <ColumnDirective field='OrderID' headerText='Order ID' width='120' textAlign='Right' validationRules={this.validationRules} isPrimaryKey={true}></ColumnDirective> 
                            <ColumnDirective field='CustomerID' headerText='Customer Name' width='150' validationRules={this.validationRules} foreignKeyValue='ContactName' foreignKeyField='CustomerID' dataSource={customerData}></ColumnDirective> 
                            <ColumnDirective field='Freight' headerText='Freight' width='100' format='C2' textAlign='Right' editType='numericedit'/> 
                            <ColumnDirective field='ShipName' headerText='Ship Name' width='170'></ColumnDirective> 
                            <ColumnDirective field='ShipCountry' headerText='Ship Country' width='150' editType='dropdownedit'></ColumnDirective> 
                        </ColumnsDirective> 
                        <Inject services={[Filter, Page, Edit, Sort, ForeignKey, Toolbar]}/> 
                    </GridComponent> 
                </div> 
 
            </div>); 
    } 
} 
 
render(<ForeignKeyColumn />, document.getElementById('sample')); 
 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Ajith G. 
 
 



AE Alexander Esser January 25, 2021 12:49 PM UTC

Hi.

Thank you for your example, but it doesn't exactly fit my problem. I'm interested in a cascading dropdown list example. In the example I had added (https://codesandbox.io/s/determined-haibt-rl4iz) the location depends on the customer. When I try setting the datasource of the dropdown fields the component doesn't start at all. (I assume the challenge is somewhere in using the EditCell elements and the foreign key setup).

My example is based on another example on your help pages (https://ej2.syncfusion.com/react/documentation/grid/how-to/cascading-drop-down-list-with-grid-editing/), but that example doesn't use underlying ids to connect the data grid source with the dropdown fields; it uses the text for mapping those. So I would need a short description why my example isn't working or another example the shows the correct implementation of cascading dropdown lists using underlying id values.

Please let me know if I was able to describe my problem.

Thanks
Alexander 


AG Ajith Govarthan Syncfusion Team January 29, 2021 01:43 AM UTC

Hi Alexander,  
  
Sorry for the delayed update. 
 
Query: I'm interested in a cascading dropdown list example. In the example I had added (https://codesandbox.io/s/determined-haibt-rl4iz) the location depends on the customer. When I try setting the datasource of the dropdown fields the component doesn't start at all. (I assume the challenge is somewhere in using the EditCell elements and the foreign key setup). 
 
Based on your attached sample you want to have cascading dropdown with foreignkey columns. So, based on that we have prepared sample and in that sample we have defined two foreignkey columns and also used the editTemplate feature to achieve cascading dropdown.  
 
We have also used text values to map to the dropdown dataSource as per your requirement. For your convenience we have attached the sample so please refer them for your reference. 
 
Code Example: 
Index.js 
 
import { render } from "react-dom"; 
import "./index.css"; 
import { DataManager, Query } from "@syncfusion/ej2-data"; 
import * as React from "react"; 
import { DropDownList } from "@syncfusion/ej2-dropdowns"; 
import { 
  GridComponent, 
  ColumnsDirective, 
  ColumnDirective, 
  Page, 
  Filter, 
  Inject, 
  Edit, 
  Sort, 
  ForeignKey, 
  Toolbar 
} from "@syncfusion/ej2-react-grids"; 
import { orderDetails, customerData } from "./data"; 
import { SampleBase } from "./sample-base"; 
export class ForeignKeyColumn extends SampleBase { 
  constructor() { 
    super(...arguments); 
    this.toolbarOptions = ["Add", "Edit", "Delete", "Update", "Cancel"]; 
    this.countryElem; 
    this.countryObj; 
 
    this.stateElem; 
    this.stateObj; 
 
    this.validationRules = { required: true }; 
    this.country = [ 
      { ContactName: "Paul Henriot", CustomerID: "VINET", id: "1" }, 
      { ContactName: "Karin Josephs", CustomerID: "TOMSP", id: "2" }, 
      { ContactName: "Mario Pontes", CustomerID: "HANAR", id: "3" }, 
      { ContactName: "Mary Saveley", CustomerID: "VICTE", id: "4" }, 
      { ContactName: "Pascale Cartrain", CustomerID: "SUPRD", id: "5" }, 
      { ContactName: "Yang Wang", CustomerID: "CHOPS", id: "6" } 
    ]; 
    this.stateColl = [ 
      { 
        CompanyName: "Alfreds Futterkiste", 
        CustomerID: "VINET", 
        countryId: "1", 
        stateId: "101", 
        Country: "Germany" 
      }, 
      { 
        CompanyName: "Ana Trujillo Emparedados y helados", 
        CustomerID: "TOMSP", 
        stateId: "102", 
        Country: "Mexico" 
      }, 
      { 
        CompanyName: "Antonio Moreno", 
        CustomerID: "VINET", 
        stateId: "103", 
        Country: "Mexico" 
      }, 
      { 
        CompanyName: "Around the Horn", 
        CustomerID: "HANAR", 
        stateId: "104", 
        Country: "UK" 
      }, 
      { 
        CompanyName: "Berglunds snabbköp", 
        CustomerID: "SUPRD", 
        stateId: "105", 
        Country: "Sweden" 
      }, 
      { 
        CompanyName: "Blauer See Delikatessen", 
        CustomerID: "CHOPS", 
        stateId: "106", 
        Country: "Germany" 
      }, 
      { 
        CompanyName: "Blondesddsl père et fils", 
        CustomerID: "SUPRD", 
        stateId: "105", 
        Country: "France" 
      }, 
      { 
        CompanyName: "Bólido Comidas preparadas", 
        CustomerID: "HANAR", 
        stateId: "106", 
        Country: "Spain" 
      }, 
      { 
        CompanyName: "Blauer See Delikatessen", 
        CustomerID: "VICTE", 
        stateId: "106", 
        Country: "Germany" 
      } 
    ]; 
    this.countryParams = { 
      create: () => { 
        this.countryElem = document.createElement("input"); 
        return this.countryElem; 
      }, 
      destroy: () => { 
        this.countryObj.destroy(); 
      }, 
      read: () => { 
        return this.countryObj.value; 
      }, 
      write: () => { 
        this.countryObj = new DropDownList({ 
          change: () => { 
            this.stateObj.enabled = true; 
            const tempQuery = new Query().where( 
              "CustomerID", 
              "equal", 
              this.countryObj.value 
            ); 
            this.stateObj.query = tempQuery;   // in the change event of the first dropdown generate query for second dropdown.  
            this.stateObj.text = ""; 
            this.stateObj.dataBind(); 
          }, 
          dataSource: new DataManager(this.country), 
          fields: { value: "CustomerID", text: "ContactName" }, 
          floatLabelType: "Never", 
          placeholder: "Select a country" 
        }); 
        this.countryObj.appendTo(this.countryElem); 
      } 
    }; 
    this.stateParams = { 
      create: () => { 
        this.stateElem = document.createElement("input"); 
        return this.stateElem; 
      }, 
      destroy: () => { 
        this.stateObj.destroy(); 
      }, 
      read: () => { 
        return this.stateObj.value; 
      }, 
      write: () => { 
        this.stateObj = new DropDownList({ 
          dataSource: new DataManager(this.stateColl), 
          enabled: false, 
          fields: { value: "Country", text: "CompanyName" }, 
          floatLabelType: "Never", 
          placeholder: "Select a state" 
        }); 
        this.stateObj.appendTo(this.stateElem); 
      } 
    }; 
  } 
  render() { 
    return ( 
      <div className="control-pane"> 
        <div className="control-section"> 
          <GridComponent 
            dataSource={orderDetails.slice(0, 8)} 
            allowPaging={true} 
            ref={grid => (this.gridInstance = grid)} 
            allowFiltering={true} 
            allowSorting={true} 
            editSettings={{ 
              allowEditing: true, 
              allowDeleting: true, 
              allowAdding: true 
            }} 
            filterSettings={{ type: "Menu" }} 
            toolbar={this.toolbarOptions} 
          > 
            <ColumnsDirective> 
              <ColumnDirective 
                field="OrderID" 
                headerText="Order ID" 
                width="120" 
                textAlign="Right" 
                validationRules={this.validationRules} 
                isPrimaryKey={true} 
              /> 
              <ColumnDirective 
                field="CustomerID" 
                headerText="Customer Name" 
                width="150" 
                validationRules={this.validationRules} 
                foreignKeyValue="ContactName" 
                foreignKeyField="CustomerID" 
                dataSource={customerData} 
                edit={this.countryParams} 
              /> 
 
              <ColumnDirective 
                field="Country" 
                headerText="Company Name" 
                foreignKeyValue="CompanyName" 
                foreignKeyField="Country" 
                dataSource={customerData} 
                edit={this.stateParams} 
                width="170" 
              /> 
              <ColumnDirective 
                field="Freight" 
                headerText="Freight" 
                width="100" 
                format="C2" 
                textAlign="Right" 
                editType="numericedit" 
              /> 
              <ColumnDirective 
                field="ShipCountry" 
                headerText="Ship Country" 
                width="150" 
                editType="dropdownedit" 
              /> 
            </ColumnsDirective> 
            <Inject 
              services={[Filter, Page, Edit, Sort, ForeignKey, Toolbar]} 
            /> 
          </GridComponent> 
        </div> 
      </div> 
    ); 
  } 
} 
 
render(<ForeignKeyColumn />, document.getElementById("sample")); 
 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Ajith G. 


Marked as answer

AE Alexander Esser February 1, 2021 08:05 AM UTC

Hi and thank for the example. I tried to implement something similar using TypeScript. When I set the the datasource attribute on the column tag the grid won't show any data and only show a spinner in front of the grid. What can be reason for that?


AG Ajith Govarthan Syncfusion Team February 2, 2021 12:19 PM UTC

Hi Alexander, 
 
Thanks for the update. 
 
Query: I tried to implement something similar using TypeScript. When I set the the datasource attribute on the column tag the grid won't show any data and only show a spinner in front of the grid. What can be reason for that? 
 
Based on your query you are facing grid rendering issue when setting the dataSource property in the column. We have checked our given sample and found everything works fine.  
 
To find the root cause of the issue, please share the below details to provide the prompt solution at the earliest. 
 
1.                   If possible, please try to reproduce the issue in the attached sample. 
 
2.                   Share the complete grid code example. 
 
3.                   Share the screenshot or video demonstration of your requirement. 
 
4.                   Please let us know if you have used remote data or local data in your grid application. 
 
5.                   Share the Syncfusion package version. 
 
 
Regards, 
Ajith G. 



AE Alexander Esser February 2, 2021 01:36 PM UTC

Hi Ajith.
I looked at the JS example you provided and that seems to work. I was referring to the TypeScript example I created a while ago (https://codesandbox.io/s/determined-haibt-rl4iz?file=/src/demoGrid.tsx) and simplified now based on your example. When I remove the comment for the dataSource attribute in line 220:

<ColumnDirective
field="customerId"
headerText="Customer"
width="150"
validationRules={this.validationRules}
foreignKeyValue="customerName"
foreignKeyField="customerId"
//dataSource={CustomerLocations}
edit={this.customerParams}
/>

the grid won't show any data and just a spinner in front of an empty grid. What could be the reason for this? 
There might also be other issues since the customerId is shown and not the name, but that might fall into place when the basics start to work.
Best
Alexander


YK yogita Kashyap February 3, 2021 07:02 AM UTC

I was also facing similar type issues in my code. Anyways glad that i could join your discussion. I was able to find the solution for my problem here itself. Thank You both 


RS Rajapandiyan Settu Syncfusion Team February 3, 2021 11:41 AM UTC

Hi Alexander, 
 
Thanks for your update. 
 
We have validated the provided sample at our end. We found that the foreignKey service is not injected in the Grid.  
 
Grid component features are segregated into individual feature-wise modules. In order to use a particular feature, you need to inject its feature service in the App. Refer to the below documentation for more information. 
 
 
We suggested you to inject the ForeignKey service in the Grid to resolve the reported problem. 
 
[demoGrid.tsx] 
 
        <GridComponent 
          dataSource={GridData} 
          ---- 
        > 
          ----- 
          <Inject services={[Edit,ForeignKey, Toolbar]} /> 
        </GridComponent> 
 
Please get back to us if you need further assistance with this. 
 
Regards, 
Rajapandiyan S 



AE Alexander Esser February 4, 2021 08:30 AM UTC

Hi Rajapandiyan.
That was my bad. I hadn't seen that it had fallen out in the list. 

There were also some naming issues in my example that I fixed now. It starts looking better, but saving changes doesn't seem to work. Instead of the id the respective name in the drop down is used. You can see the update result in the Console window in the bottom right, e.g.:
{"id":"id1","info":"Demo 1","customerId":"Cust Two","customerName":"Cust One","locationId":"Loc Two B","locationName":"Loc Two B"}
What could the reason for this.
Alex


AG Ajith Govarthan Syncfusion Team February 5, 2021 02:04 PM UTC

Hi Alexander,  
  
Thanks for your update. 
 
Query: There were also some naming issues in my example that I fixed now. It starts looking better, but saving changes doesn't seem to work. Instead of the id the respective name in the drop down is used. You can see the update result in the Console window in the bottom right 
 
Based on your query you are facing update issue with dropdown component. So, we have checked your attached sample and found that you have returned the text of the dropdown component instead of value. 
 
So, we suggest you return the value property of the dropdown instead of text in the read method. We have also found that you have not used the dataSource property for the location column. So, please ensure the mentioned changes to avoid the issue.  
 
For your convenience we have attached the sample so please refer the sample for your reference. 
 
Code Example: 
DemoGrid.tsx 
 
import React from "react"; 
import _ from "lodash"; 
import "@syncfusion/ej2-base/styles/material.css"; 
import "@syncfusion/ej2-buttons/styles/material.css"; 
import "@syncfusion/ej2-calendars/styles/material.css"; 
import "@syncfusion/ej2-dropdowns/styles/material.css"; 
import "@syncfusion/ej2-inputs/styles/material.css"; 
import "@syncfusion/ej2-navigations/styles/material.css"; 
import "@syncfusion/ej2-popups/styles/material.css"; 
import "@syncfusion/ej2-splitbuttons/styles/material.css"; 
import "@syncfusion/ej2-react-grids/styles/material.css"; 
import { DropDownList } from "@syncfusion/ej2-dropdowns"; 
import { DataManager, Query } from "@syncfusion/ej2-data"; 
import { 
  GridComponent, 
  ColumnsDirective, 
  ColumnDirective, 
  EditSettingsModel, 
  PageSettingsModel, 
  ActionEventArgs, 
  GroupEventArgs, 
  FilterEventArgs, 
  SearchEventArgs, 
  SortEventArgs, 
  AddEventArgs, 
  SaveEventArgs, 
  EditEventArgs, 
  PageEventArgs, 
  DeleteEventArgs 
} from "@syncfusion/ej2-react-grids"; 
import { 
  Edit, 
  ForeignKey, 
  IEditCell, 
  Inject, 
  Page, 
  Toolbar, 
  ToolbarItems 
} from "@syncfusion/ej2-react-grids"; 
 
import { 
  Customers, 
  CustomerLocations, 
  GridData, 
  ICustomer, 
  IGridData, 
  ICustomerLocation 
} from "./gridData"; 
 
type SyncfusionAction = 
  | PageEventArgs 
  | GroupEventArgs 
  | FilterEventArgs 
  | SearchEventArgs 
  | SortEventArgs 
  | AddEventArgs 
  | SaveEventArgs 
  | EditEventArgs 
  | DeleteEventArgs 
  | ActionEventArgs 
  | undefined; 
 
interface IDemoGridProps {} 
 
interface IDemoGridState { 
  dataSourceGrid: IGridData[] | undefined; 
  loading: boolean; 
} 
 
export default class DemoGrid extends React.Component< 
  IDemoGridProps, 
  IDemoGridState 
> { 
  constructor(props: IDemoGridProps) { 
    super(props); 
    this.state = { 
      dataSourceGrid: undefined, 
      loading: true 
    }; 
    this.gridInstance = React.createRef<GridComponent>(); 
 
    this.customerElem = undefined; 
    this.customerObj = undefined; 
    this.locationElem = undefined; 
    this.locationObj = undefined; 
  } 
 
  private customerElem: HTMLElement | undefined; 
  private customerObj: DropDownList | undefined; 
 
  private locationElem: HTMLElement | undefined; 
  private locationObj: DropDownList | undefined; 
 
  private customersDm = new DataManager([]); 
  private locationsDm = new DataManager([]); 
 
  private gridInstance: React.RefObject<GridComponent>; 
 
  private toolbarOptions: ToolbarItems[] = ["Add", "Edit", "Update", "Cancel"]; 
  private editSettings: EditSettingsModel = { 
    allowEditing: true, 
    allowAdding: true, 
    allowDeleting: true, 
    newRowPosition: "Top", 
    mode: "Normal" 
  }; 
 
  private pageSettings: PageSettingsModel = { pageCount: 5 }; 
  private validationRules = { required: true }; 
 
  public async componentDidMount(): Promise<void> { 
    _.each(Customers, (cust: ICustomer) => this.customersDm.insert(cust)); 
    _.each(CustomerLocations, (cl: ICustomerLocation) => 
      this.locationsDm.insert(cl) 
    ); 
 
    this.setState({ dataSourceGrid: GridData, loading: false }); 
  } 
 
  public customerParams: IEditCell = { 
    create: () => { 
      this.customerElem = document.createElement("input"); 
      return this.customerElem; 
    }, 
    destroy: () => { 
      if (!!this.customerObj) this.customerObj.destroy(); 
    }, 
    read: () => { 
      return !!this.customerObj ? this.customerObj.value : ""; 
    }, 
    write: () => { 
      this.customerObj = new DropDownList({ 
        change: () => { 
          if (!!this.customerObj && !!this.locationObj) { 
            this.locationObj.enabled = true; 
            const tempQuery: Query = new Query().where( 
              "customerId", 
              "equal", 
              this.customerObj.value 
            ); 
            this.locationObj.query = tempQuery; 
            this.locationObj.text = ""; 
            this.locationObj.dataBind(); 
          } 
        }, 
 
        dataSource: this.customersDm, 
 
        fields: { value: "customerId", text: "customerName" }, 
        floatLabelType: "Never", 
        placeholder: "Select a customer" 
      }); 
      this.customerObj.appendTo(this.customerElem); 
    } 
  }; 
  public locationParams: IEditCell = { 
    create: () => { 
      this.locationElem = document.createElement("input"); 
      return this.locationElem; 
    }, 
    destroy: () => { 
      if (!!this.locationObj) this.locationObj.destroy(); 
    }, 
    read: () => { 
      return !!this.locationObj ? this.locationObj.value : ""; 
    }, 
    write: () => { 
      debugger; 
      this.locationObj = new DropDownList({ 
        dataSource: this.locationsDm, 
        enabled: false, 
        fields: { value: "locationId", text: "locationName" }, 
        floatLabelType: "Never", 
        placeholder: "Select a location or leave empty" 
      }); 
      this.locationObj.appendTo(this.locationElem); 
    } 
  }; 
 
  private actionComplete = (args: SyncfusionAction): void => { 
    const captains = console; 
    captains.log(!!args ? args.requestType : "Unknown request type"); 
    const actionEvent = args as ActionEventArgs; 
    const data = actionEvent?.data; 
    captains.log(JSON.stringify(data)); 
  }; 
 
  public render() { 
    return this.state.loading ? ( 
      <div>Loading ...</div> 
    ) : ( 
      <div> 
        <h3>The Grid:</h3> 
        <GridComponent 
          dataSource={GridData} 
          ref={this.gridInstance} 
          toolbar={this.toolbarOptions} 
          allowPaging={true} 
          editSettings={this.editSettings} 
          pageSettings={this.pageSettings} 
          actionComplete={this.actionComplete} 
          title="Grid Test" 
        > 
          <ColumnsDirective> 
            <ColumnDirective 
              field="id" 
              headerText="Id" 
              width="100" 
              isPrimaryKey={true} 
              visible={true} 
            /> 
            <ColumnDirective 
              field="info" 
              headerText="Info" 
              width="250" 
              textAlign="Left" 
              validationRules={this.validationRules} 
            /> 
            <ColumnDirective 
              field="customerId" 
              headerText="Customer" 
              width="150" 
              validationRules={this.validationRules} 
              foreignKeyValue="customerName" 
              foreignKeyField="customerId" 
              dataSource={this.customersDm} 
              edit={this.customerParams} 
            /> 
            <ColumnDirective 
              field="locationId" 
              headerText="Location" 
              width="150" 
              type="string" 
              foreignKeyField="locationId" 
              foreignKeyValue="locationName" 
              dataSource={this.locationsDm} 
              edit={this.locationParams} 
            /> 
          </ColumnsDirective> 
          <Inject services={[Edit, ForeignKey, Page, Toolbar]} /> 
        </GridComponent> 
      </div> 
    ); 
  } 
} 
 
 
Please get back to us if you need further assistance. 
 
Regards, 
Ajith G


AE Alexander Esser February 5, 2021 02:26 PM UTC

Hi Ajith.
That was the missing piece I hadn't noticed. 
Thanks for clarifying 
Alexander


RR Rajapandi Ravi Syncfusion Team February 9, 2021 09:42 AM UTC

Hi Alexander, 

We are happy to hear that your issue has been resolved. 

Please get back to us if you need further assistance. 

Regards, 
Rajapandi R 



Loader.
Up arrow icon