Can you dynamically assign a bind-Value to an input component such as SfTextBox?

I have an "interesting" project where the List that backs my DataGrid contains data "normalized" from multiple record types.  There are some columns that are in common across record types.  Other columns are unique per record type.  I use the Dialog Edit Mode to edit a given record/row.  I use reflection to analyze the contents of the row.  By design, a column value will be null if it doesn't apply to the record type.  There are a couple dozen columns overall, but usually less than 10 will be non-null.  I want to render non-null column values in the edit dialog.

Below is my razor file content for the <GridEditSettings> section, including my dialog <Template>.  I'm trying to figure out how to avoid using an if/else logic block for every potential fieldName in my possible set of fields.  The key to this working is to be able to effectively specify a bind-Value that will be appropriate for downstream events, such as a Save.  The first few if/else blocks work great for the Save -- because I bind to properties of the Trans object, which is associated to the context variable..  The lower if/else blocks (ifs by data type) don't work because I'm binding to sort of senseless variables.

In theory, I'd kind of like to bind to a variable variable name -- like bind to @(Trans. + fieldName) -- or something equivalent to this.  Does anybody have any ideas on how to do anything like this?  Thanks in advance.


<GridEditSettings AllowEditing="true" Mode="@EditMode.Dialog">
    <Template>
        @{
            FailedTransaction Trans = (FailedTransaction) context;
            FieldInfo[] TransFieldInfo = Trans.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            templateFieldsDictionary = new Dictionary<string, object>();

            <div class="nmc-dialog-template">

                @foreach (FieldInfo fieldInfo in TransFieldInfo)
                {
                    string fieldName = StringUtils.GetStringBetweenTwoMarkers(fieldInfo.Name, "<", ">");
                    object fieldValue = fieldInfo.GetValue(Trans);
                    string fieldElemId = "nmc-" + fieldName;

                        <div class="form-row nmc-dialog-row">
                            <div class="col-2">
                                <label for="@fieldElemId">@fieldName:</label>
                            </div>
                            <div class="col-10">
                                <span class="force-inline-block">
                                    @if (fieldName.Equals("ErrorMsg"))
                                    {
                                        <SfTextBox ID="@fieldElemId" @bind-Value="@(Trans.ErrorMsg)" size="120" ></SfTextBox>
                                    }
                                    else if (fieldName.Equals("Checksum"))
                                    {
                                        <SfTextBox ID="@fieldElemId" @bind-Value="@(Trans.Checksum)" size="40" ></SfTextBox>
                                    }
                                    else if (fieldName.Equals("LoadedFromXMLFileName"))
                                    {
                                        <SfTextBox ID="@fieldElemId" @bind-Value="@(Trans.Checksum)" size="64" ></SfTextBox>
                                    }
                                    else if (fieldValue.GetType() == typeof(DateTime))
                                    {
                                        DateTime DatePickerValue = (DateTime) fieldValue;
                                        templateFieldsDictionary[fieldName] = DatePickerValue;
                                        <SfDatePicker ID="@fieldElemId" @bind-Value="@DatePickerValue" Format="MM/dd/yy HH:mm:ss"></SfDatePicker>
                                    }
                                    else if (fieldValue.GetType() == typeof(string))
                                    {
                                        string TextBoxValue = (string) fieldValue;
                                        templateFieldsDictionary[fieldName] = TextBoxValue;
                                        <SfTextBox ID="@fieldElemId" @bind-Value="@TextBoxValue" ></SfTextBox>
                                    }
                                    else
                                    {
                                        <span id="@fieldElemId">@fieldName not mapped (to do)</span>
                                    }
                                </span>
                            </div>
                        </div>
                }

            </div>
        }
    </Template>
</GridEditSettings>


4 Replies

VS Vignesh Srinivasan Syncfusion Team December 8, 2020 10:37 AM UTC

Hi Steve Swett, 
 
Greetings from Syncfusion support. 
 
Yes, we can dynamically assign the bind – Value in Textbox component using the type Dictionary. By using the change event in the textbox, changing value get update to the bind value property. Please fine the code sample below. 
 
code  snippet:  
  
 
@foreach (var value in myComponents) 
{ 
    var textValue = value.Value; 
<SfTextBox @bind-Value="@textValue" Placeholder="Enter Name" ValueChange="((ChangedEventArgs args)=> TextBoxChangeEvent( args, value.Key))" /> 
 <span> 
      <p> the value is @value.Value</p> 
 </span>} 
