Cascading dropdown on foreign key field

Hi,

I have two columns on my grid: Surname and Category. They are foreign key fields and when adding a new row to the grid, I'd like the Category dropdown field to be updated/filtered based on the Surname selected. I'm getting an "Uncaught TypeError: Cannot set property 'query' of undefined" when changing the surname option. How do I accomplish that?


Attachment: SPS_8ff2fe3f.zip

9 Replies 1 reply marked as answer

BS Balaji Sekar Syncfusion Team November 17, 2020 01:03 PM UTC

Hi Christian, 

Greetings from the Synfusion support. 

Based on your query we suspect that you have bound cascading dropdown editing in the ForeignKey columns using edit.params feature.  We are able to reproduce the reported problem while select a dropdown item of “Surname” column. 

In your attachment we found that dropdownlist instance store variables(surnameObj, categoryObj) is not initialized with DropdownList model which is cause of the problem. 

We suggest you to define the imported Dropdownlist module to that instance store variable and it will assign the Dropdownlist component required properties to overcome that reported problem use this solution. 

Please refer the below code example and sample for more information. 

[App.Vue] 
let surnameElem; 
let surnameObj= new DropDownList() 
let categoryElem 
let categoryObj = new DropDownList(); 

surnamesParams: { 
        create: function () { 
          surnameElem = document.createElement('input') 
          return surnameElem 
        }, 
        read: function () { 
          return surnameObj.value 
        }, 
        destroy: function () { 
          surnameObj.destroy() 
        }, 
        write: function () { 
          debugger; 
          surnameObj = new DropDownList({ 
            dataSource: surnames, 
            fields: { value: 'id', text: 'name' }, 
            change: function () {               
              const tempQuery = new Query().where('id', 'equal', surnameObj.value) 
              categoryObj.query = tempQuery 
              categoryObj.value = null 
              categoryObj.dataBind() 
            }, 
            placeholder: 'Select a Surname', 
            floatLabelType: 'Never' 
          }) 
          surnameObj.appendTo(surnameElem) 
        } 
      }, 
 
      categoriesParams: { 
        create: function () { 
          categoryElem = document.createElement('input') 
          return categoryElem 
        }, 
        read: function () { 
          return categoryObj.value 
        }, 
        destroy: function () { 
          categoryObj.destroy() 
        }, 
        write: function () { 
          debugger; 
          categoryObj = new DropDownList({ 
            dataSource: categories, 
              
            fields: { value: 'id', text: 'name' }, 
            placeholder: 'Select a Category', 
            floatLabelType: 'Never' 
          }) 
          categoryObj.appendTo(categoryElem) 
        } 
      }, 
        
    }; 



Please get back to us, if you need further assistance. 

Regards, 
Balaji Sekar 



CD Christian DAquino November 17, 2020 01:32 PM UTC

Hi,

Using your sample below I don't get the error anymore but the query doesn't get applied to the categoryObj either?


BS Balaji Sekar Syncfusion Team November 18, 2020 02:51 PM UTC

Hi Christian, 
 
Based on your query we suspect that second dropdown of cascading dropdown is not properly bind the generated query(categoryObj.query).so you can see the whole data in the Category column edit mode.  
 
We have store the generate query to local variable(query) in the read function from the Category column’s edit.params and it is assign to categoryObj after set the dropdownlist instance. 
 
Now we can perform the cascading functionality using the following solution and sample for more information. 
 
[App.Vue] 
surnamesParams: { 
        create: function () { 
          surnameElem = document.createElement("input"); 
          return surnameElem; 
        }, 
        read: function () { 
          return surnameObj.value; 
        }, 
        destroy: function () { 
          surnameObj.destroy(); 
        }, 
        write: function (args) { 
          debugger; 
          surnameObj = new DropDownList({ 
            dataSource: surnames, 
            fields: { value: "id", text: "name" }, 
            change: function () { 
              const tempQuery = new Query().where( 
                "id", 
                "equal", 
                surnameObj.value 
              ); 
              categoryObj.query = tempQuery; 
              categoryObj.value = null; 
              categoryObj.dataBind(); 
            }, 
 
            floatLabelType: "Never", 
          }); 
          surnameObj.value = args.rowData.surnameID; 
          surnameObj.appendTo(surnameElem); 
        }, 
      }, 
 
  
 
 categoriesParams: { 
        create: function () { 
          categoryElem = document.createElement("input"); 
          return categoryElem; 
        }, 
        read: function () { 
          return categoryObj.value; 
        }, 
        destroy: function () { 
          categoryObj.destroy(); 
        }, 
        write: function () { 
          var query = categoryObj.query; 
          categoryObj = new DropDownList({ 
            dataSource: categories, 
            fields: { value: "id", text: "name" }, 
            placeholder: "Select a Category", 
            floatLabelType: "Never", 
          }); 
          if (query) { 
            categoryObj.query = query; 
          } 
          categoryObj.appendTo(categoryElem); 
        }, 
      }, 
 
 
