Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor form component InputSelect should support binding of type Guid #9939

Closed
mansabbloch opened this issue May 3, 2019 · 13 comments
Closed
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one

Comments

@mansabbloch
Copy link

Is your feature request related to a problem? Yes.

Following code does not work if binding Type is Guid. The runtime error in browser console is `InputSelect does not support the type Guid"

// ItemCreate.razor
...
<InputSelect bind-Value="Item.CategoryId">
  @foreach(var cat in Categories) {
    <option value="cat.Id">@cat.Name</option>
  }
</InputSelect>
...
// Entities.cs
...
public class Item
{
  public Guid Id { get; set; }
  public string Name { get; set; }
  public virtual Category Category { get; set; }
  [ForeignKey("Category")]
  public Guid? CategoryId { get; set; }
}

public class Category
{
  public Guid Id { get; set; }
  public string Name { get; set; }
}
...

Describe the solution you'd like

InputSelect should support binding for type Guid.

Describe alternatives you've considered

I have to create custom MyInputSelect on top of InputSelect which supports Guid.

Additional context

Asp.Net Core 3 Preview 4
Browser: Chrome @version:73

@Eilon Eilon added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label May 3, 2019
@danroth27 danroth27 added the area-blazor Includes: Blazor, Razor Components label May 3, 2019
@danroth27 danroth27 added this to the 3.0.0-preview7 milestone May 3, 2019
@danroth27 danroth27 added the enhancement This issue represents an ask for new feature or an enhancement to an existing one label May 3, 2019
@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@mkArtakMSFT mkArtakMSFT modified the milestones: 3.0.0-preview7, 3.1.0 May 23, 2019
@dsychin
Copy link

dsychin commented May 29, 2019

I have a similar problem using Blazor server-side. I am using integers ID and binding InputSelect to that.
Loading the component works fine, but changing the value in InputSelect causes an exception.

[2019-05-29T02:10:46.461Z] Error: System.InvalidOperationException: Microsoft.AspNetCore.Components.Forms.InputSelect`1[System.Int32] does not support the type 'System.Int32'.
   at Microsoft.AspNetCore.Components.Forms.InputSelect`1.TryParseValueFromString(String value, T& result, String& validationErrorMessage)
   at Microsoft.AspNetCore.Components.Forms.InputBase`1.set_CurrentValueAsString(String value)
   at Microsoft.AspNetCore.Components.BindMethods.<>c__DisplayClass9_0.<SetValueHandler>b__0(UIEventArgs eventArgs)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Components.Rendering.Renderer.GetErrorHandledTask(Task taskToHandle)

@danroth27
Copy link
Member

@rynowak was this one of the issues your TypeConverter work fixed?

@rynowak
Copy link
Member

rynowak commented Jun 25, 2019

@mkArtakMSFT mkArtakMSFT modified the milestones: 3.1.0, Backlog Aug 12, 2019
@cmoncure
Copy link

cmoncure commented Nov 7, 2019

Guid (or UUID) is used by every modern web app on the face of the planet. It should have first class support everywhere it's possible to use it.

Currently this has to be worked around by adding redundant properties to your model and explicitly invoking Convert on the getter and setter every time you want to use InputSelect based on an object's Guid.

`

class Model : MyObject 
{
    public string MyUidAsString { get; set; }

    override public Guid MyUid
    {
        get { return Guid.TryParse(MyUidAsString, out Guid g) ? g : default; }
        set { MyUidAsString = Convert.ToString(value); }
    }
}

`

This is frustrating and tedious. Not Blazing!

@marinasundstrom
Copy link