@code {  
private Dictionary<string, string> myComponents = new Dictionary<string, string>(){ 
    {"TextboxObj1","value first"}, 
    {"TextboxObj2","Value second"}, 
    {"TextboxObj3", "value third" } 
}; 
public void TextBoxChangeEvent(ChangedEventArgs args, string value) 
{ 
        myComponents[value] = args.Value; 
}  
} 
 
 
Output: 
 
 
 
We have created the sample based on your scenario. Please find the sample here: 
  
  
Kindly check with the above sample. Please get back us if you need further assistance. 
  
Regards, 
  
Vignesh Srinivasan. 



SS Steve Swett December 8, 2020 05:01 PM UTC

Thank you very much for taking the time to reply and work up an example.  Unfortunately, when the <SfTextBox> is sitting within a <Template> of a data grid's <GridEditSettings> using EditMode.Dialog, the ChangedEventArgs variable -- passed to the TextBoxChangeEvent -- doesn't contain the expected values after editing the text box.

For example, when the text box is initially displayed, it shows an "A" (which is fine).  I edited it to an "x" and hit tab.  Had a breakpoint inside the TextBoxChangeEvent.  It showed the following:

args.PreviousValue = "A"
args.Value = "A"

Was expecting the latter to be an "x".

My razor page snippet is this:

var TextBoxValue = (string) fieldValue;   // where fieldValue is deduced using reflection

<SfTextBox ID="@fieldElemId" @bind-Value="@TextBoxValue" size="1" ValueChange="((ChangedEventArgs args)=> TextBoxChangeEvent( args, Trans, fieldName, TextBoxValue))" ></SfTextBox>

My TextBoxChangeEvent method is this:

public void TextBoxChangeEvent(ChangedEventArgs args, FailedTransaction Trans, string fieldName, object fieldValue)
{
    int x = 0;   // temporary bogus stuff
    x++;
}







SS Steve Swett December 9, 2020 05:37 PM UTC

I was able to come up with an alternative workaround to the ValueChange args not showing the current Value in the component.  Instead of using the ValueChange property, I used the Input property.  In the event handler, the InputEventArgs args indeed properly showed the current Value.


Razor page snippet:

string TextBoxValue = (string) fieldValue;

<SfTextBox ID="@fieldElemId" @bind-Value="@TextBoxValue" size="1" Input="((Syncfusion.Blazor.Inputs.InputEventArgs args)=> TextBoxInputEvent( args, Trans, fieldInfo))" ></SfTextBox>


My TextBoxInputEvent method:

public void TextBoxInputEvent(Syncfusion.Blazor.Inputs.InputEventArgs args, FailedTransaction Trans, FieldInfo fieldInfo)
{
    fieldInfo.SetValue(Trans, args.Value);
}





PO Prince Oliver Syncfusion Team December 10, 2020 05:06 AM UTC

Hi Steve, 
 
Query: “Unfortunately, when the <SfTextBox> is sitting within a <Template> of a data grid's <GridEditSettings> using EditMode.Dialog, the ChangedEventArgs variable -- passed to the TextBoxChangeEvent -- doesn't contain the expected values after editing the text box.”  
  
We have analyzed your query and we are able to reproduce the reported behavior at our end also while rendering the TextBox component with ValueChange event inside the Grid dialog template. We suggest you to overcome the reported issue by rendering the components inside the DialogTemplate as separate razor component. For example, we have rendered the textbox component provided (in previous update) as separate component (TextComponent.razor) inside the dialog template.   
  
Refer the below code example.   
  
<SfGrid DataSource="@GridData" Toolbar="@(new string[] {"Add""Edit" ,"Delete","Update","Cancel" })">  
    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="@EditMode.Dialog">  
        <Template>  
            @{  
                var Order = (context as OrdersDetails);  
                <div>  
                    @foreach (var value in myComponents)  
                    {  
                        var textValue = value.Value;  
                        <TextComponent Tkey="@value.Key" textValue="@textValue"></TextComponent>  
                        <span>  
                            <p> the value is @value.Value</p>  
                        </span>  
                    }  
. . . . .   
            }  
        </Template>  
    </GridEditSettings>  
</SfGrid>  
  
[TextComponent.razor]  
  
@using Syncfusion.Blazor.Inputs<SfTextBox @bind-Value="@textValue" Placeholder="Enter Name" ValueChange="((ChangedEventArgs args)=> TextBoxChangeEvent( args, Tkey))" />@code {    [Parameter]    public string textValue { getset; }    [Parameter]    public string Tkey { getset; }    public void TextBoxChangeEvent(ChangedEventArgs args, string value)    {           }} 
  
Refer the below screenshot for output of above code example.   
  
  
  
Please get back to us if you have further queries 

Regards, 
Prince 


Loader.
Up arrow icon