Please get back to us, if you need further assistance. 
 
Regards, 
Balaji Sekar 



CD Christian DAquino November 19, 2020 12:24 AM UTC

Hi,

Why isn't the category field being refreshed after the change on the surnameObj ? I was expecting that after modifying the surnameObj the categoryObj would be refreshed to null.

change: function () { 
              const tempQuery = new Query().where( 
                "id", 
                "equal", 
                surnameObj.value 
              ); 
              categoryObj.query = tempQuery; 
              categoryObj.value = null; 
              categoryObj.dataBind(); 
            },

I'm trying to replicate this example: https://ej2.syncfusion.com/vue/documentation/grid/how-to/cascading-drop-down-list-with-grid-editing/. But that doesn't work even if I remove the foreign key binding.


BS Balaji Sekar Syncfusion Team November 20, 2020 10:08 AM UTC

Hi Christian, 
 
Before proceeding your requirement, we need to confirm that you want to show the Category column value is “Null” while edited the first cascading dropdownlist(Surname column) or if we misunderstood your requirement, please share the exact requirement to us that will help to validate further. 
 
Regards, 
Balaji Sekar 



CD Christian DAquino November 21, 2020 11:53 PM UTC

Yes, you are correct. I want to "want to show the Category column value is “Null” while edited the first cascading dropdownlist(Surname column)"


BS Balaji Sekar Syncfusion Team November 24, 2020 03:53 AM UTC

Hi Christian, 
 
Thanks for your update. 
 
Based on your query we have updated  “Null” value to the category column value when we edited the surnameID column and also we prevent the edit action in the catergory column value using cellEdit event. It will allow the edit action for category column’s cell after edited the corresponding row of surnameID’s cell. 
 
Please refer the below code example and sample for more information. 
 
[App.Vue] 
<ejs-grid 
      id="Grid" 
      ref="grid" 
      height="400" 
      :dataSource="data" 
      :editSettings="editSettings" 
      :toolbar="toolbar" 
      :cellEdit="cellEdit" 
    > 
      <e-columns> 
        .      .      .     . 
      </e-columns> 
    </ejs-grid> 
 
surnamesParams: { 
        create: function () { 
          surnameElem = document.createElement("input"); 
          return surnameElem; 
        }, 
        read: function () { 
          return surnameObj.value; 
        }, 
        destroy: function () { 
          surnameObj.destroy(); 
        }, 
        write: function (args) {           
          surnameObj = new DropDownList({ 
            dataSource: surnames, 
            fields: { value: "id", text: "name" }, 
            change: function (e) { 
              const tempQuery = new Query().where( 
                "id", 
                "equal", 
                surnameObj.value 
              ); 
              this.parent.updateCell( 
                this.parent.getRowInfo(e.element).rowIndex, 
                "category", 
                null 
              );  // Update the null value to category cell  
              categoryObj.query = tempQuery; 
              categoryObj.value = null; 
              categoryObj.dataBind(); 
            }.bind(this), 
 
            floatLabelType: "Never", 
          }); 
          surnameObj.value = args.rowData.surnameID; 
          surnameObj.appendTo(surnameElem); 
        }, 
      }, 
.    .    .    . 
methods: { 
    cellEdit: function (e) {       
      if (e.columnName === "category" &&!e.cell.previousElementSibling.classList.contains("e-updatedtd")) { 
        e.cancel = true; // Prevent the edit action in category column 
      } 
    }, 
  }, 
 
 
 
Please get back to us, if you need further assistance. 
 
Regards, 
Balaji Sekar 



SH Shivani March 26, 2021 04:19 AM UTC

Hello, I am following this example for dropdown selection.
Here, I want to select country, based on country show district and based on district show area dropdown lists.
But I am getting error - 'Cannot read property 'updateCell' of undefined'
IF possible please send me an example. whatever examples you shared in this post, I can not see any of them.
Here is my code,

