DataGrid Edit Dialog - How to disable or hide controls dynamically?

Hello. I'm in need of disabling (preferably hide) a DropDown component from the Edit dialog of a DataGrid, if a certain value of another DropDown from the same dialog is selected. I'm not being able to create this behavior properly, since I am forced to click outside of the dialog for some reason, in order for the DropDown to hide or reappear. I'd like to know how can I do this properly. I'm attaching a zip file which contains a sample project, and a video demonstration of what is happening.


Attachment: SyncfusionGridEditDialogTest_b1ff16bf.zip


8 Replies 1 reply marked as answer

NP Naveen Palanivel Syncfusion Team October 31, 2023 01:21 PM UTC

Hi Jose,


Greetings from Syncfusion.


We would like to inform you that we have prevented unwanted rendering of Grid component during the external action for better performance. We suggest you to use PreventRender(false) on value change event to reflect the changes correctly.


Kindly use the below highlighted changes in the value change event and check the reported issue at your end. Also we have modified the shared sample. Kindly check the attached sample for your reference.

Sample : https://blazorplayground.syncfusion.com/embed/rXBKiXgiqFQrCOAh?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5


                    </div>

                    <div>

                        <label class="form-label">Role</label>

                        <SfDropDownList TValue="string" TItem="string"

                                        Placeholder="Pick a role..." @bind-Value="user.Role" DataSource="@Roles">

 

                            <DropDownListEvents TValue="string" TItem="string" ValueChange="ValueChange"></DropDownListEvents>

                        </SfDropDownList>

                    </div>

                    <div>

                        <label class="form-label">Associate</label>

                        <SfDropDownList TValue="string" TItem="string" Enabled="@(user.Role == "Associate")"

                                        Placeholder="Pick an associate..." @bind-Value="user.Associate" DataSource="@Associates">

                        </SfDropDownList>

                    </div>

                </div>

            }

        </Template>

    </GridEditSettings>

 

 

<h2>Only SHOW Associates dropdown when Associate role is selected 👇</h2>

<SfGrid TValue="User" @ref="GridRef111" Toolbar="@(new List<object> { "Add" })" DataSource="@Users1">

    <GridEditSettings AllowEditing="true" Mode="EditMode.Dialog" AllowAdding="true">

        <Template>

            @{

                var user = context as User1;

                <div style="min-width: 400px">

                    <div>

                        <label class="form-label">Name</label>

                        <SfTextBox @bind-Value="user.Name" />

                    </div>

                    <div>

                        <label class="form-label">Role</label>

                        <SfDropDownList TValue="string" TItem="string"

                                        Placeholder="Pick a role..." @bind-Value="user.Role" DataSource="@Roles">

                            <DropDownListEvents TValue="string" TItem="string" ValueChange="ValueChange1"></DropDownListEvents>

                        </SfDropDownList>

                    </div>

                    @if (user.Role == "Associate")

                    {

                        <div>

                            <label class="form-label">Associate</label>

                            <SfDropDownList TValue="string" TItem="string"

                                            Placeholder="Pick an associate..." @bind-Value="user.Associate" DataSource="@Associates">

                            </SfDropDownList>

                        </div>

                    }

                </div>

            }

        </Template>

    </GridEditSettings>

 

</SfGrid>

 

@code {

    public List<User> Users { get; set; }

    public List<User1> Users1 { get; set; }

 

 

    SfGrid<User> GridRef;

      SfGrid<User1> GridRef1;

 

 

    protected override void OnInitialized()

    {

    }

 

 

    public void ValueChange1(@Syncfusion.Blazor.DropDowns.ChangeEventArgs<string, string> args)

    {

       

        GridRef1.PreventRender(false);

    }


Please let us know if you have any queries.


Regards,

Naveen


Marked as answer

JO Jose replied to Naveen Palanivel October 31, 2023 04:12 PM UTC

Thank you Naveen, this has solved my problem. I have another question related to the Edit Dialog of the Grid.

I am currently editing the Template of a Grid Edit dialog, and I have added:


<Validator>
    <DataAnnotationsValidator />
</Validator>


So the fields of the form now react to the validation taken from the Dto object selected as the value of the Grid. This is an example of my actual production app:


<GridEditSettings AllowEditOnDblClick="false" AllowEditing="true" AllowAdding="true" AllowDeleting="true" Mode="EditMode.Dialog">
    <Validator>
        <DataAnnotationsValidator />
    </Validator>
    <HeaderTemplate>
        <span>@EditDialogHeaderText</span>
    </HeaderTemplate>
    <Template>
        @{
            var usuario = context as UsuarioDto;
        }
        <div style="min-width: 400px">
            <div>
                <label class="form-label">Nombre</label>
                <SfTextBox @bind-Value="usuario.Nombre" />
                <ValidationMessage For="() => usuario.Nombre" />
            </div>
            <div>
                <label class="form-label">Usuario</label>
                <SfTextBox @bind-Value="usuario.Usuario" />
                <ValidationMessage For="() => usuario.Usuario" />
            </div>
            <div>
                <label class="form-label">Password</label>
                <SfTextBox Type="InputType.Password"
                           Enabled="!IsEditOperation"
                           InputAttributes="@(new Dictionary<string, object>() { { "autocomplete", "new-password" } })"
                           Autocomplete="AutoComplete.Off" @bind-Value="usuario.Password" />
            </div>
            <div>
                <label class="form-label">Email</label>
                <SfTextBox Type="InputType.Email" @bind-Value="usuario.Email" />
                <ValidationMessage For="() => usuario.Email" />
            </div>
            <div>
                <label class="form-label">Rol</label>
                <SfDropDownList TValue="string" TItem="string"
                                Placeholder="Seleccione un rol..." @bind-Value="usuario.Rol" DataSource="@ListaRoles">
                    <DropDownListEvents TItem="string" TValue="string" ValueChange="ValueChangeHandler" />
                </SfDropDownList>
            </div>
            @if (usuario.Rol == Constants.AssociateRole)
            {
                <div>
                    <label class="form-label">Asociado</label>
                    <SfDropDownList TValue="int?" TItem="AsociadoDto" DataSource="ListaAsociados"
                                    Placeholder="Seleccione un asociado..." @bind-Value="usuario.Asociado">
                        <DropDownListFieldSettings Text="Nombre" Value="Numero" />
                        <DropDownListTemplates TItem="AsociadoDto">
                            <ItemTemplate Context="Asociado">
                                @{
                                    <span>
                                        @Asociado.Nombre (@Asociado.Numero)
                                    </span>
                                }
                            </ItemTemplate>
                        </DropDownListTemplates>
                    </SfDropDownList>
                    <ValidationMessage For="() => usuario.Rol" />
                </div>
            }
        </div>
    </Template>
    <FooterTemplate>
        @if (IsEditOperation)
        {
            <SfButton IsPrimary="true" OnClick="async () => await ModifyUser(context as UsuarioDto)">Modificar</SfButton>
        }
        else
        {
            <SfButton IsPrimary="true" OnClick="async () => await RegisterUser(context as UsuarioDto)">Registrar</SfButton>
        }
        <SfButton IsPrimary="false" OnClick="async () => await UsuariosGrid.CloseEditAsync()">Cancelar</SfButton>
    </FooterTemplate>
</GridEditSettings>

As you can see in the FooterTemplate, I have 2 buttons that depending on the action, will display a different text and call a different method (RegisterUser or ModifyUser). 

Since I'm modifying the FooterTemplate, I believe I will no longer have the Form automatically prevent the methods from executing if the validations were not successful, please correct me if I'm wrong. 

If this is the case, I would like to know how can I access some kind of object like EditContext from each method (ModifyUser() and RegisterUser()) inside the code, so I can prevent the methods from executing, and letting the form display all the validation messages before allowing the user to continue. Temporarily, I'm doing this for both Modify and Register, which looks and feels very hacky, so I'm willing to commit to the best practices:


public async Task ModifyUser(UsuarioDto usuario)
{
    var ec = new EditContext(usuario);
    ec.EnableDataAnnotationsValidation();
    if (!ec.Validate())
    {
        var errors = string.Join("\n", ec.GetValidationMessages());
        await DialogService.AlertAsync($"Revise los campos antes de continuar.\n{errors}", "AtenciĂłn");
        return;
    }


    var result = await AuthenticationService.ModificarUsuarioAsync(usuario);
    if (result.Success)
    {
        await UsuariosGrid.CloseEditAsync();
        await ObtenerUsuarios();
        await DialogService.AlertAsync("Usuario modificado exitosamente");
        StateHasChanged();
    }
    else
    {
        await DialogService.AlertAsync(result?.Errors?.Detail ?? "Error desconocido al modificar usuario");
    }
}


JO Jose November 7, 2023 04:15 PM UTC

Is there a response for this?



SP Sarveswaran Palani Syncfusion Team November 8, 2023 05:01 PM UTC

Hi Jose,

Sorry for the delayed response.

From your query, we suspect that you want achieve validation in a Grid dialog Template. We have discussed similar topic in our UG documentation. Kindly refer the attached documentation link for your reference.

Reference: https://blazor.syncfusion.com/documentation/datagrid/column-validation#display-validation-message-in-dialog-template

               https://blazor.syncfusion.com/documentation/datagrid/column-validation#custom-validator-component

If you have any further queries, please get back to us.

Regards,
Sarvesh



JO Jose replied to Sarveswaran Palani November 8, 2023 07:54 PM UTC

Hello Sarvesh, unfortunately you suspected wrong, please read my query again.

I have already read the documentation for this topic over and over again. It doesn't answer my question: I need to capture in the "Save" button of the Grid Edit dialog, the action being performed, either RegisterUser or ModifyUser. I want the form to automatically stop me from proceeding if the DataAnnotationsValidator validator found that the data from the form is invalid, and display the validation errors below the fields properly. I am overwriting the FooterTemplate therefore the form doesn't behave as if it wasn't being overwritten. I need to perform both Create and Modify actions in the same form, therefore I need to specify in the FooterTemplate the methods for both buttons. Otherwise, how do I capture the event of the form being submitted in the C# code?



VN Vignesh Natarajan Syncfusion Team November 9, 2023 02:14 PM UTC

Hi Jose,


Sorry for the inconvenience caused.


Query: “Since I'm modifying the FooterTemplate, I believe I will no longer have the Form automatically prevent the methods from executing if the validations were not successful, please correct me if I'm wrong. â€ť


We understand the issues you are facing while calling the RegisterUser or ModifyUser method directly in the FooterTemplate feature of GridEditSettings. We would like to inform you that you are trying to save / insert the records directly into your datasource without notifying the Grid’s current actions. Hence the default validation is not shown in grid.


To overcome this issue, we suggest you to achieve your requirement by calling Grid’s default EndEditAsync() method in the button click event (placed in the FooterTemplate) and when EndEditAsync() is initialized, default validation will be executed and validation will displayed in the edit form dialog if it fails. Once the validation gets succeeded, clicking on Save button will trigger our built in events and in that we suggest you to call RegisterUser and ModifyUser method to update in your database.


We have prepared a sample to achieve your requirement and kindly refer to the below code example for your reference.


<SfGrid @ref="UsuariosGrid" DataSource="@Orders" AllowPaging="true" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" })" Height="315">

    <GridEvents OnActionComplete="ActionCompleteHandler" OnActionBegin="ActionBeginHandler" TValue="Order"></GridEvents>

    <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="EditMode.Dialog">

        <HeaderTemplate>

            @{

                var text = GetHeader((context as Order));

                <span>@text</span>

            }

        </HeaderTemplate>

        <FooterTemplate>

            @if (IsEditOperation)

            {

                <SfButton IsPrimary="true" OnClick="Clicked">Modificar</SfButton>

            }

            else

            {

                <SfButton IsPrimary="true" OnClick="Clicked">Registrar</SfButton>

            }

            <SfButton IsPrimary="false" OnClick="async () => await UsuariosGrid.CloseEditAsync()">Cancelar</SfButton>

        </FooterTemplate>

    </GridEditSettings>

    <GridColumns>

        <GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" IsPrimaryKey="true" ValidationRules="@(new ValidationRules { Required = true })" TextAlign="TextAlign.Right" Width="120"></GridColumn>

        <GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" ValidationRules="@(new ValidationRules { Required = true })" Width="120"></GridColumn>

        <GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" EditType="EditType.DatePickerEdit" Format="d" TextAlign="TextAlign.Right" Width="130" Type="ColumnType.Date"></GridColumn>

        <GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" EditType="EditType.NumericEdit" Width="120"></GridColumn>

        <GridColumn Field=@nameof(Order.ShipCountry) HeaderText="Ship Country" EditType="EditType.DropDownEdit" Width="150"></GridColumn>

    </GridColumns>

</SfGrid>

 

@code {

    SfGrid<Order> UsuariosGrid { get; set; }

    public List<Order> Orders { get; set; }

    public string Header { get; set; }

    public string ButtonText { get; set; }

    public bool IsEditOperation { get; set; }

    public async Task ActionBeginHandler(ActionEventArgs<Order> Args)

    {

        if(Args.RequestType == Syncfusion.Blazor.Grids.Action.BeginEdit)

        {

            IsEditOperation = true;

        }

        else if(Args.RequestType == Syncfusion.Blazor.Grids.Action.Add)

        {

            IsEditOperation = false;

        }

    }

    public async Task ActionCompleteHandler(ActionEventArgs<Order> Args)

    {      

        if(Args.RequestType == Syncfusion.Blazor.Grids.Action.Save)

        {

            if(Args.Action == "Add")

            {

                //Call RegisterUser() method here

            }

            else if(Args.Action == "Edit")

            {

                //Call UpdateUser() method here.

            }

        }

    }   

    public async Task Clicked()

    {

//perform default save action and will throw error when validation fails.

        await UsuariosGrid.EndEditAsync();

    }


Note: OnActionBegin and OnActionComplete event will be triggered for most of actions initiated and completed in Grid with different RequestType. But currently we are revamping (segregating) our Grid events and we have provided support for new different events for different actions. But we are testing in different use cases, once it is completed we will deprecate the existing events. So kindly request you to use above solution till that.


Refer to the below sample.


Demo: https://blazorplayground.syncfusion.com/embed/hjhUssjaIssaNmsM?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5


Please get back to us if you have further queries.


Regards,

Vignesh Natarajan



JO Jose replied to Vignesh Natarajan November 9, 2023 05:08 PM UTC

Thank you Vignesh for letting me understand this mechanism better, it worked.




SP Sarveswaran Palani Syncfusion Team November 10, 2023 12:57 PM UTC

Hi Jose,


Thanks for the update. We are glad that your issue has been resolved. We are marking this ticket as closed. Please let us know if you need any further assistance.


Regards,

Sarvesh


Loader.
Up arrow icon