How can I create cascading dropddownlists and keep everything strongly typed in v30?

I am trying to upgrade from v24.1.47 to 30.1.37, and the code that we had for cascading dropdownlists is no longer working. This is because the type declaration of the value property of the DropDownList class now includes the possibility of it being an object, and Query.where() doesn't allow an object for the value parameter. The tutorial on creating cascading dropdownlists asserts the DropDownList objects to be of type any, which is a complete hack, and is pretty shocking that you are doing that in your official documentation. The video on that page doesn't include this hack, but the code shown in that video also doesn't compile when using a dropdownlist from Syncfusion v25+.

Here is the code that we have, that no longer compiles:

                        this.stateObj = new DropDownList({
                            dataSource: new DataManager(this.states),
                            fields: { value: 'stateCD', text: 'stateCD' },
                            change: () => {
                                const tempQuery: Query = new Query().where('stateCD', 'equal', this.stateObj.value);
                                this.countyObj.query = tempQuery;
                                this.countyObj.text = null;
                                this.countyObj.dataBind();
                            }
                        });


So how can I get this to keep working, without losing my typings?


7 Replies

PK Priyanka Karthikeyan Syncfusion Team July 4, 2025 02:03 PM UTC

Hi Jesse Cates,


Thank you for contacting us and for sharing the details of your query. To assist you further, we have developed a simple sample for a cascading dropdown list, which we’ve tested and confirmed is functioning as expected. However, we did encounter a type error during our testing, and we’ve included the sample below for your reference.


Sample: https://stackblitz.com/edit/9wxdylrl-pempmfxz?

Could you kindly confirm if you are experiencing the same type error on your end? Your feedback would be invaluable in helping us better understand the issue and provide the most effective solution. If you could share any additional details, such as the specific error message or context in which it occurs, it would greatly assist us in addressing your concern promptly.


Regards,

Priyanka K



JC Jesse Cates July 7, 2025 12:40 PM UTC

Sorry for not including the error message. Yes, I am getting the same type error as what you see in your sample:

"Argument of type 'string | number | boolean | object' is not assignable to parameter of type 'string | number | boolean | Date'.

  Type 'object' is not assignable to type 'string | number | boolean | Date'.ts(2345)"


Also, I want to point out that I'm using an Angular app. I don't think it matters as long as TypeScript is being used, but since your sample wasn't Angular, I wanted to make sure that was clear. Also, your sample seems to be working even though it is getting the type error. I'm guessing this is because the TS config for the sample is set to ignore type errors on build, but we're unable to do that in our application. So we're unable to build our app with this type error, unless we use an explicit type assertion to get around it.



PK Priyanka Karthikeyan Syncfusion Team July 10, 2025 01:16 PM UTC

Hi Jesse Cates,


Thank you for your confirmation.

To resolve the error you encountered, please ensure to pass args.value  in the where clause of the query. 

Please find the code snippet below for your reference:

 

​let stateObj: DropDownList = new DropDownList({
   dataSource: stateData,
   fields: { value: 'StateId', text: 'StateName' },
   // set disable state by default to prevent user interact.
   enabled: false,
   change: (args) => {
       // Query the data source based on state DropDownList selected value
       cityObj.query = new Query().where('StateId', 'equal', args.value);
       // enable the city DropDownList
       cityObj.enabled = true;
       //clear the existing selection
       cityObj.text = null;
       // bind the property change to city DropDownList
       cityObj.dataBind();
   },
   placeholder: 'Select a state',
});
 

If you need further assistance, feel free to let us know. We’re happy to help!


Regards,

Priyanka K



JC Jesse Cates July 10, 2025 02:47 PM UTC

This only works because args is typed as any in that case. It looks like your type definition for the change event is wrong, so its arguments are incorrectly typed as any. That seems like a separate bug where we lose the type-safety that is expected with TypeScript. And if I declare the arguments as being the correct ChangeEventArgs type, then I get the same "not assignable" error:


                        this.stateObj = new DropDownList({
                            dataSource: new DataManager(this.states),
                            fields: { value: 'stateCD', text: 'stateCD' },
                            change: (args: ChangeEventArgs) => {
                                const tempQuery: Query = new Query().where('stateCD', 'equal', args.value);
                                this.countyObj.query = tempQuery;
                                this.countyObj.text = null;
                                this.countyObj.dataBind();
                            }
                        });
                        this.stateObj.appendTo(this.stateElem);


PK Priyanka Karthikeyan Syncfusion Team July 11, 2025 01:19 PM UTC

Hi Jesse Cates,

 

Thank you for the update. We are pleased to inform you that the allowObjectBinding feature has been implemented in version 25.1.35. For further details, please refer to the release notes available at:

https://ej2.syncfusion.com/angular/documentation/release-notes/25.1.35?type=all#dropdownlist


This feature introduction is the cause of the type error observed in the previously documented sample.


To resolve this error, we recommend using a ternary operator to check if the value is an object type and handle it accordingly. Below is the corrected code:


// For countryObj.value in the state change event
stateObj.query = new Query().where('CountryId', 'equal',
  typeof countryObj.value === 'object' ? (countryObj.value as any).CountryId : countryObj.value);

// For stateObj.value in the city change event
cityObj.query = new Query().where('StateId', 'equal',
  typeof stateObj.value === 'object' ? (stateObj.value as any).StateId : stateObj.value);

This code checks if the value is an object and, if so, extracts the appropriate property (CountryId or StateId). If the value is not an object, it uses the value directly.


We will update the documentation in anyone of the upcoming release. Thank you for your understanding, and please feel free to reach out if you have any further questions.



Regards,

Priyanka K



JC Jesse Cates July 11, 2025 04:44 PM UTC

OK, I guess that makes sense, and if it's documented, then I think everything is fine. Thank you.



PK Priyanka Karthikeyan Syncfusion Team July 14, 2025 01:26 PM UTC

Hi Jesse Cates,


Thank you for your understanding! We're glad everything is clear—please don't hesitate to reach out if you need anything further.


Regards,

Priyanka K


Loader.
Up arrow icon