skip to Main Content

I’m trying to send Product object from view to controller using ajax, I’ve searched a lot before posting this question but most of results shows how to send array of objects or array of files but in my case my main object contains array of files and array of objects.
Here are Product and ProductVariant Models:

public class Product
    {
        public int Id { get; set; }
        public required string Name { get; set; } = string.Empty;
        public string Description { get; set; } = string.Empty;
        public int SubcategoryId { get; set; }
        public virtual Subcategory? Subcategory { get; set; }
        public virtual List<ProductImage> Images { get; set; } = new List<ProductImage>();
        public virtual IEnumerable<ProductVariant> Variants { get; set; } = new List<ProductVariant>();
        [NotMapped]
        public IEnumerable<IFormFile> FormFiles { get; set; }

    }
    public class ProductVariant
    {
        public int Id { get; set; }
        public int ProductId { get; set; }
        public required int Quantity { get; set; }
        public int MinQuantity { get; set; } = 1;
        public int? MaxQuantity { get; set; }
        public double? Width { get; set; }
        public double? Length { get; set; }
        public double? Height { get; set; }
        public double? Weight { get; set; }
        public required double Price { get; set; }
        public double Discount { get; set; } = 0;
        public ProductSize? Size { get; set; } // enum
        public Gender? Gender { get; set; } // enum
        public string? Color { get; set; } = string.Empty;
        public string? Material { get; set; } = string.Empty;
        public virtual Product? Product { get; set; }
    }

When i submit and debug Product Variants list is null while files and properies are filled with data
Here’s the View

@model DataAccessLayer.Models.Product.Product

@{
    ViewData["Title"] = "Create Product";
}

<div class="dash-content">
    <div class="page-header mb-3">

        <div class="text-center">
            <h4>Add New Product</h4>
        </div>

    </div>
    <div class="create-category">
        <div asp-action="Create" method="post" class="card" enctype="multipart/form-data" id="form">
            <div class="card-body">
                <div class="row ">
                    <div class="col-lg-6  mb-3">
                        <div class="form-group">
                            <label asp-for="Name"></label>
                            <input asp-for="Name" class="form-control" placeholder="Product Name" id="Name">
                        </div>
                    </div>


                    <div class="col-lg-6 col-sm-6 col-12 mb-3">

                        <div class="form-group">
                            <label asp-for="Subcategory"></label>
                            <select asp-for="SubcategoryId" class="form-select" id="SubcategoryId">
                                <option selected disabled>Select Sucategory</option>
                                @foreach (Category cat in ViewBag.categories)
                                {
                                    <optgroup label="@cat.Name">
                                        @foreach (var subcat in cat.Subcategories)
                                        {
                                            <option value="@subcat.Id">@subcat.Name</option>
                                        }
                                    </optgroup>
                                }
                            </select>

                        </div>
                    </div>
                    <div class="col-lg-12 mb-3">
                        <div class="form-group">
                            <label asp-for="Description"></label>
                            <textarea asp-for="Description" class="form-control" rows="4" id="Description"></textarea>
                        </div>
                    </div>
                    <div class="col-lg-12 mb-3">
                        <div class="form-group mb-4">
                            <label>Product Images</label>
                            <div class="image-upload">
                                <input name="files" type="file" multiple accept="image/*" id="inputFiles">
                            </div>
                        </div>
                    </div>
                    <output></output>
                    <div class="col-lg-12 my-3 d-flex justify-content-center">
                        <div class="page-btn">
                            <a class="btn btn-add Mx-2" onclick="showSection()">Add Product Variant</a>
                        </div>
                    </div>

                    <div class="card-body pt-2 d-none" id="createVariant">
                        <div class="row gy-3">
                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Quantity</label>
                                    <input type="number" class="form-control" placeholder="Quantity" id="Quantity">
                                </div>
                            </div>

                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Min Quantity</label>
                                    <input type="number" class="form-control" placeholder="Min Quantity" id="Min-Quantity">
                                </div>
                            </div>
                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Max Quantity</label>
                                    <input type="number" class="form-control" placeholder="Max Quantity" id="Max-Quantity">
                                </div>
                            </div>

                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Width</label>
                                    <input type="number" class="form-control" placeholder="Width" id="width">
                                </div>
                            </div>

                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Length</label>
                                    <input type="number" class="form-control" placeholder="Length" id="Length">
                                </div>
                            </div>
                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Height</label>
                                    <input type="number" class="form-control" placeholder="Height" id="Height">
                                </div>
                            </div>

                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Weight</label>
                                    <input type="number" class="form-control" placeholder="Weight" id="Weight">
                                </div>
                            </div>
                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Price</label>
                                    <input type="number" class="form-control" placeholder="Price" id="Price">
                                </div>
                            </div>
                            <div class="col-lg-4  mb-3">
                                <div class="form-group">
                                    <label>Discount</label>
                                    <input type="number" class="form-control" placeholder="Discount" id="Discount">
                                </div>
                            </div>
                            <div class="col-lg-6  mb-3">
                                <div class="form-group">
                                    <label>Size</label>
                                    <select class="form-select" id="size">
                                        <option selected>Select Size</option>
                                        <option value="S">S</option>
                                        <option value="M">M</option>
                                        <option value="L">L</option>
                                        <option value="XL">XL</option>
                                        <option value="XXL">XXL</option>
                                        <option value="XXXL">XXXL</option>
                                        <option value="XXXXL">XXXXL</option>
                                        <option value="XXXXXL">XXXXXL</option>
                                    </select>

                                </div>
                            </div>


                            <div class="col-lg-6  mb-3">
                                <div class="form-group">
                                    <label>Gender</label>
                                    <select class="form-select" id="gender">
                                        <option selected>Select Gender</option>
                                        <option value="Male">Male</option>
                                        <option value="Female">Female</option>

                                    </select>

                                </div>
                            </div>


                            <div class="col-lg-6  mb-3">
                                <div class="form-group">
                                    <label>Color</label>
                                    <input type="text" class="form-control" placeholder="Color" id="Color">
                                </div>
                            </div>

                            <div class="col-lg-6  mb-3">
                                <div class="form-group">
                                    <label>Material</label>
                                    <input type="text" class="form-control" placeholder="Material" id="Material">
                                </div>
                            </div>

                            <div class="col-lg-12 my-3 d-flex justify-content-center">
                                <button type="button" class="btn btn-add me-2" onclick="addProductVariant()" id="addBtn">Add Variant</button>
                            </div>
                        </div>
                    </div>

                </div>
                <button class="btn btn-add mx-2" onclick="addProduct()">Add</button>
            </div>
        </div>
    </div>

    <div class="container">
        <table class="table table-striped text-center">
            <thead>
                <tr>
                    <th>Quantity</th>
                    <th>Min Quantity</th>
                    <th>Max Quantity</th>
                    <th>Width</th>
                    <th>Length</th>
                    <th>Height</th>
                    <th>Weight</th>
                    <th>Price</th>
                    <th>Discount</th>
                    <th>Color</th>
                    <th>Material</th>
                    <th>Size</th>
                    <th>Gender</th>
                    <th colspan="2">Action</th>
                </tr>
            </thead>
            <tbody id="table-body">
            </tbody>
        </table>
    </div>
</div>

and javascript code

function addProduct() {
    let product = {
        name: document.getElementById("Name").value,
        description: document.getElementById("Description").value,
        subcategoryId: document.getElementById("SubcategoryId").value,
        variants: Variants,
    }
    var files = Array.from($('#inputFiles')[0].files);
    var formData = new FormData();
    for (var key in product) {
        formData.append(key, product[key]);
    }
    for (var key in files) {
        formData.append("formFiles", files[key]);
    }
    $.ajax({
        url: "/Administration/Product/Create",
        type: 'POST',
        data: formData,
        dataType: "json",
        contentType: "multipart/form-data",
        processData: false,
        contentType: false,
        success: function (data) {
            console.log(data);
        }
    });
}

The problem is everything is passed to controller except product Variant list is null.

Product Controller

 public async Task<JsonResult> Create(Product product)
{
    if (ModelState.IsValid)
    {
        UnitOfWork.ProductRepo.Add(product);
        UnitOfWork.Save();
        return Json("Success");
    }
    return Json("Fail");
}

Also here how product variants is added

let productQuantityInput = document.getElementById('Quantity');
let productMinuantityInput = document.getElementById('Min-Quantity');
let productMaxuantityInput = document.getElementById('Max-Quantity');
let productWidthInput = document.getElementById('width');
let productLengthInput = document.getElementById('Length');
let productHeightInput = document.getElementById('Height');
let productWeightInput = document.getElementById('Weight');
let productPriceInput = document.getElementById('Price');
let productDiscountInput = document.getElementById('Discount');
let productColorInput = document.getElementById('Color');
let productMaterialInput = document.getElementById('Material');
let productSize = document.getElementById('size');
let productGender = document.getElementById('gender')
let Variants = [];
function addProductVariant() {
    let variant =
    {
        quantity: productQuantityInput.value,
        minQuantity: productMinuantityInput.value,
        maxQuantity: productMaxuantityInput.value,
        width: productWidthInput.value,
        length: productLengthInput.value,
        height: productHeightInput.value,
        weight: productWeightInput.value,
        price: productPriceInput.value,
        discount: productDiscountInput.value,
        color: productColorInput.value,
        material: productMaterialInput.value,
        size: productSize.value,
        gender: productGender.value

    };
    Variants.push(variant);
}

2

Answers


  1. The ASP.NET default serialization behavior default use CamelCase, so you have to name your HTML input tag with lower case Naming not like the c# class properties:

    <div class="form-group">
      <label>Quantity</label>
      <input type="number" class="form-control" id="quantity">
    </div>
    
    Login or Signup to reply.
  2. I found when we send request like what you did, in controller we would receive string value of [object].

    enter image description here

    So I found this document which mentioned

    The field’s value. This can be a string or Blob (including subclasses
    such as File). If none of these are specified the value is converted
    to a string.

    So I think the workaround here is sending JSON string to controller and convert the string to JSON object manually. Using public string Variants { get; set; } instead of public virtual List<ProductImage> Images { get; set; } = new List<ProductImage>();.

    let product = {
        name: document.getElementById("Name").value,
        description: document.getElementById("Description").value,
        variants: Variants,
    }
    formData.append("name", document.getElementById("Name").value);
    formData.append("description", document.getElementById("Description").value);
    formData.append("Variants", JSON.stringify(Variants));
    

    Then the test result:

    List<ProductVariant> objs = JsonSerializer.Deserialize<List<ProductVariant>>(product.Variants);

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search