It is a shame that the fix (#17126) was not finished.

@Eirenarch
Copy link

I am really curious about the thought process behind only supporting string and enum. It is obvious to me that the integer types, guid and their nullable versions should also be supported

@douglassimaodev
Copy link

any update on this?

@ryanelian
Copy link

Our company managed to solve this by remaking the entire form system. (Just like those folks over at Syncfu**** / Teler** / DevExp**** with their closed source and proprietary custom components)

I'll just drop this source code, hopefully can be an inspiration for whoever tackling this issue.

using System;
using System.Collections.Generic;
using System.Text;

namespace Accelist.BlazorRAD
{
    /// <summary>
    /// Contains methods to convert string to most CLR basic types.
    /// </summary>
    public static class PowerConvert
    {
        /// <summary>
        /// Converts a string into an typed object.
        /// </summary>
        /// <param name="t"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object FromString(Type t, string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                if (t.IsValueType)
                {
                    return Activator.CreateInstance(t);
                }
                else
                {
                    return null;
                }
            }

            if (t == typeof(string))
            {
                return value;
            }

            var t2 = Nullable.GetUnderlyingType(t);
            if (t2 != null)
            {
                t = t2;
            }

            if (t == typeof(Guid))
            {
                return Guid.Parse(value);
            }
            
            // DateTime is IConvertible so no manual conversion is required

            if (t == typeof(DateTimeOffset))
            {
                return DateTimeOffset.Parse(value);
            }

            if (t == typeof(TimeSpan))
            {
                // DateTimeOffset can parse HH:MM:SS but TimeSpan cannot parse ISO 8601!
                var dt = DateTimeOffset.Parse(value);
                return new TimeSpan(dt.Hour, dt.Minute, dt.Second);
            }

            // https://docs.microsoft.com/en-us/dotnet/api/system.iconvertible?view=netcore-3.1
            // https://docs.microsoft.com/en-us/dotnet/api/system.convert.changetype?view=netcore-3.1
            return Convert.ChangeType(value, t);
        }

        /// <summary>
        /// Converts a string into an typed object.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T FromString<T>(string value)
        {
            return (T)FromString(typeof(T), value);
        }
    }
}
/// <summary>
        /// Converts the property value to string.
        /// If the property type is <see cref="DateTime"/> or <see cref="DateTimeOffset"/>, convert it into ISO 8601 format.
        /// If the property type is <see cref="DateTime"/> with unknown time zone, treat it as UTC Time Zone.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public string GetValueAsString(object model)
        {
            var value = Property.GetValue(model);
            if (value is DateTime dt)
            {
                if (dt.Kind == DateTimeKind.Unspecified)
                {
                    dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
                }
                return dt.ToString("o");
            }
            if (value is DateTimeOffset dto)
            {
                return dto.ToString("o");
            }
            return value?.ToString();
        }

Basically what happens is that because most basic HTML form inputs for Blazor works just fine when used with string instead of other data types, the implementer should perform a chained bind like this:

Native HTML input <----> C# string <----> Developer Data Type

That way, whenever the input is mutated from the HTML, it can be converted into the desired data type via string conversion first.

On the other way, the value of the actual data type chosen by the developer (For example: GUID, integer, etc.) should first be converted into string before being bound to the native HTML input.

This way, Blazor input controls can be used with any basic data types.

@boukenka
Copy link

Is there any update on this?

@valuator18
Copy link

Ran into this today when starting (and subsequently abandoning) our plan to replace our MVC forms with Blazor Components.

It seems someone lied to us and said that Blazor was production-ready.

@tomRedox
Copy link

Ran into this today when starting (and subsequently abandoning) our plan to replace our MVC forms with Blazor Components.

It seems someone lied to us and said that Blazor was production-ready.

@valuator18, for info Blazor is definitely production ready, we've have a large server-side Blazor app running in production for a few months now.

There are several ways around this particular issue (some discussed above) and third party controls that have this functionality. Alternatively you can just declare a derived property that converts your Guid property to a string and bind to that instead.

@zimcoder
Copy link

@danroth27 It seems that Guids and integers should have been supported from the onset. Now I have to tell anyone I recommend Blazor to about this issue which should have been baked in from the start. I feel like Blazor is not production-ready with such issues.

@boukenka
Copy link

@ryanelian I also had to implement a workaround to make it work with GUID. I would really appreciate it being possible to link Guid-type data. I hope a solution will be part of 5.0

@MackinnonBuck MackinnonBuck added Done This issue has been fixed and removed Working labels Jul 2, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Aug 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one
Projects
None yet
Development

No branches or pull requests