question

OscarLauroba-5245 avatar image
0 Votes"
OscarLauroba-5245 asked OscarLauroba-5245 commented

Blazor hybrid binding to expando objects

I'm taking my first steps in Blazor hybrid apps and it seems it's not possible binding html inputs to expando object's properties. Expando objects are .Net. I'm also interesting in creating forms at runtime because my app does not know the data at development time but at runtime with dynamic objects like expandoObjects. Is there a way to accomplish this. If not, is there any preview in the future, .Net 7 maybe? Thank you very much.

dotnet-aspnet-core-blazor
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered

Expando objects are part of the dynamic runtime added for the IronPython and IronRuby projects. originally asp.net MVC was designed for IronPython. when it switched to C#, binding changed from expando objects to using reflection, attributes and expression trees (for intellisense support).

you can bind to Dictionary<string,string> which will allows dynamic forms. You will need additional datatype meta data, and will need to create you own validation, but you probably wanted this anyway for the dynamic forms.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

ZhiLv-MSFT avatar image
0 Votes"
ZhiLv-MSFT answered

Hi @OscarLauroba-5245,

in Blazor hybrid apps and it seems it's not possible binding html inputs to expando object's properties.

This is a known issue, and it is not a feature that asp.net Blazor currently support. The Blazor form elements require a statically typed model to work. So we can't directly bind the ExpandoObject. You can submit this feedback about this issue on the Github.

As a workaround, you can use a Dictionary to store the relates value and assign to the ExpandoObject, then in the form, convert the ExpandoObject to the IDictionary and loop the items to display the value. Refer to the following sample (view the source code):

242690-image.png

The result as below(this is a Blazor MAUI application):

242753-1.gif


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Best regards,
Dillion


sourcecode.txt (1011 B)
image.png (146.0 KiB)
1.gif (524.7 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

OscarLauroba-5245 avatar image
0 Votes"
OscarLauroba-5245 answered OscarLauroba-5245 commented

Hi Dillion, thank you very much.
Currently it seems it's the way to go, but I can't achieve data binding a property that's not a string, for example DateTime.243409-sourcecode-2022-09-21.txt
Please, see the atached file.

 @page "/counter"
     
 @using System.Dynamic
    
 <h1>Counter</h1> 
 <button class="btn btn-primary" @onclick="CheckValue">Check ExpandoObject Value</button>
    
 <div class="mb-3">
    <label class="form-label">Date</label>
    <input type="date" class="form-control" value=@(product["date"]) />
    <input type="text" class="form-control" value=@(product["date"]) />
 </div>
    
 @foreach (var option in (IDictionary<string, object>)selectedProduct.Properties)
 {
     <div class="col-sm">
         <input type="text" placeholder="@option.Key" value="@option.Value"
         @onchange="@((ChangeEventArgs __e) => ((IDictionary<string, object>)selectedProduct.Properties)[option.Key] = (object)__e.Value.ToString())"/>
     </div>
 }
    
 @code { 
    
     private dynamic selectedProduct = new ExpandoObject();
        
     private IDictionary<string, object> product;
     private dynamic expnProduct = new ExpandoObject();
        
     protected override async Task OnInitializedAsync()
     {
         Dictionary<string, object> properties = new Dictionary<string, object>();
         properties.Add("color", "red");
         properties.Add("size", "100*100");
         properties.Add("weight", "10kg");
    
         selectedProduct.Properties = properties; 
    
         product = (IDictionary <String, Object>) expnProduct;
         product["color"] = "red";
         product["size"] = 100;
         product["weight"] = 10.50D;
         expnProduct.name = "Product One"; // product["name"] = "Product one"
         expnProduct.date = DateTime.Today;
     }
    
     private void CheckValue()
     {
         var data = selectedProduct;
     } 
 }


[2]: /answers/storage/attachments/243300-image.png




image.png (45.2 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @OscarLauroba-5245,

but I can't achieve data binding a property that's not a string,

Do you mean the date type input element not render the date correct? I checked your code, the date type input element just display the data format ("mm/dd/yyyy").

For this issue, as a workaround, you could use the string type to store the date and use the text type input element display the value, if you want to select the date, you can use some JS date time picker plugin.

Best regards,
Dillion

0 Votes 0 ·

When the input type is date, it does not show any value. I don't know why but this works:

 <input type="date" class="form-control" value=@(((DateTime) product["date"]).ToString("yyyy-MM-dd")) />
0 Votes 0 ·