[SOLVED] Using input tag helper "name" and getting input value empty. ASP.NET MVC (.NET 5)

Issue

I have simple form for creating items

    <form asp-action="CreateItem" enctype="multipart/form-data">
            <div class="form-group">
                <label asp-for="@Model.ItemPhoto" class="control-label"></label>
                <input type="file" asp-for="@Model.ItemPhoto" name="Photo" class="form-control-file" />
                <span asp-validation-for="@Model.ItemPhoto" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Name" class="control-label"></label>
                <input asp-for="@Model.Name" class="form-control" />
                <span asp-validation-for="@Model.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.ItemType" class="control-label"></label>
                <select asp-for="@Model.ItemType" class="form-control">
                    @foreach (var itemType in Enum.GetValues(typeof(RandApp.Enums.ItemType)))
                    {
                        <option value="@itemType.ToString()">@itemType</option>
                    }
                </select>
                <span asp-validation-for="@Model.ItemType" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.MaterialType" class="control-label"></label>
                <select asp-for="@Model.MaterialType" class="form-control">
                    @foreach (var materialType in Enum.GetValues(typeof(RandApp.Enums.MaterialType)))
                    {
                        <option value="@materialType.ToString()">@materialType</option>
                    }
                </select>
                <span asp-validation-for="@Model.MaterialType" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Color" class="control-label"></label>
                <select asp-for="@Model.Color" class="form-control">
                    @foreach (var color in Enum.GetValues(typeof(RandApp.Enums.ItemColor)))
                    {
                        <option value="@color.ToString()">@color</option>
                    }
                </select>
                <span asp-validation-for="@Model.Color" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Size" class="control-label"></label>
                <select asp-for="@Model.Size" class="form-control">
                    @foreach (var size in Enum.GetValues(typeof(RandApp.Enums.ItemSize)))
                    {
                        <option value="@size.ToString()">@size</option>
                    }
                </select>
                <span asp-validation-for="@Model.Size" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.DesignedFor" class="control-label"></label>
                <select asp-for="@Model.DesignedFor" class="form-control">
                    @foreach (var desigendFor in Enum.GetValues(typeof(RandApp.Enums.DesignedFor)))
                    {
                        <option value="@desigendFor.ToString()">@desigendFor</option>
                    }
                </select>
                <span asp-validation-for="@Model.DesignedFor" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Price" class="control-label"></label>
                <input asp-for="@Model.Price" class="form-control" />
                <span asp-validation-for="@Model.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Description" class="control-label"></label>
                <textarea asp-for="@Model.Description" class="form-control"></textarea>
                <span asp-validation-for="@Model.Description" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>

there is its controller

public async Task<IActionResult> CreateItem(Item item, IFormFile Photo)
        {
            if (ModelState.IsValid)
            {
                var path = Path.Combine(_webHostEnvironment.WebRootPath, "assets", Photo.FileName);
                var stream = new FileStream(path, FileMode.Create);
                await Photo.CopyToAsync(stream);
                item.ItemPhoto = Photo.FileName;
                await _itemRepo.CreateAsync(item);
                ViewBag.Item = item;
                return RedirectToAction("ReadItems");
            }

            return View();
        }

my goal is to get the path of chosen photo and save it in folder called "assets"(located in "wwwroot" folder).
The problem is that when i fill the fields and submitting the values, i get item.ItemPhoto value null and i can’t enter in if statement. (see the photo down below).
[1]: https://i.stack.imgur.com/H2aLt.png

one solution i have found is to remove "enctype="multipart/form-data" from form and "name="Photo" tag helper from input

<form asp-action="CreateItem" enctype="multipart/form-data">
            <div class="form-group">
                <label asp-for="@Model.ItemPhoto" class="control-label"></label>
                <input type="file" asp-for="@Model.ItemPhoto" name="Photo" class="form-control-file" />
                <span asp-validation-for="@Model.ItemPhoto" class="text-danger"></span>
            </div>

but in this case i can’t get the path properly.
what can i do to solve this problem, why am i getting empty value from input?

Solution

File and string type cannot be passed together with the same name automatically and cannot achieve this requirement by using just one input. You can set a hidden input for ItemPhoto and use js to set the value when the file changed:

@model Item
<form asp-action="CreateItem" enctype="multipart/form-data">
            <div class="form-group">
                <label asp-for="@Model.ItemPhoto" class="control-label"></label>
                                    //change here...
                <input type="file" name="ItemPhoto" class="form-control-file" onchange="SetValue(this)"  />
                             //add hidden input......
                <input asp-for="@Model.ItemPhoto" hidden/>
                <span asp-validation-for="@Model.ItemPhoto" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="@Model.Name" class="control-label"></label>
                <input asp-for="@Model.Name" class="form-control" />
                <span asp-validation-for="@Model.Name" class="text-danger"></span>
            </div>
            <input type="submit" value="Create"/>
</form>
@section Scripts
{
    <script>
        function SetValue(input) {
            var fileName = input.files[0].name;
            //asp-for will generate the id and name
            //so you can get the selector by using $("#ItemPhoto")
            $("#ItemPhoto").val(fileName);          
        }
    </script>
}

Backend (The name attribute should always match with the parameter/property name):

public async Task<IActionResult> CreateItem(Item item, IFormFile ItemPhoto)
{
    //....
    return View();
}

Answered By – Rena

Answer Checked By – Timothy Miller (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *