简体   繁体   中英

How to make a property created in a generic Component available to the Render Fragment in blazor

How to make a property created in a generic Component available to the definition of the Render Fragment content

I´m new to blazor and trying to make a generic CRUD component based on the model shown right below. Many of my other classes inherit from this model and don´t add any fields

public class BasicCatalogModel
{
    [Key]
    public virtual long Id { get; set; }

    public virtual String Name { get; set; }

    public virtual String Description { get; set; }

    public virtual bool Enabled { get; set; }

}

Then I have a generic Data Service that has a signature like so:

public class BasicCatalogService<T>: ICatalogService<T> where T: BasicCatalogModel

This service is injected into a "generic" component that is created in my CustomModelCRUD. What I need to do is add custom Colums and custom Fields for those models that need to add one or two extra fields

<BasicCatalogCRUD TItem="CustomModel" DataService="@CustomService" CrudTitle="@modelLocalizer["Custom.crud.title"]">
 <CustomColumns>
    <div>HERE are my custom columns and this works since I don´t need to add a reference to the current item</div>
 </CustomColumns>
 <CustomFields>
    I need to add a custom field where I use the currentItem created in BasicCatalogCRUD
    I need to make the field visible here to add a custom Field to the form
    <input value="currentItem.CustomField">
 <CustomFields>
</BasicCatalogCRUD>

This is part of the generic CRUD as it is Right now

@inject IStringLocalizer<ModelResource> modelLocalizer
@inject NotificationService NotificationService
@inject DialogService DialogService

@typeparam TItem

<h1>@CrudTitle</h1>
    <Columns>
        //Columns Before

        @CustomColumns
        
        //Colums After      

        
    </Columns>

</div>


@code {
    /// <summary>
    /// The item I need to access in the RenderFragment CustomFields
    /// </summary>
    TItem currentItem;
    
    [Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
    [Parameter] public String CrudTitle { get; set; }
    [Parameter] public RenderFragment CustomColumns { get; set; }
    
    ///I also need to pass the CustomFields value to the Dialog
    [Parameter] public RenderFragment CustomFields { get; set; }



    /// <summary>
    /// Here we load the generic Form on to a RadzedDialog
    /// </summary>
    void LoadDataOnForm(TItem objectInstance)
    {
        currentItem = objectInstance;


        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("CurrentItem", objectInstance);
        parameters.Add("FieldTitle", GetActionLabel());
        parameters.Add("ItemGrid", itemGrid);
        parameters.Add("LabelBuilder", labelBuilder);
        parameters.Add("DataService", DataService);
        
        //I add the parameter to the parameters and send it to the dialog.
        parameters.Add("CustomFields", CustomFields);


        DialogOptions dialogOptions = new DialogOptions() { Width = "700px", Height = "600px" };

        DialogService.Open<BasicCatalogoForm<TItem>>(GetActionLabel(), parameters, dialogOptions);

    }

}

And finally the code of the form

@inject IStringLocalizer<ModelResource> modelLocalizer
@inject IStringLocalizer<AppResource> appLocalizer
@inject NotificationService NotificationService
@inject DialogService DialogService

@typeparam TItem

@if (CurrentItem != null)
{
    <RadzenTemplateForm TItem="TItem" Data="@CurrentItem" Submit=@OnSubmit InvalidSubmit=@OnInvalidSubmit>
        <FluentValidationValidator />
        <RadzenFieldset>
            //Fields Before ...
            //The fields should be inserted here
            @CustomFields       

        </RadzenFieldset>

        <RadzenButton ButtonType="ButtonType.Submit" Icon="save" Text="@appLocalizer["button.save.label"]" />


    </RadzenTemplateForm>

}


@code {

    [Parameter] public String FieldTitle { get; set; }
    
    [Parameter] public TItem CurrentItem { get; set; }

    [Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
    
    [Parameter] public RenderFragment CustomFields { get; set; }


}

I'm currently researching passing data to the render fragment (This doesn´t seem to solve my problem as far as I can tell) and cascading values (doesn´t seem like the right option either). So, how do I make currentItem available in CustomModelCRUD?

So, I was actually very wrong and you can accomplish this using RenderFragments.

First, it is necessary to add the render fragment to the generic form. Look for the HERE: comments to see where it was added. By doing it this way, we can pass a value of type TItem to the render fragment

@typeparam TItem
    
@if (CurrentItem != null)
{
    <RadzenTemplateForm TItem="TItem" Data="@CurrentItem" Submit=@OnSubmit InvalidSubmit=@OnInvalidSubmit>
        <FluentValidationValidator />
        <RadzenFieldset>
            //Fields Before ...

            //HERE : The fields should be inserted here but we need to check if 
            //we are receiving the fragment and if the currentItem is set.
            //Adding the nullchecks also allows us to make the customFields an
            //optional thing
            @if (CustomFields != null && CurrentItem != null)
            {
                @CustomFields(CurrentItem)
            }      
            
            //... Fields After 

        </RadzenFieldset>

        <RadzenButton ButtonType="ButtonType.Submit" Icon="save" Text="@appLocalizer["button.save.label"]" />
    </RadzenTemplateForm>

}


@code {

    [Parameter] public String FieldTitle { get; set; }
    
    [Parameter] public TItem CurrentItem { get; set; }

    [Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
    
    [Parameter] public RenderFragment<TItem> CustomFields { get; set; } //HERE: This is how I added the render fragment 


}

after that we need to add the fragment to the Generic CRUD. Once again look for the HERE: comments.

@inject IStringLocalizer<ModelResource> modelLocalizer
@inject NotificationService NotificationService
@inject DialogService DialogService

@typeparam TItem

<h1>@CrudTitle</h1>
    <Columns>
        //Columns Before

        //HERE: We also need to to a null check for the custom
        //columns to make them optional
        @if (CustomColumns != null)
        {
            @CustomColumns
        }
        
        //Colums After      

        
    </Columns>

</div>


@code {
    /// <summary>
    /// The item I need to access in the RenderFragment CustomFields
    /// </summary>
    TItem currentItem;
    
    [Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
    [Parameter] public String CrudTitle { get; set; }
    
    
    //HERE: the custom colums stay as they are.
    [Parameter] public RenderFragment CustomColumns { get; set; }
    
    //HERE: We add the RenderFragment. The fragment MUST have the same signature
    //as the one in the Generic Form above
    [Parameter] public RenderFragment<TItem> CustomFields { get; set; }



    /// <summary>
    /// Here we load the generic Form on to a RadzedDialog
    /// </summary>
    void LoadDataOnForm(TItem objectInstance)
    {
        currentItem = objectInstance;


        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("CurrentItem", objectInstance);
        parameters.Add("FieldTitle", GetActionLabel());
        parameters.Add("ItemGrid", itemGrid);
        parameters.Add("LabelBuilder", labelBuilder);
        parameters.Add("DataService", DataService);
        
        //HERE: The super important part. it is necessary to do a null check, and pass the CustomFields to the 
        //generic form. DO NOT do it like this:  parameters.Add("CustomFields", CustomFields(CurrentItem));
        if (CustomFields != null) 
        {
                parameters.Add("CustomFields", CustomFields);
        }


        DialogOptions dialogOptions = new DialogOptions() { Width = "700px", Height = "600px" };

        DialogService.Open<BasicCatalogoForm<TItem>>(GetActionLabel(), parameters, dialogOptions);

    }

}

Finally we need to declare the fragments in the CustomModelCRUD

<BasicCatalogCRUD TItem="CustomModel" DataService="@CustomModelService" CrudTitle="Custom Model CRUD">


    @*HERE: this is optional and the models that follow the BasicCatalogModel don´t need to add this.*@
    <CustomColumns>
        <RadzenGridColumn TItem="CustomModel" Property="CustomProperty" Title="Custom Property" />
    </CustomColumns>
    
    @*HERE: this is optional and the models that follow the BasicCatalogModel don´t need to add this.*@
    <CustomFields>


        @*HERE: we can access the value of the CurrentItem in the BasicCatalogCRUD using the context keyword*@
        @*but we must Make a NullCheck because when the BasicCatalogCRUD is initialized there might be no*@
        @*current Item set and a nullPointer Exception could be thrown. *@
        @if (context != null)
        {
            <div class="row">
                <div class="col-md-4 align-items-center">
                    <RadzenLabel Text="@modelLocalizer["prioridad.field.CustomProperty.label"]" />
                </div>
                <div class="col-md-8">
                    <RadzenNumeric TValue="int" Min="1" Max="100" @bind-Value="context.CustomProperty" />
                    <span class="field-error-message"><ValidationMessage For="@(() => context.CustomProperty)" /></span>
                </div>
            </div>
        }
    </CustomFields>
</BasicCatalogCRUD>

Since the CRUD and DialogForm are generic, we could also create the other CRUDs without the need of the CustomColums and CustomFields tags

<BasicCatalogCRUD TItem="NormalModel" DataService="@NormalModelService" CrudTitle="Custom Model CRUD"></BasicCatalogCRUD>

And with this, I finally got my Generic CRUD and generic Form Dialog that can add optional columns and Fields depending on my needs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM