This is a migrated thread and some comments may be shown as answers.

Binding DropDownList Value to complex model

11 Answers 7001 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Joseph
Top achievements
Rank 1
Joseph asked on 25 Mar 2020, 05:13 PM

I'm wondering how I can two-way bind a TelerikDropDown selection to a complex model object rather than a primitive type such as an Id field. I'm trying to add a TelerikDropDownList to a page where the user can select a user-friendly name of an object and have that selection's value bound to the object itself rather than a primitive data type. For example:

<TelerikDropDownList Data="@DropDownItems" TextField="LabelField" ValueField="ValueField" @bind-Value="@SelectedItem"/>
 
@code {
    public List<GenericDropDownModel<Item>> DropDownItems { get; set; }
    public IEnumerable<Item> AllItems { get; set; }
    public Item SelectedItem { get; set; }
     
    protected override Task OnInitializedAsync()
    {
        AllItems = await DataService.LoadItems();
        SelectedItem = AllItems.First();
    }
     
    private void SetDropDownItems()
    {
        List<GenericDropDownModel<Item>> dropDownItems = new List<GenericDropDownModel<Item>>();
        if (AllItems != null)
        {              
            foreach(var item in AllItems)
            {
                GenericDropDownModel<Item> dropDownItem = new GenericDropDownModel<Item>()
                {
                    ValueField = item,
                    LabelField = item.Name
                };
                dropDownItems.Add(dropDownItem);
            }
        }
        DropDownItemsItems = dropDownItems;
    }
 
    public class GenericDropDownModel<T>
    {
        public string LabelField { get; set; }
        public T ValueField { get; set; }      
    }
 
    public class Item
    {
        public string Name { get; set; }
        public IModel Model { get; set; }
        public IEnumerable<IOtherModel> OtherModels { get; set; }      
    }
     
    public class Model
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public string Info { get; set; }

        public IAnotherModel MoreDetails { get; set; }
    }
}

 

The drop-down is not allowing me to bind to non-primitive types nor specify a property of a property, i.e.:

<TelerikDropDownList Data="@AllItems" TextField="Name" ValueField="@Model.Info" @bind-Value="@SelectedInfo"/>


I get the following error with the first code snippet scenario:

System.InvalidOperationException: Telerik.Blazor.Components.TelerikDropDownList`2[GenericDropDownModel`1[Item],Item] does not support the type 'Item'.
   at Telerik.Blazor.Components.Common.TelerikSelectBase`2.TryParseValueFromString(String value, TValue& result, String& validationErrorMessage)
   at Telerik.Blazor.Components.Common.TelerikSelectBase`2.set_CurrentValueAsString(String value)
   at Telerik.Blazor.Components.TelerikDropDownList`2.SelectItem(ListDataItem item)
   at Telerik.Blazor.Components.TelerikDropDownList`2.OnParametersSetAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

11 Answers, 1 is accepted

Sort by
0
Joseph
Top achievements
Rank 1
answered on 25 Mar 2020, 05:15 PM
SetDropDownItems() was also meant to be placed in the setter for AllItems.
-1
Marin Bratanov
Telerik team
answered on 25 Mar 2020, 06:37 PM

Hello Joseph,

The following article explains the situation: https://docs.telerik.com/blazor-ui/knowledge-base/dropdowns-get-model and why only certain types can be bound to the Value parameter.

 

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Kasimier Buchcik
Top achievements
Rank 1
Veteran
answered on 22 Jun 2020, 03:38 PM

Hi Marin,

would adding a bindable "SelectedItem" (plus "OnSelectedItemChange(d)") interfere with the existing "Value" mechanism?
E.g. when using ObjectGraphDataAnnotationsValidator/ValidateComplexType, it would be convenient to bind directly to the complex type property. One cpuld still specify the ValueField to be used by the existing "Value" mechanism. Or would this somehow break something?

<TelerikDropDownList Data="items"
    @bind-SelectedItem="editModel.Item"
    OnSelectedItemChanged="ev => SomeHandler(ev)"
    ValueField="Id"
    TextField="ItemName" />

The edit model type:

public class MyThingy
{
    public Guid Id { get; set; }
 
    [Required]
    public string Name { get; set; }
 
    [Required]
    [ValidateComplexType]
    public MyThingyItem Item { get; set; }
}
 
public class MyThingyItem
{
    public Guid Id { get; set; }
 
    [Required]
    public string ItemName { get; set; }
}

Regards,

Kasimier Buchcik

0
Marin Bratanov
Telerik team
answered on 23 Jun 2020, 06:23 AM

Hi Kasimier,

I will try to cover each point in your question:

would adding a bindable "SelectedItem" (plus "OnSelectedItemChange(d)") interfere with the existing "Value" mechanism? - highly likely, binding two things to a similar field or a related field is likely to cause trouble.

@bind-SelectedItem="editModel.Item" AND   OnSelectedItemChanged="ev => SomeHandler(ev)" - this is not possible in Blazor - the <ParameterName>Changed event that provides two-way binding cannot be used together with two-way binding. This applies to all components, including the standard ones.

using a complex object type - If you use the current Value and point it to an identifier of the item, the OnChange or ValueChanged event we provide let you get the entire item from the data source (as per the article linked above), and so you can set it to the full custom object field in your view-model, which can, in turn, trigger any custom validation you have, or let you invoke any other business logic. At the same time the current value binding mechanism allows extremely flexible validation with various types (GUIDs are, by the way, very popular) and not just with strings, and also filtering of the data.

With all that said, binding to an entire model is actually possible and only requires just a few lines of code in an event handler, while the current mechanism has the benefit of flexible validation and allows filtering. Moreover, if you want to get entire complex models, you can use the grid single row selection feature. You could even put it in a window or other popup (such as an animation container) to show when needed only.

 

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Kasimier Buchcik
Top achievements
Rank 1
Veteran
answered on 23 Jun 2020, 09:44 AM
[quote]

- highly likely, binding two things to a similar field or a related field is likely to cause trouble.

[/quote]
I can imagine that. Although if one needs to bind to a complex object then Telerik's advise it to do exactly that via the OnChange handler. It just moves responsibility over to the component consumer.

 [quote]
@bind-SelectedItem="editModel.Item" AND   OnSelectedItemChanged="ev => SomeHandler(ev)" - this is not possible in Blazor - the <ParameterName>Changed event that provides two-way binding cannot be used together with two-way binding. This applies to all components, including the standard ones.
[/quote]
"SelectedItemChanged" is not equal to "OnSelectedItemChanged". 
Even just an "OnSelectedItemChanged" without a "SelectedItem" parameter would be an improvement because the OnChange/ValueChanged only provide the selected value. By the way: if OnChange would use an event args object holding the selected item and selected value, that would also help a bit.

[quote]
binding to an entire model is actually possible and only requires just a few lines of code in an event handler
[/quote]
That can be said for any missing functionality. Multiply that with every DropDownList folks have to use in the next years.

I wonder where the Blazor/Razor component world is headed to in the future. If the XAML/WPF/WinUI and e.g. the Angular world has a way of binding to complex objects but Blazor not... then something's wrong. Especially PWA's are not only about setting some GUIDs and sending those to the server. Working with object graphs should be common here.

I find it great that Telerik wrote the Blazor components from scratch and does not just wrap JS widgets. But I currently tend to think that Telerik's Blazor components inherited too much philosophy, restrictions and pecularities of its Kendo for jQuery implementation. 
Another thingy I just realized: one has to set TelerikDropDownList.DefaultText=" " (i.e. to at least a space) in order to have a way of clearing the selection. No "clear" button yet. This feels a lot like Kendo for jQuery.
I think such restrictions and peculiarities will become hard to work with because in Blazor one can't add missing functionality like in Kendo for jQuery.
May I ask which team is writing the components? Do Telerik's WPF/WinUI/Angular folks contribute to Blazor components?

My thoughts should be taken with a grain of salt, because I'm really new to Blazor + Telerik's Blazor components (3 weeks), so I may be missing the big picture and sound silly :-) 

Regards
Kasimier Buchcik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Marin Bratanov
Telerik team
answered on 23 Jun 2020, 12:15 PM

Hello Kasimier,

If entire model binding is provided, it will come with the suitable events. I would not speculate on their exact nature until a feature is implemented, as I can go really off the mark. Right now, the component does not carry a selected item reference in itself so it can pass it to a handler, it is up to the view model to fetch such a reference.

On the default text - an item with a default value is what "clears" the value in such a scenario, and DefaultText provides that. The DefaultText simply matches the default value of the Value field - for a string that's null. I am attaching a short video that shows how this works below, and also a project you can use to test this. So, you can think of the DefaultText as the TextField of a model you bind to, where the ValueField is the default value for its type. We hide this behind a simle string property so you don't have to stuff your data with padding.

On a clear button - a dropdown list does not have one by design, but a combo box or an autocomplete do as they can be text inputs. A dropdownlist is a <select> element equivalent, but with better design. So, clearing it is done through the DefaultText feature.

As for how Blazor should work - I would personally rather transmit an ID (number, string, guid, whatever my models and data use) than an entire model if I need a lookup. Of course, this is subject to personal preferences, existing APIs and coding approaches. Also, if you need an async operation, you need an async event anyway, plain MVVM binding can't achieve that (barring some fidgeting with nested components and using the ParametersSet event). So, there is no universally correct answer. The DropDownList is, first and foremost, a form component, and so it provides binding to primitive types and validation. Fetching an entire model from it is not in the immediate plans for out-of-the-box support, mainly because it is extremely easy through the OnChange event. As to whether comparing a web technology with desktop technologies is fair, or comparing to a framework that's a decade old, while blazor has been official for one month - that's also a question that does not have a definitive answer in my view.

Lastly, if entire model selection is so crucial to you that you can't wrap it in a component that steps on the dropdownlist for reuse - I'd suggest going with the grid single row selection.

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Kasimier Buchcik
Top achievements
Rank 1
Veteran
answered on 23 Jun 2020, 03:34 PM

[quote]If entire model binding is provided, it will come with the suitable events. I would not speculate on their exact nature until a feature is implemented, as I can go really off the mark [/quote]
If this will ever be implemented then the "ValueField" would have to be empty, right? If yes then the ValueField's default value (which is "Value") could become a problem because devs would have to explicitely set that to "", right?

I found a comment of Steve Sanderson in an AspNetCore Binding to objects issue.
"This could make sense for “select”, but would not for any other type of form control. We might do it for select at some point, but it will depend on what usage patterns arise and what level of community demand there is."
I find it very irritating that binding to members of complex type is presented as something unheard of. I'm happy that - at least - we had not had such discussions in the WPF community. Sometimes one just needs to bind to such a property; especially in the context of offline/PWA applications where data might not always be intended to be sent to a server immediately - or ever. Sometimes one wants to build an object graph.
Dunno, having worked with other UI technologies, this restriction does not make sense to me. But maybe there's a deeper technological hurdle that I'm not aware of.

[quote]dropdown list does not have one by design[/quote]
I understand. On the other hand e.g. Angular/PrimeNG has a dropdown with a clear button by design. If designs differ that I would go with the design that has more functionality in case I need it.
Wouldn't hurt to add a clear button for folks that need one.
I guess with Kendo UI for jQuery one could simply wrap or derive the drop down and hack together such a button. Would this be possible with Blazor?

[quote] if you need an async operation, you need an async event anyway, plain MVVM binding can't achieve that [/quote]
This is true for any binding. It isn't restricted to binding to properties of complex type.

0
Marin Bratanov
Telerik team
answered on 23 Jun 2020, 04:39 PM

Hello Kasimier,

To each question:

What will happen to Value and ValueField and the component type - That's one of the key problems - the component is generic based on the type of the Value field, so implementing an entire selected item will likely be either a breaking change, or will require specific configuration, or both. I can't answer this question more accurately because doing so would require that the research and implementation of such a feature are done.

The standard Blazor select not supporting entire models as values - we are following the same pattern as Microsoft right now - the standard form type controls bind to simple values. If other requests and usage patterns arise, things will be considered. I suppose that's one of the major differences between the Web and Desktop - with the Web we have standard approaches for forms and their values that date back many years, and those patterns shape things to this day.

Binding to complex objects and async events - my point in saying that is that at the moment, to get the model you need an event. TO fetch data from an endpoint, you need it too, for the majority of cases - so, the code you need to add to get models is not that much.

Designs in other technologies - It is their prerogative to choose to add one, each vendor, framework and style can choose their own design rules and guidelines.

Hacking a clear button in Blazor - your best bet would be using some CSS to position the desired button above the dropdown list. Then, a simple @onclick handler for it can set the value to whatever you want. Maybe you would also like to prevent the click, too, so that the dropdown does not open. At the moment - the Telerik ComboBox component offers a clear button so you may want to consider that instead of hacking a solution on the dropdownlist.

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
0
Kasimier Buchcik
Top achievements
Rank 1
Veteran
answered on 24 Jun 2020, 08:32 AM
[quote] If other requests and usage patterns arise, things will be considered. I suppose that's one of the major differences between the Web and Desktop - with the Web we have standard approaches for forms and their values that date back many years, and those patterns shape things to this day.[/quote]
I guess when people start migrating WinForm/WPF apps to RIA/PWA Blazor apps, then Telerik will have lots of similar disussions. There's no glory in it to find out that one can't simply add a drop-down-list somewhere, give it a collection of complex objects and receive the selected complex object. For me it's not the difference between web and desktop, but the difference between simple classic "form" input and RIA applications.
I'm quite sure that people do realize that, but somehow we are all waiting because someone at MS didn't press the start button.
Thus, I have to wait and jump through the hoops until then :-) 
1
Tom
Top achievements
Rank 1
Iron
answered on 26 Jan 2022, 10:31 PM
Is there a way to vote/request this functionality be added, it seems crazy that nothing has been done on this. It is basic functionality of every business app I've ever worked on and the current solution is a clunky workaround for something that should be trivial.
Marin Bratanov
Telerik team
commented on 30 Jan 2022, 09:36 AM

Hi Tom,

This thread is the feature request for that: https://feedback.telerik.com/blazor/1524004-the-dropdownlist-should-be-bindable-to-complex-types. I would encourage you to first go through it, as it covers much the same information as this one - which I hope will explain why this is impossible as a built-in feature. Said shortly, it will break all forms and validation integration, which will be a much bigger issue. Thus, lookups are to be used. So, you could vote and request it to be reopened there, but I very much doubt that will happen. While we have added a lot of value and functionality in our components, we must still step on the framework and we cannot do what it cannot do. The web is not a desktop app and thus some things may be harder and require a bit more work.

0
Víctor
Top achievements
Rank 1
Iron
Iron
Iron
answered on 22 Aug 2023, 12:00 PM | edited on 23 Aug 2023, 02:36 PM

It's unfortunate you do not provide a way to bind complex models and I have to crete a wrapper around DropdownList becouse you only support Primitive types... makes it hard to use!

 

Georgi
Telerik team
commented on 25 Aug 2023, 09:46 AM

Hello, Victor,

I am sorry for the inconvenience this might be causing you. 

I assume that you have already read this discussion and the linked threads, so you are aware of our rationale. Just in case, I am sharing again this KB article - Get DropDown Model, which provides a possible workaround. 

Tags
General Discussions
Asked by
Joseph
Top achievements
Rank 1
Answers by
Joseph
Top achievements
Rank 1
Marin Bratanov
Telerik team
Kasimier Buchcik
Top achievements
Rank 1
Veteran
Tom
Top achievements
Rank 1
Iron
Víctor
Top achievements
Rank 1
Iron
Iron
Iron
Share this question
or