Значение привязки из внешнего ключа модели - PullRequest
0 голосов
/ 28 апреля 2020

Я хочу отобразить Product.Category.Name - дочерний компонент, но у меня есть ошибка. Но в родительском компоненте Product.Category.Name работает, а не в дочернем компоненте?

Моя модель:

public class Product
{
    /// <summary>
    /// Gets or sets the id.
    /// </summary>
    [Key]
    [BindNever]
    public int Id { get; set; }

    /// <summary>
    /// Gets or sets the name.
    /// </summary>
    [Required]
    public string Name { get; set; }

    /// <summary>
    /// Gets or sets the price.
    /// </summary>
    [Required]
    [Range(0, 500)]
    public double Price { get; set; }

    /// <summary>
    /// Gets or sets the image.
    /// </summary>
    public byte[] Image { get; set; }

    /// <summary>
    /// Gets or sets the shade color.
    /// </summary>
    public string ShadeColor { get; set; }

    /// <summary>
    /// Gets or sets the category id.
    /// </summary>
    public int CategoryId { get; set; }

    /// <summary>
    /// Gets or sets the category.
    /// </summary>
    [ForeignKey("CategoryId")]
    public virtual Category Category { get; set; }
}

Мой родительский компонент:

   @page "/products"
@using BlazingShop.Data
@using BlazingShop.Services
@using BlazingShop.Pages.Components
@inject IProductService ProductService

<div class="d-flex">
    <div>
        <h1>Product List</h1>
    </div>
    <div class="ml-auto">
        <BSButton Color="Color.Info" @onclick="LoadProductDetailsModal"><i class="fal fa-plus-circle mr-1"></i>Add New Product</BSButton>
    </div>
</div>

<BSTable Class="w-75 m-auto">
    <thead>
        <tr>
            <th>Name</th>
            <th>Price</th>
            <th>Shade Color</th>
            <th>Category</th>
            <th class="text-right">Action</th>
        </tr>
    </thead>
    <tbody>
    <SpinLoader IsLoading="isLoading" IsFaulted="isFaulted">
        <LoadingTemplate>
            <tr>
                <td colspan="7">
                    <Circle Color="#e67e22" Size="60px" Center="true"></Circle>
                </td>
            </tr>
        </LoadingTemplate>
        <ContentTemplate>
            @foreach (var product in products)
            {
            <tr>
                <td>@product.Name</td>
                <td>@product.Price</td>
                <td>@product.ShadeColor</td>
                <td>@product.Category.Name</td>
                <td class="text-right">
                    <BSButton Color="Color.Primary" OnClick="(()=>LoadProductDetailsModalForEdit(product))"><i class="fal fa-edit mr-1"></i>Edit</BSButton>
                    <BSButton Color="Color.Danger" OnClick="(()=>LoadConfirmationModalForDelete(product))"><i class="fal fa-trash-alt mr-1"></i>Delete</BSButton>
                </td>
            </tr>
            }
        </ContentTemplate>
        <FaultedContentTemplate>
            <tr>
                <td colspan="7">
                    <BSAlert Color="Color.Danger">
                        <span>An Exception occured - So no Products could be shown at this time</span>
                    </BSAlert>
                </td>
            </tr>
        </FaultedContentTemplate>
    </SpinLoader>
    </tbody>
</BSTable>

<ProductDetails ProductDetailModalTitle="@productDetailModalTitle" @ref="ProductDetails" Product="product" OnSave="@RefreshProductList"></ProductDetails>

<ConfirmDelete Delete="@DeleteProduct" @ref="ConfirmDeleteModal"></ConfirmDelete>

@code {

    private ProductDetails ProductDetails { get; set; }

    Product product = new Product();

    private List<Product> products;

    private ConfirmDelete ConfirmDeleteModal { get; set; }

    private List<Category> categories;

    string productDetailModalTitle = string.Empty;

    bool isFaulted = false;
    bool isLoading = true;
    int delay = 2000;

    protected override async Task OnInitializedAsync()
    {
        await LoadProductList();
    }

    private async Task LoadProductList()
    {
        await TryLoadingProductListAsync (onSuccess: SuccessPath, onFaulted: FaultedPath);
    }

    void SuccessPath(List<Product> data)
    {

        products = data;
    }

    void FaultedPath(Exception e)
    {
        // log message, don't share it with the user
        var fakeLog = e.Message;
    }

    async Task TryLoadingProductListAsync(Action<List<Product>> onSuccess, Action<Exception> onFaulted)
    {
        isLoading = true;
        await Task.Delay(delay);
        try
        {
            var data = await ProductService.GetProductsAsync();
            isFaulted = false;
            onSuccess(data);
        }
        catch (Exception e)
        {
            isFaulted = true;
            onFaulted(e);
        }
        finally
        {
            isLoading = false;
        }
    }

    private void LoadProductDetailsModal()
    {
        this.product = new Product();
        categories = ProductService.GetCategoriesAsync();
        this.product.CategoryId = categories[0].Id;
        this.productDetailModalTitle = "Add New Product";
        ProductDetails.Toggle();
    }

    private void LoadProductDetailsModalForEdit(Product product)
    {
        this.product = product;
        categories = ProductService.GetCategoriesAsync();
        this.productDetailModalTitle = product.Name;
        ProductDetails.Toggle();
    }

    private void LoadConfirmationModalForDelete(Product product)
    {
        this.product = product;
        ConfirmDeleteModal.Toggle();

    }

    private async Task DeleteProduct()
    {
        await ProductService.DeleteProductAsync(this.product);
        await RefreshProductList();
        ConfirmDeleteModal.Toggle();
    }

    private async Task<List<Product>> RefreshProductList()
    {
        products = await ProductService.GetProductsAsync();
        product = new Product();

        return products;
    }
}

Мой дочерний компонент:

@using BlazingShop.Services
@using BlazingShop.Data
@using BlazorInputFile
@using System.IO
@inject IProductService ProductService

<BSModal @ref="@ProductDetailsModal" IsCentered="true">

    <BSModalHeader OnClick="@OnToggle">@ProductDetailModalTitle</BSModalHeader>
    <EditForm Model="Product" OnValidSubmit="HandleValidSubmit">
        <BSModalBody style="min-height: 150px;">
            <BSFormGroup Class="row">
                <div class="d-flex">
                    <label For="ProductName" class="col-4 m-0 align-self-center">Name:</label>
                    <div class="col-7">
                        <BSInput Id="ProductName" InputType="InputType.Text" @bind-Value="Product.Name"></BSInput>
                        <ValidationMessage For="@(() => Product.Name)"></ValidationMessage>
                    </div>
                </div>
                <div class="d-flex">
                    <label For="ProductCategory" class="col-4 m-0 align-self-center">Category:</label>
                    <div class="col-7">
                        <BSInput Id="ProductCategory" InputType="InputType.Text" @bind-Value="Product.Category.Name"></BSInput>
                        <ValidationMessage For="@(() => Product.Category.Name)"></ValidationMessage>
                    </div>
                </div>
                <div class="d-flex">
                    <label For="ProductPrice" class="col-4 m-0 align-self-center">Price:</label>
                    <div class="col-7">
                        <BSInput Id="ProductPrice" InputType="InputType.Text" @bind-Value="Product.Price"></BSInput>
                        <ValidationMessage For="@(() => Product.Price)"></ValidationMessage>
                    </div>
                </div>
                <div class="d-flex">
                    <label For="ProductShadeColor" class="col-4 m-0 align-self-center">Shade Color:</label>
                    <div class="col-7">
                        <BSInput Id="ProductShadeColor" InputType="InputType.Text" @bind-Value="Product.ShadeColor"></BSInput>
                        <ValidationMessage For="@(() => Product.ShadeColor)"></ValidationMessage>
                    </div>
                </div>
                <div class="d-flex">
                    <label For="ProductImage" class="col-4 m-0 align-self-center">Upload Image:</label>
                    <div class="col-7">
                        <BSBasicInput InputType="InputType.File" Id="ProductImage" Value="string.Empty" OnChange=""></BSBasicInput>
                        <ValidationMessage For="@(() => Product.Image)"></ValidationMessage>
                    </div>
                </div>
            </BSFormGroup>
        </BSModalBody>
        <BSModalFooter>
            <DataAnnotationsValidator />
            <BSButton Color="Color.Primary" ButtonType="ButtonType.Submit">Save Changes</BSButton>
            <BSButton Color="Color.Secondary" @onclick="@OnToggle">Close</BSButton>
        </BSModalFooter>
    </EditForm>
</BSModal>

@code {

    BSModal ProductDetailsModal;

    [Parameter]
    public Product Product { get; set; }
    [Parameter]
    public string ProductDetailModalTitle { get; set; }
    [Parameter]
    public EventCallback<bool> OnSave { get; set; }

    public byte[] ImageUploaded { get; set; }


    void OnToggle(MouseEventArgs e)
    {
        Toggle();
    }

    public void Toggle()
    {
        ProductDetailsModal.Toggle();
    }

    private async void HandleValidSubmit()
    {
        Toggle();

        if (Product.Id == 0)
        {
            await ProductService.AddProductAsync(Product);
        }
        else
        {
            await ProductService.EditProductAsync(Product);
        }

        await OnSave.InvokeAsync(true);
    }

    async Task HandleSelection(IFileListEntry[] files)
    {
        var file = files.FirstOrDefault();

        if (file != null)
        {
            var ms = new MemoryStream();
            await file.Data.CopyToAsync(ms);
            ImageUploaded = ms.ToArray();
        }
    }

    string ConvertImageToDisplay(byte[] image)
    {
        if (image != null)
        {
            var base64 = Convert.ToBase64String(image);
            var finalStr = $"data:image/jpg;base64,{base64}";

            return finalStr;
        }
        else
        {
            return string.Empty;
        }
    }
}

Можете ли вы помочь мне отобразить Product.Category.Name (или id) в дочернем компоненте, пожалуйста, Thx.

1 Ответ

0 голосов
/ 28 апреля 2020

Эй, я просто нахожу ответ: В дочернем компоненте In нужно сделать выбор:

<BSInput Id="ProductCategory" InputType="InputType.Select" @bind-Value="Product.CategoryId">
                        @foreach (var category in Categories)
                        {
                            <option value="@category.Id">@category.Name</option>
                        }
                    </BSInput>

Мне нужно загрузить список категорий Когда я загружаю компонент:

@{
public List<Category> Categories { get; set; }

protected override async Task OnInitializedAsync()
    {
        Categories = ProductService.GetCategoriesAsync();
    }
}
...