countryParams: {
        create: () => {
          countryElem = document.createElement("input");
          return countryElem;
        },
        read: () => {
          if (countryObj != null || countryObj != undefined) {
            return countryObj.value;
          }
        },
        destroy: () => {
          if (countryObj != null || countryObj != undefined) {
            countryObj.destroy();
          }
        },
        write: (args=> {
          countryObj = new DropDownList({
            dataSource: this.countriesList,
            fields: {
              value: "CountryCode",
              text: "CountryName"
            },
            change: function (e) {
              debugger;
              districtObj.enabled = true;
              const tempQuery = new Query().where('CountryCode''equal'countryObj.value);
              this.parent.updateCell(this.parent.getRowInfo(e.element).rowIndex,"country"null); 
              districtObj.query = tempQuery 
              districtObj.value = null
              districtObj.dataBind();
            }.bind(this),
            //value: args.rowData[args.column.field], // need to set value peroperty to show the row data in the dropdown
            placeholder: "Select a Country"
          });
          countryObj.value = args.rowData[args.column.field]; 
          countryObj.appendTo(countryElem);
        }
      },
      districtParams: {
        create: () => {
          districtElem = document.createElement("input");
          return districtElem;
        },
        read: () => {
          if (districtObj != null || districtObj != undefined) {
            return districtObj.value;
          }
        },
        destroy: () => {
          if (districtObj != null || districtObj != undefined) {
            districtObj.destroy();
          }
        },
        write: () => {
          debugger;
          var query = districtObj.query;
          districtObj = new DropDownList({
            dataSource: this.districtList,
            fields: {
              value: "DistrictCode",
              text: "DistrictCode"
            },
            enabled: false,
            //value: args.rowData[args.column.field], // need to set value peroperty to show the row data in the dropdown
            placeholder: "Select a District"
          });
          if (query) { 
             districtObj.query = query
          } 
          districtObj.appendTo(districtElem);
        }
      },






BS Balaji Sekar Syncfusion Team March 29, 2021 01:16 PM UTC

Hi Christian, 
 
Greetings from the Syncfusion support. 
 
Based on your query we suspect that you want update District column value based on Country column value changes and you have tried to update District column value using updateCell method in change event of Country column’s editing(Dropdownlist editing).but in your code snippet, you have used the inline editing it is cause of the problem. We can overcome the mentioned problem using Batch editing with updateCell method. 
 
Please refer the below code example and sample for more information for more information. 
[App.Vue] 
<ejs-grid 
      id="Grid" 
      ref="grid" 
      height="400" 
      :dataSource="data" 
      :editSettings="editSettings" 
      :toolbar="toolbar" 
      :cellEdit="cellEdit" 
    > 
      <e-columns> 
        <e-column field="id" headerText="ID" isPrimaryKey="true"></e-column> 
        <e-column 
          field="surnameID" 
          headerText="Surname" 
          type="string" 
          foreignKeyValue="name" 
          foreignKeyField="id" 
          :dataSource="surnames" 
          editType="dropdownedit" 
          :edit="surnamesParams" 
        ></e-column> 
        <e-column 
          field="category" 
          headerText="Category" 
          type="string" 
          foreignKeyValue="name" 
          foreignKeyField="id" 
          :dataSource="categories" 
          editType="dropdownedit" 
          :edit="categoriesParams" 
        ></e-column> 
      </e-columns> 
    </ejs-grid> 
 
editSettings: { 
        allowEditing: true, 
        showConfirmDialog: false, 
        allowAdding: true, 
        allowDeleting: false, 
        mode: "Batch", 
      }, 
surnamesParams: { 
        create: function () { 
          surnameElem = document.createElement("input"); 
          return surnameElem; 
        }, 
        read: function () { 
          return surnameObj.value; 
        }, 
        destroy: function () { 
          surnameObj.destroy(); 
        }, 
        write: function (args) { 
          surnameObj = new DropDownList({ 
            dataSource: surnames, 
            fields: { value: "id", text: "name" }, 
            change: function (e) { 
              const tempQuery = new Query().where( 
                "id", 
                "equal", 
                surnameObj.value 
              ); 
              this.parent.updateCell( 
                this.parent.getRowInfo(e.element).rowIndex, 
                "category", 
                null 
              ); 
              categoryObj.query = tempQuery; 
              categoryObj.value = null; 
              categoryObj.dataBind(); 
            }.bind(this), 
 
            floatLabelType: "Never", 
          }); 
          surnameObj.value = args.rowData.surnameID; 
          surnameObj.appendTo(surnameElem); 
        }, 
      }, 
 
 
Please get back to us, if you need further assistance.  
 
Regards, 
Balaji Sekar 


Marked as answer
Loader.
Up arrow icon